diff --git a/src/components/CrudModel.vue b/src/components/CrudModel.vue
index 58b4146bf..c2eb894db 100644
--- a/src/components/CrudModel.vue
+++ b/src/components/CrudModel.vue
@@ -64,6 +64,10 @@ const $props = defineProps({
type: Function,
default: null,
},
+ beforeSaveFn: {
+ type: Function,
+ default: null,
+ },
goTo: {
type: String,
default: '',
@@ -149,7 +153,7 @@ function filter(value, update, filterOptions) {
(ref) => {
ref.setOptionIndex(-1);
ref.moveOptionSelection(1, true);
- }
+ },
);
}
@@ -176,7 +180,11 @@ async function saveChanges(data) {
hasChanges.value = false;
return;
}
- const changes = data || getChanges();
+ let changes = data || getChanges();
+ if ($props.beforeSaveFn) {
+ changes = await $props.beforeSaveFn(changes, getChanges);
+ }
+
try {
await axios.post($props.saveUrl || $props.url + '/crud', changes);
} finally {
@@ -215,7 +223,7 @@ async function remove(data) {
if (preRemove.length) {
newData = newData.filter(
- (form) => !preRemove.some((index) => index == form.$index)
+ (form) => !preRemove.some((index) => index == form.$index),
);
const changes = getChanges();
if (!changes.creates?.length && !changes.updates?.length)
@@ -374,6 +382,8 @@ watch(formUrl, async () => {
@click="onSubmit"
:disable="!hasChanges"
:title="t('globals.save')"
+ v-shortcut="'s'"
+ shortcut="s"
data-cy="crudModelDefaultSaveBtn"
/>
diff --git a/src/components/FormModel.vue b/src/components/FormModel.vue
index 2e580257c..a8e8c0a1f 100644
--- a/src/components/FormModel.vue
+++ b/src/components/FormModel.vue
@@ -97,7 +97,7 @@ const $props = defineProps({
});
const emit = defineEmits(['onFetch', 'onDataSaved']);
const modelValue = computed(
- () => $props.model ?? `formModel_${route?.meta?.title ?? route.name}`
+ () => $props.model ?? `formModel_${route?.meta?.title ?? route.name}`,
).value;
const componentIsRendered = ref(false);
const arrayData = useArrayData(modelValue);
@@ -148,7 +148,7 @@ onMounted(async () => {
JSON.stringify(newVal) !== JSON.stringify(originalData.value);
isResetting.value = false;
},
- { deep: true }
+ { deep: true },
);
}
});
@@ -156,7 +156,7 @@ onMounted(async () => {
if (!$props.url)
watch(
() => arrayData.store.data,
- (val) => updateAndEmit('onFetch', val)
+ (val) => updateAndEmit('onFetch', val),
);
watch(
@@ -165,7 +165,7 @@ watch(
originalData.value = null;
reset();
await fetch();
- }
+ },
);
onBeforeRouteLeave((to, from, next) => {
@@ -254,7 +254,7 @@ function filter(value, update, filterOptions) {
(ref) => {
ref.setOptionIndex(-1);
ref.moveOptionSelection(1, true);
- }
+ },
);
}
diff --git a/src/components/FormModelPopup.vue b/src/components/FormModelPopup.vue
index afdc6efca..30aaa3513 100644
--- a/src/components/FormModelPopup.vue
+++ b/src/components/FormModelPopup.vue
@@ -1,5 +1,5 @@
@@ -51,6 +58,19 @@ defineExpose({
{{ subtitle }}
+ (isSaveAndContinue = true)"
+ />
{
+ isSaveAndContinue = false;
+ emit('onDataCanceled');
+ }
+ "
/>
(isSaveAndContinue = false)"
/>
diff --git a/src/components/VnTable/VnColumn.vue b/src/components/VnTable/VnColumn.vue
index 0040385c5..1c5d8c0b9 100644
--- a/src/components/VnTable/VnColumn.vue
+++ b/src/components/VnTable/VnColumn.vue
@@ -12,6 +12,7 @@ import VnInputDate from 'components/common/VnInputDate.vue';
import VnInputTime from 'components/common/VnInputTime.vue';
import VnComponent from 'components/common/VnComponent.vue';
import VnUserLink from 'components/ui/VnUserLink.vue';
+import VnSelectEnum from '../common/VnSelectEnum.vue';
const model = defineModel(undefined, { required: true });
const emit = defineEmits(['blur']);
@@ -59,6 +60,7 @@ const defaultSelect = {
row: $props.row,
disable: !$props.isEditable,
class: 'fit',
+ 'emit-value': false,
},
forceAttrs: {
label: $props.showLabel && $props.column.label,
@@ -139,6 +141,10 @@ const defaultComponents = {
component: markRaw(VnSelect),
...defaultSelect,
},
+ selectEnum: {
+ component: markRaw(VnSelectEnum),
+ ...defaultSelect,
+ },
icon: {
component: markRaw(QIcon),
},
diff --git a/src/components/VnTable/VnFilter.vue b/src/components/VnTable/VnFilter.vue
index 1618f4f5a..d089717ef 100644
--- a/src/components/VnTable/VnFilter.vue
+++ b/src/components/VnTable/VnFilter.vue
@@ -1,6 +1,6 @@
-
+
{
diff --git a/src/components/VnTable/VnTableFilter.vue b/src/components/VnTable/VnTableFilter.vue
index 732605ce5..7ed6bc8b5 100644
--- a/src/components/VnTable/VnTableFilter.vue
+++ b/src/components/VnTable/VnTableFilter.vue
@@ -29,25 +29,29 @@ function columnName(col) {
+
diff --git a/src/components/common/VnComponent.vue b/src/components/common/VnComponent.vue
index c1700fd45..825dbb0fb 100644
--- a/src/components/common/VnComponent.vue
+++ b/src/components/common/VnComponent.vue
@@ -58,7 +58,6 @@ function toValueAttrs(attrs) {
v-on="mix(toComponent).event ?? {}"
v-model="model"
@blur="emit('blur')"
- @mouse-down="() => console.log('mouse-down')"
/>
diff --git a/src/components/common/VnInput.vue b/src/components/common/VnInput.vue
index 9e3acc4fa..8184d3832 100644
--- a/src/components/common/VnInput.vue
+++ b/src/components/common/VnInput.vue
@@ -140,7 +140,7 @@ const handleUppercase = () => {
hide-bottom-space
:data-cy="$attrs.dataCy ?? $attrs.label + '_input'"
>
-
+
@@ -165,15 +165,15 @@ const handleUppercase = () => {
}
"
>
-
+
-
+
@@ -194,4 +194,4 @@ const handleUppercase = () => {
inputMin: Debe ser mayor a {value}
maxLength: El valor excede los {value} carácteres
inputMax: Debe ser menor a {value}
-
\ No newline at end of file
+
diff --git a/src/components/common/VnSelect.vue b/src/components/common/VnSelect.vue
index c850f2e53..339f90e0e 100644
--- a/src/components/common/VnSelect.vue
+++ b/src/components/common/VnSelect.vue
@@ -171,7 +171,8 @@ onMounted(() => {
});
const arrayDataKey =
- $props.dataKey ?? ($props.url?.length > 0 ? $props.url : $attrs.name ?? $attrs.label);
+ $props.dataKey ??
+ ($props.url?.length > 0 ? $props.url : ($attrs.name ?? $attrs.label));
const arrayData = useArrayData(arrayDataKey, {
url: $props.url,
@@ -220,7 +221,7 @@ async function fetchFilter(val) {
optionFilterValue.value ??
(new RegExp(/\d/g).test(val)
? optionValue.value
- : optionFilter.value ?? optionLabel.value);
+ : (optionFilter.value ?? optionLabel.value));
let defaultWhere = {};
if ($props.filterOptions.length) {
@@ -239,7 +240,7 @@ async function fetchFilter(val) {
const { data } = await arrayData.applyFilter(
{ filter: filterOptions },
- { updateRouter: false }
+ { updateRouter: false },
);
setOptions(data);
return data;
@@ -272,7 +273,7 @@ async function filterHandler(val, update) {
ref.setOptionIndex(-1);
ref.moveOptionSelection(1, true);
}
- }
+ },
);
}
@@ -308,7 +309,7 @@ function handleKeyDown(event) {
if (inputValue) {
const matchingOption = myOptions.value.find(
(option) =>
- option[optionLabel.value].toLowerCase() === inputValue.toLowerCase()
+ option[optionLabel.value].toLowerCase() === inputValue.toLowerCase(),
);
if (matchingOption) {
@@ -320,11 +321,11 @@ function handleKeyDown(event) {
}
const focusableElements = document.querySelectorAll(
- 'a:not([disabled]), button:not([disabled]), input:not([disabled]), textarea:not([disabled]), select:not([disabled]), details:not([disabled]), [tabindex]:not([tabindex="-1"]):not([disabled])'
+ 'a:not([disabled]), button:not([disabled]), input:not([disabled]), textarea:not([disabled]), select:not([disabled]), details:not([disabled]), [tabindex]:not([tabindex="-1"]):not([disabled])',
);
const currentIndex = Array.prototype.indexOf.call(
focusableElements,
- event.target
+ event.target,
);
if (currentIndex >= 0 && currentIndex < focusableElements.length - 1) {
focusableElements[currentIndex + 1].focus();
diff --git a/src/components/common/VnSelectTravelExtended.vue b/src/components/common/VnSelectTravelExtended.vue
new file mode 100644
index 000000000..484581ad3
--- /dev/null
+++ b/src/components/common/VnSelectTravelExtended.vue
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+ {{ scope.opt?.agencyModeName }} -
+ {{ scope.opt?.warehouseInName }}
+ ({{ toDate(scope.opt?.shipped) }}) →
+ {{ scope.opt?.warehouseOutName }}
+ ({{ toDate(scope.opt?.landed) }})
+
+
+
+
+
+
diff --git a/src/components/ui/VnFilterPanel.vue b/src/components/ui/VnFilterPanel.vue
index 93f069cc6..2587211b2 100644
--- a/src/components/ui/VnFilterPanel.vue
+++ b/src/components/ui/VnFilterPanel.vue
@@ -114,7 +114,7 @@ async function clearFilters() {
arrayData.resetPagination();
// Filtrar los params no removibles
const removableFilters = Object.keys(userParams.value).filter((param) =>
- $props.unremovableParams.includes(param)
+ $props.unremovableParams.includes(param),
);
const newParams = {};
// Conservar solo los params que no son removibles
@@ -162,13 +162,13 @@ const formatTags = (tags) => {
const tags = computed(() => {
const filteredTags = tagsList.value.filter(
- (tag) => !($props.customTags || []).includes(tag.label)
+ (tag) => !($props.customTags || []).includes(tag.label),
);
return formatTags(filteredTags);
});
const customTags = computed(() =>
- tagsList.value.filter((tag) => ($props.customTags || []).includes(tag.label))
+ tagsList.value.filter((tag) => ($props.customTags || []).includes(tag.label)),
);
async function remove(key) {
@@ -191,7 +191,9 @@ const getLocale = (label) => {
if (te(globalLocale)) return t(globalLocale);
else if (te(t(`params.${param}`)));
else {
- const camelCaseModuleName = route.meta.moduleName.charAt(0).toLowerCase() + route.meta.moduleName.slice(1);
+ const camelCaseModuleName =
+ route.meta.moduleName.charAt(0).toLowerCase() +
+ route.meta.moduleName.slice(1);
return t(`${camelCaseModuleName}.params.${param}`);
}
};
@@ -290,6 +292,9 @@ const getLocale = (label) => {
/>
diff --git a/src/pages/Entry/Card/EntryDescriptor.vue b/src/pages/Entry/Card/EntryDescriptor.vue
index b64ed234e..4bf20eaba 100644
--- a/src/pages/Entry/Card/EntryDescriptor.vue
+++ b/src/pages/Entry/Card/EntryDescriptor.vue
@@ -10,6 +10,9 @@ import filter from './EntryFilter.js';
import TravelDescriptorProxy from 'src/pages/Travel/Card/TravelDescriptorProxy.vue';
import axios from 'axios';
import { useRouter } from 'vue-router';
+import { useQuasar } from 'quasar';
+
+const quasar = useQuasar();
const { push } = useRouter();
const $props = defineProps({
@@ -56,17 +59,24 @@ const getEntryRedirectionFilter = (entry) => {
function showEntryReport() {
openReport(`Entries/${entityId.value}/entry-order-pdf`);
}
-function recalculateRates() {
- console.log('recalculateRates');
+async function recalculateRates(entity) {
+ const entryConfig = await axios.get('EntryConfigs/findOne');
+ if (entryConfig.data?.inventorySupplierFk === entity.supplierFk) {
+ quasar.notify({
+ type: 'negative',
+ message: t('Cannot recalculate prices because this is an inventory entry'),
+ });
+ return;
+ }
+
+ await axios.post(`Entries/${entityId.value}/recalcEntryPrices`);
}
async function cloneEntry() {
- console.log('cloneEntry');
await axios
.post(`Entries/${entityId.value}/cloneEntry`)
.then((response) => push(`/entry/${response.data[0].vNewEntryFk}`));
}
async function deleteEntry() {
- console.log('deleteEntry');
await axios.post(`Entries/${entityId.value}/deleteEntry`).then(() => push(`/entry/`));
}
@@ -118,6 +128,10 @@ async function deleteEntry() {
:label="t('entry.summary.invoiceAmount')"
:value="entity?.invoiceAmount"
/>
+
@@ -163,21 +177,6 @@ async function deleteEntry() {
>
{{ t('Supplier card') }}
-
- {{ t('All travels with current agency') }}
-
-
+
diff --git a/src/pages/Entry/EntryList.vue b/src/pages/Entry/EntryList.vue
index aa35dd2d9..30f336e12 100644
--- a/src/pages/Entry/EntryList.vue
+++ b/src/pages/Entry/EntryList.vue
@@ -9,6 +9,7 @@ import { onBeforeMount } from 'vue';
import EntryFilter from './EntryFilter.vue';
import VnTable from 'components/VnTable/VnTable.vue';
import SupplierDescriptorProxy from 'src/pages/Supplier/Card/SupplierDescriptorProxy.vue';
+import VnSelectTravelExtended from 'src/components/common/VnSelectTravelExtended.vue';
import { toDate } from 'src/filters';
const { t } = useI18n();
@@ -274,45 +275,56 @@ onBeforeMount(async () => {
-
-
-
-
+
- {{ toDate(row.landed) }}
-
+
+
+ {{ toDate(row.landed) }}
+
+
+
+
+ {{ row.supplierName }}
+
+
+
+
+
+
+
-
-
- {{ row.supplierName }}
-
-
-
-
+
diff --git a/src/pages/Entry/locale/en.yml b/src/pages/Entry/locale/en.yml
index 6a0023b17..7f9399704 100644
--- a/src/pages/Entry/locale/en.yml
+++ b/src/pages/Entry/locale/en.yml
@@ -1,4 +1,7 @@
entry:
+ lock:
+ title: Lock entry
+ message: This entry has been locked by {userName} for {time} minutes. Do you want to unlock it?
list:
newEntry: New entry
tableVisibleColumns:
@@ -20,11 +23,13 @@ entry:
entryTypeDescription: Entry type
invoiceAmount: Import
travelFk: Travel
+ dated: Dated
inventoryEntry: Inventory entry
summary:
commission: Commission
currency: Currency
invoiceNumber: Invoice number
+ invoiceAmount: Invoice amount
ordered: Ordered
booked: Booked
excludedFromAvailable: Inventory
@@ -42,6 +47,7 @@ entry:
buyingValue: Buying value
import: Import
pvp: PVP
+ entryType: Entry type
basicData:
travel: Travel
currency: Currency
@@ -78,11 +84,48 @@ entry:
landing: Landing
isExcludedFromAvailable: Es inventory
params:
- toShipped: To
- fromShipped: From
- daysOnward: Days onward
- daysAgo: Days ago
- warehouseInFk: Warehouse in
+ isExcludedFromAvailable: Exclude from inventory
+ isOrdered: Ordered
+ isConfirmed: Ready to label
+ isReceived: Received
+ isIgnored: Ignored
+ isRaid: Raid
+ landed: Date
+ supplierFk: Supplier
+ reference: Ref/Alb/Guide
+ invoiceNumber: Invoice
+ agencyModeId: Agency
+ isBooked: Booked
+ companyFk: Company
+ evaNotes: Notes
+ warehouseOutFk: Origin
+ warehouseInFk: Destiny
+ entryTypeDescription: Entry type
+ invoiceAmount: Import
+ travelFk: Travel
+ dated: Dated
+ itemFk: Item id
+ hex: Color
+ name: Item name
+ size: Size
+ stickers: Stickers
+ packagingFk: Packaging
+ weight: Kg
+ groupingMode: Grouping selector
+ grouping: Grouping
+ quantity: Quantity
+ buyingValue: Buying value
+ price2: Package
+ price3: Box
+ minPrice: Minumum price
+ hasMinPrice: Has minimum price
+ packingOut: Packing out
+ comment: Comment
+ subName: Supplier name
+ tags: Tags
+ company_name: Company name
+ itemTypeFk: Item type
+ workerFk: Worker id
search: Search entries
searchInfo: You can search by entry reference
entryFilter:
diff --git a/src/pages/Entry/locale/es.yml b/src/pages/Entry/locale/es.yml
index a31327124..ae28568c6 100644
--- a/src/pages/Entry/locale/es.yml
+++ b/src/pages/Entry/locale/es.yml
@@ -1,4 +1,8 @@
entry:
+ lock:
+ title: Entrada bloqueada
+ message: Esta entrada ha sido bloqueada por {userName} hace {time} minutos. ¿Quieres desbloquearla?
+
list:
newEntry: Nueva entrada
tableVisibleColumns:
@@ -20,11 +24,13 @@ entry:
warehouseInFk: Destino
entryTypeDescription: Tipo entrada
invoiceAmount: Importe
+ dated: Fecha
inventoryEntry: Es inventario
summary:
commission: Comisión
currency: Moneda
invoiceNumber: Núm. factura
+ invoiceAmount: Importe
ordered: Pedida
booked: Contabilizada
excludedFromAvailable: Inventario
@@ -43,6 +49,7 @@ entry:
buyingValue: Coste
import: Importe
pvp: PVP
+ entryType: Tipo entrada
basicData:
travel: Envío
currency: Moneda
@@ -78,14 +85,52 @@ entry:
packingOut: Embalaje envíos
landing: Llegada
isExcludedFromAvailable: Es inventario
- params:
- toShipped: Hasta
- fromShipped: Desde
- warehouseInFk: Alm. entrada
- daysOnward: Días adelante
- daysAgo: Días atras
+
search: Buscar entradas
searchInfo: Puedes buscar por referencia de entrada
+ params:
+ isExcludedFromAvailable: Excluir del inventario
+ isOrdered: Pedida
+ isConfirmed: Lista para etiquetar
+ isReceived: Recibida
+ isRaid: Redada
+ isIgnored: Ignorado
+ landed: Fecha
+ supplierFk: Proveedor
+ invoiceNumber: Nº Factura
+ reference: Ref/Alb/Guía
+ agencyModeId: Agencia
+ isBooked: Asentado
+ companyFk: Empresa
+ travelFk: Envio
+ evaNotes: Notas
+ warehouseOutFk: Origen
+ warehouseInFk: Destino
+ entryTypeDescription: Tipo entrada
+ invoiceAmount: Importe
+ dated: Fecha
+ itemFk: Id artículo
+ hex: Color
+ name: Nombre artículo
+ size: Medida
+ stickers: Etiquetas
+ packagingFk: Embalaje
+ weight: Kg
+ groupinMode: Selector de grouping
+ grouping: Grouping
+ quantity: Quantity
+ buyingValue: Precio de compra
+ price2: Paquete
+ price3: Caja
+ minPrice: Precio mínimo
+ hasMinPrice: Tiene precio mínimo
+ packingOut: Packing out
+ comment: Referencia
+ subName: Nombre proveedor
+ tags: Etiquetas
+ company_name: Nombre empresa
+ itemTypeFk: Familia
+ workerFk: Comprador
entryFilter:
params:
invoiceNumber: Núm. factura
diff --git a/src/pages/InvoiceIn/Card/InvoiceInDescriptorMenu.vue b/src/pages/InvoiceIn/Card/InvoiceInDescriptorMenu.vue
index 24bf427e9..83c5b103b 100644
--- a/src/pages/InvoiceIn/Card/InvoiceInDescriptorMenu.vue
+++ b/src/pages/InvoiceIn/Card/InvoiceInDescriptorMenu.vue
@@ -272,7 +272,6 @@ const createInvoiceInCorrection = async () => {
>
- {{ console.log('opt: ', opt) }}
{{ opt.id }} -
diff --git a/src/pages/InvoiceIn/InvoiceInList.vue b/src/pages/InvoiceIn/InvoiceInList.vue
index 5e80ae652..acb1bed06 100644
--- a/src/pages/InvoiceIn/InvoiceInList.vue
+++ b/src/pages/InvoiceIn/InvoiceInList.vue
@@ -28,6 +28,7 @@ const cols = computed(() => [
name: 'isBooked',
label: t('invoicein.isBooked'),
columnFilter: false,
+ component: 'checkbox',
},
{
align: 'left',
@@ -176,7 +177,9 @@ const cols = computed(() => [
{{ scope.opt?.nickname }}
- #{{ scope.opt?.id }}, {{ scope.opt?.name }}
+
+ #{{ scope.opt?.id }}, {{ scope.opt?.name }}
+
diff --git a/src/pages/Monitor/MonitorOrders.vue b/src/pages/Monitor/MonitorOrders.vue
index 4efab56fb..873f8abb4 100644
--- a/src/pages/Monitor/MonitorOrders.vue
+++ b/src/pages/Monitor/MonitorOrders.vue
@@ -157,7 +157,7 @@ const openTab = (id) =>
openConfirmationModal(
$t('globals.deleteConfirmTitle'),
$t('salesOrdersTable.deleteConfirmMessage'),
- removeOrders
+ removeOrders,
)
"
>
diff --git a/src/pages/Route/Agency/AgencyList.vue b/src/pages/Route/Agency/AgencyList.vue
index 9d456c1da..308d67030 100644
--- a/src/pages/Route/Agency/AgencyList.vue
+++ b/src/pages/Route/Agency/AgencyList.vue
@@ -50,7 +50,6 @@ const columns = computed(() => [
name: 'isAnyVolumeAllowed',
component: 'checkbox',
cardVisible: true,
- disable: true,
},
{
align: 'right',
@@ -80,7 +79,8 @@ const columns = computed(() => [
url="Agencies"
order="name"
:columns="columns"
- :right-search="false"
+ is-editable="false"
+ :right-search="true"
:use-model="true"
redirect="agency"
default-mode="card"
diff --git a/src/pages/Route/RouteExtendedList.vue b/src/pages/Route/RouteExtendedList.vue
index b113afc8f..8e7c5339d 100644
--- a/src/pages/Route/RouteExtendedList.vue
+++ b/src/pages/Route/RouteExtendedList.vue
@@ -68,7 +68,7 @@ const columns = computed(() => [
},
useLike: false,
cardVisible: true,
- format: (row, dashIfEmpty) => dashIfEmpty(row.travelRef),
+ format: (row, dashIfEmpty) => dashIfEmpty(row.workerUserName),
},
{
align: 'center',
@@ -87,6 +87,7 @@ const columns = computed(() => [
},
},
columnClass: 'expand',
+ format: (row, dashIfEmpty) => dashIfEmpty(row.agencyName),
},
{
align: 'center',
@@ -108,6 +109,7 @@ const columns = computed(() => [
columnFilter: {
inWhere: true,
},
+ format: (row, dashIfEmpty) => dashIfEmpty(row.vehiclePlateNumber),
},
{
align: 'center',
@@ -117,7 +119,7 @@ const columns = computed(() => [
cardVisible: true,
create: true,
component: 'date',
- format: ({ created }) => toDate(created),
+ format: ({ dated }) => toDate(dated),
},
{
align: 'center',
@@ -127,7 +129,7 @@ const columns = computed(() => [
cardVisible: true,
create: true,
component: 'date',
- format: ({ from }) => toDate(from),
+ format: ({ from }) => from,
},
{
align: 'center',
@@ -152,7 +154,7 @@ const columns = computed(() => [
label: t('route.hourStarted'),
component: 'time',
columnFilter: false,
- format: ({ hourStarted }) => toHour(hourStarted),
+ format: ({ started }) => toHour(started),
},
{
align: 'center',
@@ -160,7 +162,7 @@ const columns = computed(() => [
label: t('route.hourFinished'),
component: 'time',
columnFilter: false,
- format: ({ hourFinished }) => toHour(hourFinished),
+ format: ({ finished }) => toHour(finished),
},
{
align: 'center',