diff --git a/cypress.config.js b/cypress.config.js
index 1924144f6..a9e27fcfd 100644
--- a/cypress.config.js
+++ b/cypress.config.js
@@ -14,8 +14,8 @@ export default defineConfig({
downloadsFolder: 'test/cypress/downloads',
video: false,
specPattern: 'test/cypress/integration/**/*.spec.js',
- experimentalRunAllSpecs: true,
- watchForFileChanges: true,
+ experimentalRunAllSpecs: false,
+ watchForFileChanges: false,
reporter: 'cypress-mochawesome-reporter',
reporterOptions: {
charts: true,
diff --git a/package.json b/package.json
index 17f39cad7..d23ed0ced 100644
--- a/package.json
+++ b/package.json
@@ -1,74 +1,74 @@
{
- "name": "salix-front",
- "version": "25.06.0",
- "description": "Salix frontend",
- "productName": "Salix",
- "author": "Verdnatura",
- "private": true,
- "packageManager": "pnpm@8.15.1",
- "type": "module",
- "scripts": {
- "resetDatabase": "cd ../salix && gulp docker",
- "lint": "eslint --ext .js,.vue ./",
- "format": "prettier --write \"**/*.{js,vue,scss,html,md,json}\" --ignore-path .gitignore",
- "test:e2e": "cypress open",
- "test:e2e:ci": "npm run resetDatabase && cd ../salix-front && cypress run",
- "test": "echo \"See package.json => scripts for available tests.\" && exit 0",
- "test:unit": "vitest",
- "test:unit:ci": "vitest run",
- "commitlint": "commitlint --edit",
- "prepare": "npx husky install",
- "addReferenceTag": "node .husky/addReferenceTag.js",
- "docs:dev": "vitepress dev docs",
- "docs:build": "vitepress build docs",
- "docs:preview": "vitepress preview docs"
- },
- "dependencies": {
- "@quasar/cli": "^2.4.1",
- "@quasar/extras": "^1.16.16",
- "axios": "^1.4.0",
- "chromium": "^3.0.3",
- "croppie": "^2.6.5",
- "moment": "^2.30.1",
- "pinia": "^2.1.3",
- "quasar": "^2.17.7",
- "validator": "^13.9.0",
- "vue": "^3.5.13",
- "vue-i18n": "^9.3.0",
- "vue-router": "^4.2.5"
- },
- "devDependencies": {
- "@commitlint/cli": "^19.2.1",
- "@commitlint/config-conventional": "^19.1.0",
- "@intlify/unplugin-vue-i18n": "^0.8.2",
- "@pinia/testing": "^0.1.2",
- "@quasar/app-vite": "^2.0.8",
- "@quasar/quasar-app-extension-qcalendar": "^4.0.2",
- "@quasar/quasar-app-extension-testing-unit-vitest": "^0.4.0",
- "@vue/test-utils": "^2.4.4",
- "autoprefixer": "^10.4.14",
- "cypress": "^13.6.6",
- "cypress-mochawesome-reporter": "^3.8.2",
- "eslint": "^9.18.0",
- "eslint-config-prettier": "^10.0.1",
- "eslint-plugin-cypress": "^4.1.0",
- "eslint-plugin-vue": "^9.32.0",
- "husky": "^8.0.0",
- "postcss": "^8.4.23",
- "prettier": "^3.4.2",
- "sass": "^1.83.4",
- "vitepress": "^1.6.3",
- "vitest": "^0.34.0"
- },
- "engines": {
- "node": "^20 || ^18 || ^16",
- "npm": ">= 8.1.2",
- "yarn": ">= 1.21.1",
- "bun": ">= 1.0.25"
- },
- "overrides": {
- "@vitejs/plugin-vue": "^5.2.1",
- "vite": "^6.0.11",
- "vitest": "^0.31.1"
- }
+ "name": "salix-front",
+ "version": "25.08.0",
+ "description": "Salix frontend",
+ "productName": "Salix",
+ "author": "Verdnatura",
+ "private": true,
+ "packageManager": "pnpm@8.15.1",
+ "type": "module",
+ "scripts": {
+ "resetDatabase": "cd ../salix && gulp docker",
+ "lint": "eslint --ext .js,.vue ./",
+ "format": "prettier --write \"**/*.{js,vue,scss,html,md,json}\" --ignore-path .gitignore",
+ "test:e2e": "cypress open",
+ "test:e2e:ci": "npm run resetDatabase && cd ../salix-front && cypress run",
+ "test": "echo \"See package.json => scripts for available tests.\" && exit 0",
+ "test:unit": "vitest",
+ "test:unit:ci": "vitest run",
+ "commitlint": "commitlint --edit",
+ "prepare": "npx husky install",
+ "addReferenceTag": "node .husky/addReferenceTag.js",
+ "docs:dev": "vitepress dev docs",
+ "docs:build": "vitepress build docs",
+ "docs:preview": "vitepress preview docs"
+ },
+ "dependencies": {
+ "@quasar/cli": "^2.4.1",
+ "@quasar/extras": "^1.16.16",
+ "axios": "^1.4.0",
+ "chromium": "^3.0.3",
+ "croppie": "^2.6.5",
+ "moment": "^2.30.1",
+ "pinia": "^2.1.3",
+ "quasar": "^2.17.7",
+ "validator": "^13.9.0",
+ "vue": "^3.5.13",
+ "vue-i18n": "^9.3.0",
+ "vue-router": "^4.2.5"
+ },
+ "devDependencies": {
+ "@commitlint/cli": "^19.2.1",
+ "@commitlint/config-conventional": "^19.1.0",
+ "@intlify/unplugin-vue-i18n": "^0.8.2",
+ "@pinia/testing": "^0.1.2",
+ "@quasar/app-vite": "^2.0.8",
+ "@quasar/quasar-app-extension-qcalendar": "^4.0.2",
+ "@quasar/quasar-app-extension-testing-unit-vitest": "^0.4.0",
+ "@vue/test-utils": "^2.4.4",
+ "autoprefixer": "^10.4.14",
+ "cypress": "^13.6.6",
+ "cypress-mochawesome-reporter": "^3.8.2",
+ "eslint": "^9.18.0",
+ "eslint-config-prettier": "^10.0.1",
+ "eslint-plugin-cypress": "^4.1.0",
+ "eslint-plugin-vue": "^9.32.0",
+ "husky": "^8.0.0",
+ "postcss": "^8.4.23",
+ "prettier": "^3.4.2",
+ "sass": "^1.83.4",
+ "vitepress": "^1.6.3",
+ "vitest": "^0.34.0"
+ },
+ "engines": {
+ "node": "^20 || ^18 || ^16",
+ "npm": ">= 8.1.2",
+ "yarn": ">= 1.21.1",
+ "bun": ">= 1.0.25"
+ },
+ "overrides": {
+ "@vitejs/plugin-vue": "^5.2.1",
+ "vite": "^6.0.11",
+ "vitest": "^0.31.1"
+ }
}
\ No newline at end of file
diff --git a/quasar.config.js b/quasar.config.js
index 6d545c026..9467c92af 100644
--- a/quasar.config.js
+++ b/quasar.config.js
@@ -30,7 +30,6 @@ export default configure(function (/* ctx */) {
// --> boot files are part of "main.js"
// https://v2.quasar.dev/quasar-cli/boot-files
boot: ['i18n', 'axios', 'vnDate', 'validations', 'quasar', 'quasar.defaults'],
-
// https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#css
css: ['app.scss'],
diff --git a/src/boot/defaults/constants.js b/src/boot/defaults/constants.js
new file mode 100644
index 000000000..c96ceb2d1
--- /dev/null
+++ b/src/boot/defaults/constants.js
@@ -0,0 +1,2 @@
+export const langs = ['en', 'es'];
+export const decimalPlaces = 2;
diff --git a/src/boot/keyShortcut.js b/src/boot/keyShortcut.js
index 5afb5b74a..6da06c8bf 100644
--- a/src/boot/keyShortcut.js
+++ b/src/boot/keyShortcut.js
@@ -1,6 +1,6 @@
export default {
- mounted: function (el, binding) {
- const shortcut = binding.value ?? '+';
+ mounted(el, binding) {
+ const shortcut = binding.value || '+';
const { key, ctrl, alt, callback } =
typeof shortcut === 'string'
@@ -8,25 +8,24 @@ export default {
key: shortcut,
ctrl: true,
alt: true,
- callback: () =>
- document
- .querySelector(`button[shortcut="${shortcut}"]`)
- ?.click(),
+ callback: () => el?.click(),
}
: binding.value;
+ if (!el.hasAttribute('shortcut')) {
+ el.setAttribute('shortcut', key);
+ }
+
const handleKeydown = (event) => {
if (event.key === key && (!ctrl || event.ctrlKey) && (!alt || event.altKey)) {
callback();
}
};
- // Attach the event listener to the window
window.addEventListener('keydown', handleKeydown);
-
el._handleKeydown = handleKeydown;
},
- unmounted: function (el) {
+ unmounted(el) {
if (el._handleKeydown) {
window.removeEventListener('keydown', el._handleKeydown);
}
diff --git a/src/boot/qformMixin.js b/src/boot/qformMixin.js
index 97d80c670..cb31391b3 100644
--- a/src/boot/qformMixin.js
+++ b/src/boot/qformMixin.js
@@ -9,19 +9,19 @@ export default {
if (!form) return;
try {
const inputsFormCard = form.querySelectorAll(
- `input:not([disabled]):not([type="checkbox"])`
+ `input:not([disabled]):not([type="checkbox"])`,
);
if (inputsFormCard.length) {
focusFirstInput(inputsFormCard[0]);
}
const textareas = document.querySelectorAll(
- 'textarea:not([disabled]), [contenteditable]:not([disabled])'
+ 'textarea:not([disabled]), [contenteditable]:not([disabled])',
);
if (textareas.length) {
focusFirstInput(textareas[textareas.length - 1]);
}
const inputs = document.querySelectorAll(
- 'form#formModel input:not([disabled]):not([type="checkbox"])'
+ 'form#formModel input:not([disabled]):not([type="checkbox"])',
);
const input = inputs[0];
if (!input) return;
diff --git a/src/boot/quasar.js b/src/boot/quasar.js
index 547517682..a8c397b83 100644
--- a/src/boot/quasar.js
+++ b/src/boot/quasar.js
@@ -51,4 +51,5 @@ export default boot(({ app }) => {
await useCau(response, message);
};
+ app.provide('app', app);
});
diff --git a/src/components/CreateBankEntityForm.vue b/src/components/CreateBankEntityForm.vue
index 2da3aa994..7c4b94a6a 100644
--- a/src/components/CreateBankEntityForm.vue
+++ b/src/components/CreateBankEntityForm.vue
@@ -14,7 +14,7 @@ const { t } = useI18n();
const bicInputRef = ref(null);
const state = useState();
-const customer = computed(() => state.get('customer'));
+const customer = computed(() => state.get('Customer'));
const countriesFilter = {
fields: ['id', 'name', 'code'],
diff --git a/src/components/CrudModel.vue b/src/components/CrudModel.vue
index d569dfda1..93a2ac96a 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: '',
@@ -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 {
@@ -229,12 +237,12 @@ async function remove(data) {
componentProps: {
title: t('globals.confirmDeletion'),
message: t('globals.confirmDeletionMessage'),
- newData,
+ data: { deletes: ids },
ids,
+ promise: saveChanges,
},
})
.onOk(async () => {
- await saveChanges({ deletes: ids });
newData = newData.filter((form) => !ids.some((id) => id == form[pk]));
fetch(newData);
});
@@ -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/FilterTravelForm.vue b/src/components/FilterTravelForm.vue
index 4d43c3810..765d97763 100644
--- a/src/components/FilterTravelForm.vue
+++ b/src/components/FilterTravelForm.vue
@@ -181,6 +181,7 @@ const selectTravel = ({ id }) => {
color="primary"
:disabled="isLoading"
:loading="isLoading"
+ data-cy="save-filter-travel-form"
/>
{
:no-data-label="t('Enter a new search')"
class="q-mt-lg"
@row-click="(_, row) => selectTravel(row)"
+ data-cy="table-filter-travel-form"
>
-
+
{{ row.id }}
diff --git a/src/components/FormModel.vue b/src/components/FormModel.vue
index 3842ff947..633f1254d 100644
--- a/src/components/FormModel.vue
+++ b/src/components/FormModel.vue
@@ -84,7 +84,7 @@ const $props = defineProps({
},
reload: {
type: Boolean,
- default: false,
+ default: true,
},
defaultTrim: {
type: Boolean,
@@ -105,15 +105,15 @@ const isLoading = ref(false);
// Si elegimos observar los cambios del form significa que inicialmente las actions estaran deshabilitadas
const isResetting = ref(false);
const hasChanges = ref(!$props.observeFormChanges);
-const originalData = ref({});
-const formData = computed(() => state.get(modelValue));
+const originalData = computed(() => state.get(modelValue));
+const formData = ref();
const defaultButtons = computed(() => ({
save: {
dataCy: 'saveDefaultBtn',
color: 'primary',
icon: 'save',
label: 'globals.save',
- click: () => myForm.value.submit(),
+ click: () => myForm.value.onSubmit(false),
type: 'submit',
},
reset: {
@@ -127,8 +127,6 @@ const defaultButtons = computed(() => ({
}));
onMounted(async () => {
- originalData.value = JSON.parse(JSON.stringify($props.formInitialData ?? {}));
-
nextTick(() => (componentIsRendered.value = true));
// Podemos enviarle al form la estructura de data inicial sin necesidad de fetchearla
@@ -160,10 +158,18 @@ if (!$props.url)
(val) => updateAndEmit('onFetch', { val }),
);
+watch(
+ originalData,
+ (val) => {
+ if (val) formData.value = JSON.parse(JSON.stringify(val));
+ },
+ { immediate: true },
+);
+
watch(
() => [$props.url, $props.filter],
async () => {
- originalData.value = null;
+ state.set(modelValue, null);
reset();
await fetch();
},
@@ -198,12 +204,12 @@ async function fetch() {
updateAndEmit('onFetch', { val: data });
} catch (e) {
state.set(modelValue, {});
- originalData.value = {};
throw e;
}
}
-async function save() {
+async function save(prevent = false) {
+ if (prevent) return;
if ($props.observeFormChanges && !hasChanges.value)
return notify('globals.noChanges', 'negative');
@@ -265,7 +271,6 @@ function filter(value, update, filterOptions) {
function updateAndEmit(evt, { val, res, old } = { val: null, res: null, old: null }) {
state.set(modelValue, val);
- originalData.value = val && JSON.parse(JSON.stringify(val));
if (!$props.url) arrayData.store.data = val;
emit(evt, state.get(modelValue), res, old);
@@ -293,7 +298,7 @@ defineExpose({
{
- if (closeButton.value) closeButton.value.click();
+ if (closeButton.value && isSaveAndContinue) closeButton.value.click();
emit('onDataSaved', formData, requestResponse);
};
const isLoading = computed(() => formModelRef.value?.isLoading);
+const reset = computed(() => formModelRef.value?.reset);
defineExpose({
isLoading,
onDataSaved,
+ isSaveAndContinue,
+ reset,
});
@@ -59,15 +66,22 @@ defineExpose({
flat
:disabled="isLoading"
:loading="isLoading"
- @click="emit('onDataCanceled')"
- v-close-popup
data-cy="FormModelPopup_cancel"
+ v-close-popup
z-max
+ @click="
+ isSaveAndContinue = false;
+ emit('onDataCanceled');
+ "
/>
+
diff --git a/src/components/ItemsFilterPanel.vue b/src/components/ItemsFilterPanel.vue
index 36123b834..f73753a6b 100644
--- a/src/components/ItemsFilterPanel.vue
+++ b/src/components/ItemsFilterPanel.vue
@@ -281,7 +281,7 @@ const setCategoryList = (data) => {
{
return locale.includes(normalizedSearch);
});
});
-
const filteredPinnedModules = computed(() => {
if (!search.value) return pinnedModules.value;
const normalizedSearch = search.value
@@ -72,7 +71,7 @@ watch(
items.value = [];
getRoutes();
},
- { deep: true }
+ { deep: true },
);
function findMatches(search, item) {
@@ -104,33 +103,40 @@ function addChildren(module, route, parent) {
}
function getRoutes() {
- if (props.source === 'main') {
- const modules = Object.assign([], navigation.getModules().value);
-
- for (const item of modules) {
- const moduleDef = routes.find(
- (route) => toLowerCamel(route.name) === item.module
- );
- if (!moduleDef) continue;
- item.children = [];
-
- addChildren(item.module, moduleDef, item.children);
- }
-
- items.value = modules;
+ const handleRoutes = {
+ main: getMainRoutes,
+ card: getCardRoutes,
+ };
+ try {
+ handleRoutes[props.source]();
+ } catch (error) {
+ throw new Error(`Method is not defined`);
}
+}
+function getMainRoutes() {
+ const modules = Object.assign([], navigation.getModules().value);
- if (props.source === 'card') {
- const currentRoute = route.matched[1];
- const currentModule = toLowerCamel(currentRoute.name);
- let moduleDef = routes.find(
- (route) => toLowerCamel(route.name) === currentModule
+ for (const item of modules) {
+ const moduleDef = routes.find(
+ (route) => toLowerCamel(route.name) === item.module,
);
+ if (!moduleDef) continue;
+ item.children = [];
- if (!moduleDef) return;
- if (!moduleDef?.menus) moduleDef = betaGetRoutes();
- addChildren(currentModule, moduleDef, items.value);
+ addChildren(item.module, moduleDef, item.children);
}
+
+ items.value = modules;
+}
+
+function getCardRoutes() {
+ const currentRoute = route.matched[1];
+ const currentModule = toLowerCamel(currentRoute.name);
+ let moduleDef = routes.find((route) => toLowerCamel(route.name) === currentModule);
+
+ if (!moduleDef) return;
+ if (!moduleDef?.menus) moduleDef = betaGetRoutes();
+ addChildren(currentModule, moduleDef, items.value);
}
function betaGetRoutes() {
@@ -223,9 +229,16 @@ const searchModule = () => {
-
+
{
.header {
color: var(--vn-label-color);
}
-.searched{
+.searched {
background-color: var(--vn-section-hover-color);
}
diff --git a/src/components/LeftMenuItem.vue b/src/components/LeftMenuItem.vue
index a3112b17f..c0cee44fe 100644
--- a/src/components/LeftMenuItem.vue
+++ b/src/components/LeftMenuItem.vue
@@ -26,6 +26,7 @@ const itemComputed = computed(() => {
:to="{ name: itemComputed.name }"
clickable
v-ripple
+ :data-cy="`${itemComputed.name}-menu-item`"
>
diff --git a/src/components/RefundInvoiceForm.vue b/src/components/RefundInvoiceForm.vue
index 590acede0..6dcb8b390 100644
--- a/src/components/RefundInvoiceForm.vue
+++ b/src/components/RefundInvoiceForm.vue
@@ -9,6 +9,7 @@ import VnSelect from 'components/common/VnSelect.vue';
import FormPopup from './FormPopup.vue';
import axios from 'axios';
import useNotify from 'src/composables/useNotify.js';
+import VnCheckbox from 'src/components/common/VnCheckbox.vue';
const $props = defineProps({
invoiceOutData: {
@@ -131,15 +132,11 @@ const refund = async () => {
:required="true"
/>
-
-
-
- {{ t('Inherit warehouse tooltip') }}
-
-
+
diff --git a/src/components/TicketProblems.vue b/src/components/TicketProblems.vue
index 934b13a1c..783f2556f 100644
--- a/src/components/TicketProblems.vue
+++ b/src/components/TicketProblems.vue
@@ -4,26 +4,21 @@ import { toCurrency } from 'src/filters';
defineProps({ row: { type: Object, required: true } });
-
-
+
- {{ $t('salesTicketsTable.noVerifiedData') }}
-
-
- {{ $t('salesTicketsTable.purchaseRequest') }}
-
-
- {{ $t('salesTicketsTable.notVisible') }}
-
-
- {{ $t('salesTicketsTable.clientFrozen') }}
-
+
+
+ {{ t('ticketSale.claim') }}:
+ {{ row.claim?.claimFk }}
+
+
+
-
+
{{ $t('salesTicketsTable.componentLack') }}
-
+
+
+ {{ $t('ticket.summary.hasItemDelay') }}
+
+
+
+
+ {{ $t('salesTicketsTable.hasItemLost') }}
+
+
+
+ {{ $t('salesTicketsTable.notVisible') }}
+
+
+
+ {{ $t('ticketList.rounding') }}
+
+
+
+ {{ $t('salesTicketsTable.purchaseRequest') }}
+
+
+ {{ $t('salesTicketsTable.noVerifiedData') }}
+
+
+ {{ $t('salesTicketsTable.clientFrozen') }}
+
+
{{ $t('salesTicketsTable.tooLittle') }}
diff --git a/src/components/TransferInvoiceForm.vue b/src/components/TransferInvoiceForm.vue
index aa71070d6..c4ef1454a 100644
--- a/src/components/TransferInvoiceForm.vue
+++ b/src/components/TransferInvoiceForm.vue
@@ -10,6 +10,7 @@ import VnSelect from 'components/common/VnSelect.vue';
import FormPopup from './FormPopup.vue';
import axios from 'axios';
import useNotify from 'src/composables/useNotify.js';
+import VnCheckbox from './common/VnCheckbox.vue';
const $props = defineProps({
invoiceOutData: {
@@ -186,15 +187,11 @@ const makeInvoice = async () => {
/>
-
-
-
- {{ t('transferInvoiceInfo') }}
-
-
+
diff --git a/src/components/VnTable/VnColumn.vue b/src/components/VnTable/VnColumn.vue
index 9e9bfad69..44364cca1 100644
--- a/src/components/VnTable/VnColumn.vue
+++ b/src/components/VnTable/VnColumn.vue
@@ -1,9 +1,8 @@
diff --git a/src/components/VnTable/VnFilter.vue b/src/components/VnTable/VnFilter.vue
index 426f5c716..2dad8fe52 100644
--- a/src/components/VnTable/VnFilter.vue
+++ b/src/components/VnTable/VnFilter.vue
@@ -1,14 +1,12 @@
-
-
+ {
/>
+
diff --git a/src/components/VnTable/VnOrder.vue b/src/components/VnTable/VnOrder.vue
index 8ffdfe2bc..e3795cc4b 100644
--- a/src/components/VnTable/VnOrder.vue
+++ b/src/components/VnTable/VnOrder.vue
@@ -41,6 +41,7 @@ async function orderBy(name, direction) {
break;
}
if (!direction) return await arrayData.deleteOrder(name);
+
await arrayData.addOrder(name, direction);
}
@@ -51,45 +52,60 @@ defineExpose({ orderBy });
@mouseenter="hover = true"
@mouseleave="hover = false"
@click="orderBy(name, model?.direction)"
- class="row items-center no-wrap cursor-pointer"
+ class="row items-center no-wrap cursor-pointer title"
>
{{ label }}
-
-
+
- {{ model?.index }}
-
-
-
+
+ {{ model?.index }}
+
+
+
+
+
diff --git a/src/components/VnTable/VnTable.vue b/src/components/VnTable/VnTable.vue
index 29ede7cbe..02e870add 100644
--- a/src/components/VnTable/VnTable.vue
+++ b/src/components/VnTable/VnTable.vue
@@ -1,22 +1,37 @@
-
+
@@ -67,3 +72,21 @@ function columnName(col) {
+
diff --git a/src/components/VnTable/VnVisibleColumn.vue b/src/components/VnTable/VnVisibleColumn.vue
index dad950d73..6d15c585e 100644
--- a/src/components/VnTable/VnVisibleColumn.vue
+++ b/src/components/VnTable/VnVisibleColumn.vue
@@ -32,16 +32,21 @@ const areAllChecksMarked = computed(() => {
function setUserConfigViewData(data, isLocal) {
if (!data) return;
- // Importante: El name de las columnas de la tabla debe conincidir con el name de las variables que devuelve la view config
if (!isLocal) localColumns.value = [];
- // Array to Object
+
const skippeds = $props.skip.reduce((a, v) => ({ ...a, [v]: v }), {});
for (let column of columns.value) {
- const { label, name } = column;
+ const { label, name, labelAbbreviation } = column;
if (skippeds[name]) continue;
column.visible = data[name] ?? true;
- if (!isLocal) localColumns.value.push({ name, label, visible: column.visible });
+ if (!isLocal)
+ localColumns.value.push({
+ name,
+ label,
+ labelAbbreviation,
+ visible: column.visible,
+ });
}
}
@@ -152,7 +157,11 @@ onMounted(async () => {
diff --git a/src/components/__tests__/FormModel.spec.js b/src/components/__tests__/FormModel.spec.js
index e35684bc3..3dce04374 100644
--- a/src/components/__tests__/FormModel.spec.js
+++ b/src/components/__tests__/FormModel.spec.js
@@ -57,6 +57,7 @@ describe('FormModel', () => {
vm.state.set(model, formInitialData);
expect(vm.hasChanges).toBe(false);
+ await vm.$nextTick();
vm.formData.mockKey = 'newVal';
await vm.$nextTick();
expect(vm.hasChanges).toBe(true);
@@ -93,9 +94,13 @@ describe('FormModel', () => {
it('should call axios.patch with the right data', async () => {
const spy = vi.spyOn(axios, 'patch').mockResolvedValue({ data: {} });
- const { vm } = mount({ propsData: { url, model, formInitialData } });
- vm.formData.mockKey = 'newVal';
+ const { vm } = mount({ propsData: { url, model } });
+
+ vm.formData = {};
await vm.$nextTick();
+ vm.formData = { mockKey: 'newVal' };
+ await vm.$nextTick();
+
await vm.save();
expect(spy).toHaveBeenCalled();
vm.formData.mockKey = 'mockVal';
@@ -106,6 +111,7 @@ describe('FormModel', () => {
const { vm } = mount({
propsData: { url, model, formInitialData, urlCreate: 'mockUrlCreate' },
});
+ await vm.$nextTick();
vm.formData.mockKey = 'newVal';
await vm.$nextTick();
await vm.save();
@@ -119,7 +125,7 @@ describe('FormModel', () => {
});
const spyPatch = vi.spyOn(axios, 'patch').mockResolvedValue({ data: {} });
const spySaveFn = vi.spyOn(vm.$props, 'saveFn');
-
+ await vm.$nextTick();
vm.formData.mockKey = 'newVal';
await vm.$nextTick();
await vm.save();
diff --git a/src/components/__tests__/Leftmenu.spec.js b/src/components/__tests__/Leftmenu.spec.js
index 10d9d66fb..4ab8b527f 100644
--- a/src/components/__tests__/Leftmenu.spec.js
+++ b/src/components/__tests__/Leftmenu.spec.js
@@ -1,9 +1,12 @@
-import { vi, describe, expect, it, beforeAll } from 'vitest';
+import { vi, describe, expect, it, beforeAll, beforeEach, afterEach } from 'vitest';
import { createWrapper, axios } from 'app/test/vitest/helper';
import Leftmenu from 'components/LeftMenu.vue';
-
+import * as vueRouter from 'vue-router';
import { useNavigationStore } from 'src/stores/useNavigationStore';
+let vm;
+let navigation;
+
vi.mock('src/router/modules', () => ({
default: [
{
@@ -21,6 +24,16 @@ vi.mock('src/router/modules', () => ({
{
path: '',
name: 'CustomerMain',
+ meta: {
+ menu: 'Customer',
+ menuChildren: [
+ {
+ name: 'CustomerCreditContracts',
+ title: 'creditContracts',
+ icon: 'vn:solunion',
+ },
+ ],
+ },
children: [
{
path: 'list',
@@ -28,6 +41,13 @@ vi.mock('src/router/modules', () => ({
meta: {
title: 'list',
icon: 'view_list',
+ menuChildren: [
+ {
+ name: 'CustomerCreditContracts',
+ title: 'creditContracts',
+ icon: 'vn:solunion',
+ },
+ ],
},
},
{
@@ -44,51 +64,325 @@ vi.mock('src/router/modules', () => ({
},
],
}));
-
-describe('Leftmenu', () => {
- let vm;
- let navigation;
- beforeAll(() => {
- vi.spyOn(axios, 'get').mockResolvedValue({
- data: [],
- });
-
- vm = createWrapper(Leftmenu, {
- propsData: {
- source: 'main',
+vi.spyOn(vueRouter, 'useRoute').mockReturnValue({
+ matched: [
+ {
+ path: '/',
+ redirect: {
+ name: 'Dashboard',
},
- }).vm;
-
- navigation = useNavigationStore();
- navigation.fetchPinned = vi.fn().mockReturnValue(Promise.resolve(true));
- navigation.getModules = vi.fn().mockReturnValue({
- value: [
+ name: 'Main',
+ meta: {},
+ props: {
+ default: false,
+ },
+ children: [
{
- name: 'customer',
- title: 'customer.pageTitles.customers',
- icon: 'vn:customer',
- module: 'customer',
+ path: '/dashboard',
+ name: 'Dashboard',
+ meta: {
+ title: 'dashboard',
+ icon: 'dashboard',
+ },
},
],
+ },
+ {
+ path: '/customer',
+ redirect: {
+ name: 'CustomerMain',
+ },
+ name: 'Customer',
+ meta: {
+ title: 'customers',
+ icon: 'vn:client',
+ moduleName: 'Customer',
+ keyBinding: 'c',
+ menu: 'customer',
+ },
+ },
+ ],
+ query: {},
+ params: {},
+ meta: { moduleName: 'mockName' },
+ path: 'mockName/1',
+ name: 'Customer',
+});
+function mount(source = 'main') {
+ vi.spyOn(axios, 'get').mockResolvedValue({
+ data: [],
+ });
+ const wrapper = createWrapper(Leftmenu, {
+ propsData: {
+ source,
+ },
+ });
+
+ navigation = useNavigationStore();
+ navigation.fetchPinned = vi.fn().mockReturnValue(Promise.resolve(true));
+ navigation.getModules = vi.fn().mockReturnValue({
+ value: [
+ {
+ name: 'customer',
+ title: 'customer.pageTitles.customers',
+ icon: 'vn:customer',
+ module: 'customer',
+ },
+ ],
+ });
+ return wrapper;
+}
+
+describe('getRoutes', () => {
+ afterEach(() => vi.clearAllMocks());
+ const getRoutes = vi.fn().mockImplementation((props, getMethodA, getMethodB) => {
+ const handleRoutes = {
+ methodA: getMethodA,
+ methodB: getMethodB,
+ };
+ try {
+ handleRoutes[props.source]();
+ } catch (error) {
+ throw Error('Method not defined');
+ }
+ });
+
+ const getMethodA = vi.fn();
+ const getMethodB = vi.fn();
+ const fn = (props) => getRoutes(props, getMethodA, getMethodB);
+
+ it('should call getMethodB when source is card', () => {
+ let props = { source: 'methodB' };
+ fn(props);
+
+ expect(getMethodB).toHaveBeenCalled();
+ expect(getMethodA).not.toHaveBeenCalled();
+ });
+ it('should call getMethodA when source is main', () => {
+ let props = { source: 'methodA' };
+ fn(props);
+
+ expect(getMethodA).toHaveBeenCalled();
+ expect(getMethodB).not.toHaveBeenCalled();
+ });
+
+ it('should call getMethodA when source is not exists or undefined', () => {
+ let props = { source: 'methodC' };
+ expect(() => fn(props)).toThrowError('Method not defined');
+
+ expect(getMethodA).not.toHaveBeenCalled();
+ expect(getMethodB).not.toHaveBeenCalled();
+ });
+});
+
+describe('Leftmenu as card', () => {
+ beforeAll(() => {
+ vm = mount('card').vm;
+ });
+
+ it('should get routes for card source', async () => {
+ vm.getRoutes();
+ });
+});
+describe('Leftmenu as main', () => {
+ beforeEach(() => {
+ vm = mount().vm;
+ });
+
+ it('should initialize with default props', () => {
+ expect(vm.source).toBe('main');
+ });
+
+ it('should filter items based on search input', async () => {
+ vm.search = 'cust';
+ await vm.$nextTick();
+ expect(vm.filteredItems[0].name).toEqual('customer');
+ expect(vm.filteredItems[0].module).toEqual('customer');
+ });
+ it('should filter items based on search input', async () => {
+ vm.search = 'Rou';
+ await vm.$nextTick();
+ expect(vm.filteredItems).toEqual([]);
+ });
+
+ it('should return pinned items', () => {
+ vm.items = [
+ { name: 'Item 1', isPinned: false },
+ { name: 'Item 2', isPinned: true },
+ ];
+ expect(vm.pinnedModules).toEqual(
+ new Map([['Item 2', { name: 'Item 2', isPinned: true }]]),
+ );
+ });
+
+ it('should find matches in routes', () => {
+ const search = 'child1';
+ const item = {
+ children: [
+ { name: 'child1', children: [] },
+ { name: 'child2', children: [] },
+ ],
+ };
+ const matches = vm.findMatches(search, item);
+ expect(matches).toEqual([{ name: 'child1', children: [] }]);
+ });
+ it('should not proceed if event is already prevented', async () => {
+ const item = { module: 'testModule', isPinned: false };
+ const event = {
+ preventDefault: vi.fn(),
+ stopPropagation: vi.fn(),
+ defaultPrevented: true,
+ };
+
+ await vm.togglePinned(item, event);
+
+ expect(event.preventDefault).not.toHaveBeenCalled();
+ expect(event.stopPropagation).not.toHaveBeenCalled();
+ });
+
+ it('should call quasar.notify with success message', async () => {
+ const item = { module: 'testModule', isPinned: false };
+ const event = {
+ preventDefault: vi.fn(),
+ stopPropagation: vi.fn(),
+ defaultPrevented: false,
+ };
+ const response = { data: { id: 1 } };
+
+ vi.spyOn(axios, 'post').mockResolvedValue(response);
+ vi.spyOn(vm.quasar, 'notify');
+
+ await vm.togglePinned(item, event);
+
+ expect(vm.quasar.notify).toHaveBeenCalledWith({
+ message: 'Data saved',
+ type: 'positive',
});
});
- it('should return a proper formated object with two child items', async () => {
- const expectedMenuItem = [
- {
- children: null,
- name: 'CustomerList',
- title: 'globals.pageTitles.list',
- icon: 'view_list',
- },
- {
- children: null,
- name: 'CustomerCreate',
- title: 'globals.pageTitles.createCustomer',
- icon: 'vn:addperson',
- },
- ];
- const firstMenuItem = vm.items[0];
- expect(firstMenuItem.children).toEqual(expect.arrayContaining(expectedMenuItem));
+ it('should handle a single matched route with a menu', () => {
+ const route = {
+ matched: [{ meta: { menu: 'customer' } }],
+ };
+
+ const result = vm.betaGetRoutes();
+
+ expect(result.meta.menu).toEqual(route.matched[0].meta.menu);
+ });
+ it('should get routes for main source', () => {
+ vm.props.source = 'main';
+ vm.getRoutes();
+ expect(navigation.getModules).toHaveBeenCalled();
+ });
+
+ it('should find direct child matches', () => {
+ const search = 'child1';
+ const item = {
+ children: [{ name: 'child1' }, { name: 'child2' }],
+ };
+ const result = vm.findMatches(search, item);
+ expect(result).toEqual([{ name: 'child1' }]);
+ });
+
+ it('should find nested child matches', () => {
+ const search = 'child3';
+ const item = {
+ children: [
+ { name: 'child1' },
+ {
+ name: 'child2',
+ children: [{ name: 'child3' }],
+ },
+ ],
+ };
+ const result = vm.findMatches(search, item);
+ expect(result).toEqual([{ name: 'child3' }]);
+ });
+});
+
+describe('normalize', () => {
+ beforeAll(() => {
+ vm = mount('card').vm;
+ });
+ it('should normalize and lowercase text', () => {
+ const input = 'ÁÉÍÓÚáéíóú';
+ const expected = 'aeiouaeiou';
+ expect(vm.normalize(input)).toBe(expected);
+ });
+
+ it('should handle empty string', () => {
+ const input = '';
+ const expected = '';
+ expect(vm.normalize(input)).toBe(expected);
+ });
+
+ it('should handle text without diacritics', () => {
+ const input = 'hello';
+ const expected = 'hello';
+ expect(vm.normalize(input)).toBe(expected);
+ });
+
+ it('should handle mixed text', () => {
+ const input = 'Héllo Wórld!';
+ const expected = 'hello world!';
+ expect(vm.normalize(input)).toBe(expected);
+ });
+});
+
+describe('addChildren', () => {
+ const module = 'testModule';
+ beforeEach(() => {
+ vm = mount().vm;
+ vi.clearAllMocks();
+ });
+
+ it('should add menu items to parent if matches are found', () => {
+ const parent = 'testParent';
+ const route = {
+ meta: {
+ menu: 'testMenu',
+ },
+ children: [{ name: 'child1' }, { name: 'child2' }],
+ };
+ vm.addChildren(module, route, parent);
+
+ expect(navigation.addMenuItem).toHaveBeenCalled();
+ });
+
+ it('should handle routes with no meta menu', () => {
+ const route = {
+ meta: {},
+ menus: {},
+ };
+
+ const parent = [];
+
+ vm.addChildren(module, route, parent);
+ expect(navigation.addMenuItem).toHaveBeenCalled();
+ });
+
+ it('should handle empty parent array', () => {
+ const parent = [];
+ const route = {
+ meta: {
+ menu: 'child11',
+ },
+ children: [
+ {
+ name: 'child1',
+ meta: {
+ menuChildren: [
+ {
+ name: 'CustomerCreditContracts',
+ title: 'creditContracts',
+ icon: 'vn:solunion',
+ },
+ ],
+ },
+ },
+ ],
+ };
+ vm.addChildren(module, route, parent);
+ expect(navigation.addMenuItem).toHaveBeenCalled();
});
});
diff --git a/src/components/__tests__/UserPanel.spec.js b/src/components/__tests__/UserPanel.spec.js
index ac20f911e..9e449745a 100644
--- a/src/components/__tests__/UserPanel.spec.js
+++ b/src/components/__tests__/UserPanel.spec.js
@@ -1,61 +1,65 @@
-import { vi, describe, expect, it, beforeEach, beforeAll, afterEach } from 'vitest';
+import { vi, describe, expect, it, beforeEach, afterEach } from 'vitest';
import { createWrapper } from 'app/test/vitest/helper';
import UserPanel from 'src/components/UserPanel.vue';
import axios from 'axios';
import { useState } from 'src/composables/useState';
+vi.mock('src/utils/quasarLang', () => ({
+ default: vi.fn(),
+}));
+
describe('UserPanel', () => {
- let wrapper;
- let vm;
- let state;
+ let wrapper;
+ let vm;
+ let state;
- beforeEach(() => {
- wrapper = createWrapper(UserPanel, {});
- state = useState();
- state.setUser({
- id: 115,
- name: 'itmanagement',
- nickname: 'itManagementNick',
- lang: 'en',
- darkMode: false,
- companyFk: 442,
- warehouseFk: 1,
- });
- wrapper = wrapper.wrapper;
- vm = wrapper.vm;
+ beforeEach(() => {
+ wrapper = createWrapper(UserPanel, {});
+ state = useState();
+ state.setUser({
+ id: 115,
+ name: 'itmanagement',
+ nickname: 'itManagementNick',
+ lang: 'en',
+ darkMode: false,
+ companyFk: 442,
+ warehouseFk: 1,
});
+ wrapper = wrapper.wrapper;
+ vm = wrapper.vm;
+ });
- afterEach(() => {
- vi.clearAllMocks();
- });
+ afterEach(() => {
+ vi.clearAllMocks();
+ });
- it('should fetch warehouses data on mounted', async () => {
- const fetchData = wrapper.findComponent({ name: 'FetchData' });
- expect(fetchData.props('url')).toBe('Warehouses');
- expect(fetchData.props('autoLoad')).toBe(true);
- });
+ it('should fetch warehouses data on mounted', async () => {
+ const fetchData = wrapper.findComponent({ name: 'FetchData' });
+ expect(fetchData.props('url')).toBe('Warehouses');
+ expect(fetchData.props('autoLoad')).toBe(true);
+ });
- it('should toggle dark mode correctly and update preferences', async () => {
- await vm.saveDarkMode(true);
- expect(axios.patch).toHaveBeenCalledWith('/UserConfigs/115', { darkMode: true });
- expect(vm.user.darkMode).toBe(true);
- vm.updatePreferences();
- expect(vm.darkMode).toBe(true);
- });
+ it('should toggle dark mode correctly and update preferences', async () => {
+ await vm.saveDarkMode(true);
+ expect(axios.patch).toHaveBeenCalledWith('/UserConfigs/115', { darkMode: true });
+ expect(vm.user.darkMode).toBe(true);
+ await vm.updatePreferences();
+ expect(vm.darkMode).toBe(true);
+ });
- it('should change user language and update preferences', async () => {
- const userLanguage = 'es';
- await vm.saveLanguage(userLanguage);
- expect(axios.patch).toHaveBeenCalledWith('/VnUsers/115', { lang: userLanguage });
- expect(vm.user.lang).toBe(userLanguage);
- vm.updatePreferences();
- expect(vm.locale).toBe(userLanguage);
- });
+ it('should change user language and update preferences', async () => {
+ const userLanguage = 'es';
+ await vm.saveLanguage(userLanguage);
+ expect(axios.patch).toHaveBeenCalledWith('/VnUsers/115', { lang: userLanguage });
+ expect(vm.user.lang).toBe(userLanguage);
+ await vm.updatePreferences();
+ expect(vm.locale).toBe(userLanguage);
+ });
- it('should update user data', async () => {
- const key = 'name';
- const value = 'itboss';
- await vm.saveUserData(key, value);
- expect(axios.post).toHaveBeenCalledWith('UserConfigs/setUserConfig', { [key]: value });
- });
-});
+ it('should update user data', async () => {
+ const key = 'name';
+ const value = 'itboss';
+ await vm.saveUserData(key, value);
+ expect(axios.post).toHaveBeenCalledWith('UserConfigs/setUserConfig', { [key]: value });
+ });
+});
\ No newline at end of file
diff --git a/src/components/common/VnCard.vue b/src/components/common/VnCard.vue
index 0d80f43ce..44002c22a 100644
--- a/src/components/common/VnCard.vue
+++ b/src/components/common/VnCard.vue
@@ -10,11 +10,11 @@ import LeftMenu from 'components/LeftMenu.vue';
import RightMenu from 'components/common/RightMenu.vue';
const props = defineProps({
dataKey: { type: String, required: true },
- baseUrl: { type: String, default: undefined },
- customUrl: { type: String, default: undefined },
+ url: { type: String, default: undefined },
filter: { type: Object, default: () => {} },
descriptor: { type: Object, required: true },
filterPanel: { type: Object, default: undefined },
+ idInWhere: { type: Boolean, default: false },
searchDataKey: { type: String, default: undefined },
searchbarProps: { type: Object, default: undefined },
redirectOnError: { type: Boolean, default: false },
@@ -23,25 +23,20 @@ const props = defineProps({
const stateStore = useStateStore();
const route = useRoute();
const router = useRouter();
-const url = computed(() => {
- if (props.baseUrl) {
- return `${props.baseUrl}/${route.params.id}`;
- }
- return props.customUrl;
-});
const searchRightDataKey = computed(() => {
if (!props.searchDataKey) return route.name;
return props.searchDataKey;
});
+
const arrayData = useArrayData(props.dataKey, {
- url: url.value,
- filter: props.filter,
+ url: props.url,
+ userFilter: props.filter,
+ oneRecord: true,
});
onBeforeMount(async () => {
try {
- if (!props.baseUrl) arrayData.store.filter.where = { id: route.params.id };
- await arrayData.fetch({ append: false, updateRouter: false });
+ await fetch(route.params.id);
} catch {
const { matched: matches } = router.currentRoute.value;
const { path } = matches.at(-1);
@@ -49,13 +44,17 @@ onBeforeMount(async () => {
}
});
-if (props.baseUrl) {
- onBeforeRouteUpdate(async (to, from) => {
- if (to.params.id !== from.params.id) {
- arrayData.store.url = `${props.baseUrl}/${to.params.id}`;
- await arrayData.fetch({ append: false, updateRouter: false });
- }
- });
+onBeforeRouteUpdate(async (to, from) => {
+ const id = to.params.id;
+ if (id !== from.params.id) await fetch(id, true);
+});
+
+async function fetch(id, append = false) {
+ const regex = /\/(\d+)/;
+ if (props.idInWhere) arrayData.store.filter.where = { id };
+ else if (!regex.test(props.url)) arrayData.store.url = `${props.url}/${id}`;
+ else arrayData.store.url = props.url.replace(regex, `/${id}`);
+ await arrayData.fetch({ append, updateRouter: false });
}
@@ -83,7 +82,7 @@ if (props.baseUrl) {
-
+
diff --git a/src/components/common/VnCardBeta.vue b/src/components/common/VnCardBeta.vue
index f237a300c..7c82316dc 100644
--- a/src/components/common/VnCardBeta.vue
+++ b/src/components/common/VnCardBeta.vue
@@ -1,6 +1,6 @@
+
+
+
+
+
+ {{ info }}
+
+
+
+
diff --git a/src/components/common/VnColor.vue b/src/components/common/VnColor.vue
new file mode 100644
index 000000000..8a5a787b0
--- /dev/null
+++ b/src/components/common/VnColor.vue
@@ -0,0 +1,32 @@
+
+
+
+
+
diff --git a/src/components/common/VnComponent.vue b/src/components/common/VnComponent.vue
index 580bcf348..d9d1ea26b 100644
--- a/src/components/common/VnComponent.vue
+++ b/src/components/common/VnComponent.vue
@@ -17,6 +17,8 @@ const $props = defineProps({
},
});
+const emit = defineEmits(['blur']);
+
const componentArray = computed(() => {
if (typeof $props.prop === 'object') return [$props.prop];
return $props.prop;
@@ -54,6 +56,7 @@ function toValueAttrs(attrs) {
v-bind="mix(toComponent).attrs"
v-on="mix(toComponent).event ?? {}"
v-model="model"
+ @blur="emit('blur')"
/>
diff --git a/src/components/common/VnDmsList.vue b/src/components/common/VnDmsList.vue
index 36c87bab0..424781a26 100644
--- a/src/components/common/VnDmsList.vue
+++ b/src/components/common/VnDmsList.vue
@@ -17,7 +17,7 @@ import { useSession } from 'src/composables/useSession';
const route = useRoute();
const quasar = useQuasar();
const { t } = useI18n();
-const rows = ref();
+const rows = ref([]);
const dmsRef = ref();
const formDialog = ref({});
const token = useSession().getTokenMultimedia();
@@ -389,6 +389,14 @@ defineExpose({
+
+
+ {{ t('No data to display') }}
+
+
@@ -405,7 +413,7 @@ defineExpose({
fab
color="primary"
icon="add"
- shortcut="+"
+ v-shortcut
@click="showFormDialog()"
class="fill-icon"
>
diff --git a/src/components/common/VnInput.vue b/src/components/common/VnInput.vue
index 78f08a479..aeb4a31fd 100644
--- a/src/components/common/VnInput.vue
+++ b/src/components/common/VnInput.vue
@@ -11,6 +11,7 @@ const emit = defineEmits([
'update:options',
'keyup.enter',
'remove',
+ 'blur',
]);
const $props = defineProps({
@@ -136,6 +137,7 @@ const handleUppercase = () => {
:type="$attrs.type"
:class="{ required: isRequired }"
@keyup.enter="emit('keyup.enter')"
+ @blur="emit('blur')"
@keydown="handleKeydown"
:clearable="false"
:rules="mixinRules"
@@ -143,7 +145,7 @@ const handleUppercase = () => {
hide-bottom-space
:data-cy="$attrs.dataCy ?? $attrs.label + '_input'"
>
-
+
@@ -168,11 +170,11 @@ const handleUppercase = () => {
}
"
>
-
+
@@ -180,7 +182,7 @@ const handleUppercase = () => {
{{ t('Convert to uppercase') }}
-
+
@@ -194,13 +196,15 @@ const handleUppercase = () => {
@@ -214,4 +218,4 @@ const handleUppercase = () => {
maxLength: El valor excede los {value} carácteres
inputMax: Debe ser menor a {value}
Convert to uppercase: Convertir a mayúsculas
-
\ No newline at end of file
+
diff --git a/src/components/common/VnInputDate.vue b/src/components/common/VnInputDate.vue
index a8888aad8..73c825e1e 100644
--- a/src/components/common/VnInputDate.vue
+++ b/src/components/common/VnInputDate.vue
@@ -42,7 +42,7 @@ const formattedDate = computed({
if (value.at(2) == '/') value = value.split('/').reverse().join('/');
value = date.formatDate(
new Date(value).toISOString(),
- 'YYYY-MM-DDTHH:mm:ss.SSSZ'
+ 'YYYY-MM-DDTHH:mm:ss.SSSZ',
);
}
const [year, month, day] = value.split('-').map((e) => parseInt(e));
@@ -55,7 +55,7 @@ const formattedDate = computed({
orgDate.getHours(),
orgDate.getMinutes(),
orgDate.getSeconds(),
- orgDate.getMilliseconds()
+ orgDate.getMilliseconds(),
);
}
}
@@ -64,7 +64,7 @@ const formattedDate = computed({
});
const popupDate = computed(() =>
- model.value ? date.formatDate(new Date(model.value), 'YYYY/MM/DD') : model.value
+ model.value ? date.formatDate(new Date(model.value), 'YYYY/MM/DD') : model.value,
);
onMounted(() => {
// fix quasar bug
@@ -73,7 +73,7 @@ onMounted(() => {
watch(
() => model.value,
(val) => (formattedDate.value = val),
- { immediate: true }
+ { immediate: true },
);
const styleAttrs = computed(() => {
diff --git a/src/components/common/VnInputNumber.vue b/src/components/common/VnInputNumber.vue
index 165cfae3d..274f78b21 100644
--- a/src/components/common/VnInputNumber.vue
+++ b/src/components/common/VnInputNumber.vue
@@ -8,6 +8,7 @@ defineProps({
});
const model = defineModel({ type: [Number, String] });
+const emit = defineEmits(['blur']);
diff --git a/src/components/common/VnPopupProxy.vue b/src/components/common/VnPopupProxy.vue
new file mode 100644
index 000000000..f386bfff8
--- /dev/null
+++ b/src/components/common/VnPopupProxy.vue
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
+ {{ $t($props.tooltip) }}
+
+
+
diff --git a/src/components/common/VnSection.vue b/src/components/common/VnSection.vue
index ef65b841f..4bd17124f 100644
--- a/src/components/common/VnSection.vue
+++ b/src/components/common/VnSection.vue
@@ -106,7 +106,14 @@ function checkIsMain() {
:data-key="dataKey"
:array-data="arrayData"
:columns="columns"
- />
+ >
+
+
+
+
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/VnSelectCache.vue b/src/components/common/VnSelectCache.vue
index 29cf22dc5..f0f3357f6 100644
--- a/src/components/common/VnSelectCache.vue
+++ b/src/components/common/VnSelectCache.vue
@@ -14,7 +14,7 @@ const $props = defineProps({
},
});
const options = ref([]);
-
+const emit = defineEmits(['blur']);
onBeforeMount(async () => {
const { url, optionValue, optionLabel } = useAttrs();
const findBy = $props.find ?? url?.charAt(0)?.toLocaleLowerCase() + url?.slice(1, -1);
@@ -35,5 +35,5 @@ onBeforeMount(async () => {
});
-
+
diff --git a/src/components/common/VnSelectDialog.vue b/src/components/common/VnSelectDialog.vue
index a4cd0011d..41730b217 100644
--- a/src/components/common/VnSelectDialog.vue
+++ b/src/components/common/VnSelectDialog.vue
@@ -37,7 +37,6 @@ const isAllowedToCreate = computed(() => {
defineExpose({ vnSelectDialogRef: select });
-
-
+
+ en:
+ globals:
+ copyId: Copy ID
+ es:
+ globals:
+ copyId: Copiar ID
+
diff --git a/src/components/ui/CardSummary.vue b/src/components/ui/CardSummary.vue
index c815b8e16..6a61994c1 100644
--- a/src/components/ui/CardSummary.vue
+++ b/src/components/ui/CardSummary.vue
@@ -40,9 +40,10 @@ const arrayData = useArrayData(props.dataKey, {
filter: props.filter,
userFilter: props.userFilter,
skip: 0,
+ oneRecord: true,
});
const { store } = arrayData;
-const entity = computed(() => (Array.isArray(store.data) ? store.data[0] : store.data));
+const entity = computed(() => store.data);
const isLoading = ref(false);
defineExpose({
@@ -61,7 +62,7 @@ async function fetch() {
store.filter = props.filter ?? {};
isLoading.value = true;
const { data } = await arrayData.fetch({ append: false, updateRouter: false });
- emit('onFetch', Array.isArray(data) ? data[0] : data);
+ emit('onFetch', data);
isLoading.value = false;
}
@@ -208,4 +209,13 @@ async function fetch() {
.summaryHeader {
color: $white;
}
+
+.cardSummary :deep(.q-card__section[content]) {
+ display: flex;
+ flex-wrap: wrap;
+ padding: 0;
+ > * {
+ flex: 1;
+ }
+}
diff --git a/src/components/ui/SkeletonDescriptor.vue b/src/components/ui/SkeletonDescriptor.vue
index 9679751f5..f9188221a 100644
--- a/src/components/ui/SkeletonDescriptor.vue
+++ b/src/components/ui/SkeletonDescriptor.vue
@@ -1,53 +1,32 @@
+
-
+
-
-
-
+
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
-
+
+
-
-
diff --git a/src/components/ui/VnConfirm.vue b/src/components/ui/VnConfirm.vue
index a02b56bdb..c6f539879 100644
--- a/src/components/ui/VnConfirm.vue
+++ b/src/components/ui/VnConfirm.vue
@@ -82,7 +82,7 @@ function cancel() {
@click="cancel()"
/>
-
+
@@ -95,6 +95,7 @@ function cancel() {
:disable="isLoading"
flat
@click="cancel()"
+ data-cy="VnConfirm_cancel"
/>
- $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) {
@@ -188,10 +188,13 @@ function formatValue(value) {
const getLocale = (label) => {
const param = label.split('.').at(-1);
const globalLocale = `globals.params.${param}`;
+ const moduleName = route.meta.moduleName;
+ const moduleLocale = `${moduleName.toLowerCase()}.${param}`;
if (te(globalLocale)) return t(globalLocale);
- else if (te(t(`params.${param}`)));
+ else if (te(moduleLocale)) return t(moduleLocale);
else {
- const camelCaseModuleName = route.meta.moduleName.charAt(0).toLowerCase() + route.meta.moduleName.slice(1);
+ const camelCaseModuleName =
+ moduleName.charAt(0).toLowerCase() + moduleName.slice(1);
return t(`${camelCaseModuleName}.params.${param}`);
}
};
@@ -290,6 +293,9 @@ const getLocale = (label) => {
/>
es:
@@ -205,4 +279,6 @@ onBeforeRouteLeave((to, from, next) => {
New note: Nueva nota
Save (Enter): Guardar (Intro)
Observation type: Tipo de observación
+ New note is empty: La nueva nota esta vacia
+ Are you sure remove this note?: Estas seguro de quitar esta nota?
diff --git a/src/components/ui/VnStockValueDisplay.vue b/src/components/ui/VnStockValueDisplay.vue
new file mode 100644
index 000000000..d8f43323b
--- /dev/null
+++ b/src/components/ui/VnStockValueDisplay.vue
@@ -0,0 +1,41 @@
+
+
+
+
+ {{ toPercentage(formattedValue) }}
+
+
+
+
diff --git a/src/components/ui/VnSubToolbar.vue b/src/components/ui/VnSubToolbar.vue
index 5ded4be00..8d4126d1d 100644
--- a/src/components/ui/VnSubToolbar.vue
+++ b/src/components/ui/VnSubToolbar.vue
@@ -19,23 +19,26 @@ onMounted(() => {
const observer = new MutationObserver(
() =>
(hasContent.value =
- actions.value?.childNodes?.length + data.value?.childNodes?.length)
+ actions.value?.childNodes?.length + data.value?.childNodes?.length),
);
if (actions.value) observer.observe(actions.value, opts);
if (data.value) observer.observe(data.value, opts);
});
-onBeforeUnmount(() => stateStore.toggleSubToolbar());
+const actionsChildCount = () => !!actions.value?.childNodes?.length;
+
+onBeforeUnmount(() => stateStore.toggleSubToolbar() && hasSubToolbar);
-
+
+
diff --git a/src/components/ui/__tests__/CardSummary.spec.js b/src/components/ui/__tests__/CardSummary.spec.js
index 411ebf9bb..2f7f90882 100644
--- a/src/components/ui/__tests__/CardSummary.spec.js
+++ b/src/components/ui/__tests__/CardSummary.spec.js
@@ -51,16 +51,6 @@ describe('CardSummary', () => {
expect(vm.store.filter).toEqual('cardFilter');
});
- it('should compute entity correctly from store data', () => {
- vm.store.data = [{ id: 1, name: 'Entity 1' }];
- expect(vm.entity).toEqual({ id: 1, name: 'Entity 1' });
- });
-
- it('should handle empty data gracefully', () => {
- vm.store.data = [];
- expect(vm.entity).toBeUndefined();
- });
-
it('should respond to prop changes and refetch data', async () => {
const newUrl = 'CardSummary/35';
const newKey = 'cardSummaryKey/35';
@@ -72,7 +62,7 @@ describe('CardSummary', () => {
expect(vm.store.filter).toEqual({ key: newKey });
});
- it('should return true if route path ends with /summary' , () => {
+ it('should return true if route path ends with /summary', () => {
expect(vm.isSummary).toBe(true);
});
-});
\ No newline at end of file
+});
diff --git a/src/composables/__tests__/useArrayData.spec.js b/src/composables/__tests__/useArrayData.spec.js
index d4c5d0949..a610ba9eb 100644
--- a/src/composables/__tests__/useArrayData.spec.js
+++ b/src/composables/__tests__/useArrayData.spec.js
@@ -16,7 +16,7 @@ describe('useArrayData', () => {
vi.clearAllMocks();
});
- it('should fetch and repalce url with new params', async () => {
+ it('should fetch and replace url with new params', async () => {
vi.spyOn(axios, 'get').mockReturnValueOnce({ data: [] });
const arrayData = useArrayData('ArrayData', { url: 'mockUrl' });
@@ -33,11 +33,11 @@ describe('useArrayData', () => {
});
expect(routerReplace.path).toEqual('mockSection/list');
expect(JSON.parse(routerReplace.query.params)).toEqual(
- expect.objectContaining(params)
+ expect.objectContaining(params),
);
});
- it('Should get data and send new URL without keeping parameters, if there is only one record', async () => {
+ it('should get data and send new URL without keeping parameters, if there is only one record', async () => {
vi.spyOn(axios, 'get').mockReturnValueOnce({ data: [{ id: 1 }] });
const arrayData = useArrayData('ArrayData', { url: 'mockUrl', navigate: {} });
@@ -56,7 +56,7 @@ describe('useArrayData', () => {
expect(routerPush.query).toBeUndefined();
});
- it('Should get data and send new URL keeping parameters, if you have more than one record', async () => {
+ it('should get data and send new URL keeping parameters, if you have more than one record', async () => {
vi.spyOn(axios, 'get').mockReturnValueOnce({ data: [{ id: 1 }, { id: 2 }] });
vi.spyOn(vueRouter, 'useRoute').mockReturnValue({
@@ -95,4 +95,25 @@ describe('useArrayData', () => {
expect(routerPush.path).toEqual('mockName/');
expect(routerPush.query.params).toBeDefined();
});
+
+ it('should return one record', async () => {
+ vi.spyOn(axios, 'get').mockReturnValueOnce({
+ data: [
+ { id: 1, name: 'Entity 1' },
+ { id: 2, name: 'Entity 2' },
+ ],
+ });
+ const arrayData = useArrayData('ArrayData', { url: 'mockUrl', oneRecord: true });
+ await arrayData.fetch({});
+
+ expect(arrayData.store.data).toEqual({ id: 1, name: 'Entity 1' });
+ });
+
+ it('should handle empty data gracefully if has to return one record', async () => {
+ vi.spyOn(axios, 'get').mockReturnValueOnce({ data: [] });
+ const arrayData = useArrayData('ArrayData', { url: 'mockUrl', oneRecord: true });
+ await arrayData.fetch({});
+
+ expect(arrayData.store.data).toBeUndefined();
+ });
});
diff --git a/src/composables/checkEntryLock.js b/src/composables/checkEntryLock.js
new file mode 100644
index 000000000..f964dea27
--- /dev/null
+++ b/src/composables/checkEntryLock.js
@@ -0,0 +1,65 @@
+import { useQuasar } from 'quasar';
+import { useI18n } from 'vue-i18n';
+import { useRouter } from 'vue-router';
+import axios from 'axios';
+import VnConfirm from 'components/ui/VnConfirm.vue';
+
+export async function checkEntryLock(entryFk, userFk) {
+ const { t } = useI18n();
+ const quasar = useQuasar();
+ const { push } = useRouter();
+ const { data } = await axios.get(`Entries/${entryFk}`, {
+ params: {
+ filter: JSON.stringify({
+ fields: ['id', 'locked', 'lockerUserFk'],
+ include: { relation: 'user', scope: { fields: ['id', 'nickname'] } },
+ }),
+ },
+ });
+ const entryConfig = await axios.get('EntryConfigs/findOne');
+
+ if (data?.lockerUserFk && data?.locked) {
+ const now = new Date(Date.vnNow()).getTime();
+ const lockedTime = new Date(data.locked).getTime();
+ const timeDiff = (now - lockedTime) / 1000;
+ const isMaxTimeLockExceeded = entryConfig.data.maxLockTime > timeDiff;
+
+ if (data?.lockerUserFk !== userFk && isMaxTimeLockExceeded) {
+ quasar
+ .dialog({
+ component: VnConfirm,
+ componentProps: {
+ 'data-cy': 'entry-lock-confirm',
+ title: t('entry.lock.title'),
+ message: t('entry.lock.message', {
+ userName: data?.user?.nickname,
+ time: timeDiff / 60,
+ }),
+ },
+ })
+ .onOk(
+ async () =>
+ await axios.patch(`Entries/${entryFk}`, {
+ locked: Date.vnNow(),
+ lockerUserFk: userFk,
+ }),
+ )
+ .onCancel(() => {
+ push({ path: `summary` });
+ });
+ }
+ } else {
+ await axios
+ .patch(`Entries/${entryFk}`, {
+ locked: Date.vnNow(),
+ lockerUserFk: userFk,
+ })
+ .then(
+ quasar.notify({
+ message: t('entry.lock.success'),
+ color: 'positive',
+ group: false,
+ }),
+ );
+ }
+}
diff --git a/src/composables/getColAlign.js b/src/composables/getColAlign.js
new file mode 100644
index 000000000..c0338a984
--- /dev/null
+++ b/src/composables/getColAlign.js
@@ -0,0 +1,21 @@
+export function getColAlign(col) {
+ let align;
+ switch (col.component) {
+ case 'select':
+ align = 'left';
+ break;
+ case 'number':
+ align = 'right';
+ break;
+ case 'date':
+ case 'checkbox':
+ align = 'center';
+ break;
+ default:
+ align = col?.align;
+ }
+
+ if (/^is[A-Z]/.test(col.name) || /^has[A-Z]/.test(col.name)) align = 'center';
+
+ return 'text-' + (align ?? 'center');
+}
diff --git a/src/composables/useArrayData.js b/src/composables/useArrayData.js
index bd3cecf08..fcc61972a 100644
--- a/src/composables/useArrayData.js
+++ b/src/composables/useArrayData.js
@@ -57,6 +57,7 @@ export function useArrayData(key, userOptions) {
'navigate',
'mapKey',
'keepData',
+ 'oneRecord',
];
if (typeof userOptions === 'object') {
for (const option in userOptions) {
@@ -112,7 +113,11 @@ export function useArrayData(key, userOptions) {
store.isLoading = false;
canceller = null;
- processData(response.data, { map: !!store.mapKey, append });
+ processData(response.data, {
+ map: !!store.mapKey,
+ append,
+ oneRecord: store.oneRecord,
+ });
return response;
}
@@ -314,7 +319,11 @@ export function useArrayData(key, userOptions) {
return { params, limit };
}
- function processData(data, { map = true, append = true }) {
+ function processData(data, { map = true, append = true, oneRecord = false }) {
+ if (oneRecord) {
+ store.data = Array.isArray(data) ? data[0] : data;
+ return;
+ }
if (!append) {
store.data = [];
store.map = new Map();
diff --git a/src/composables/useRole.js b/src/composables/useRole.js
index 3ec65dd0a..ff54b409c 100644
--- a/src/composables/useRole.js
+++ b/src/composables/useRole.js
@@ -27,6 +27,15 @@ export function useRole() {
return false;
}
+ function likeAny(roles) {
+ const roleStore = state.getRoles();
+ for (const role of roles) {
+ if (!roleStore.value.findIndex((rs) => rs.startsWith(role)) !== -1)
+ return true;
+ }
+
+ return false;
+ }
function isEmployee() {
return hasAny(['employee']);
}
@@ -35,6 +44,7 @@ export function useRole() {
isEmployee,
fetch,
hasAny,
+ likeAny,
state,
};
}
diff --git a/src/css/app.scss b/src/css/app.scss
index 7296b079f..0c5dc97fa 100644
--- a/src/css/app.scss
+++ b/src/css/app.scss
@@ -21,7 +21,10 @@ body.body--light {
.q-header .q-toolbar {
color: var(--vn-text-color);
}
+
+ --vn-color-negative: $negative;
}
+
body.body--dark {
--vn-header-color: #5d5d5d;
--vn-page-color: #222;
@@ -37,6 +40,8 @@ body.body--dark {
--vn-text-color-contrast: black;
background-color: var(--vn-page-color);
+
+ --vn-color-negative: $negative;
}
a {
@@ -75,7 +80,6 @@ a {
text-decoration: underline;
}
-// Removes chrome autofill background
input:-webkit-autofill,
select:-webkit-autofill {
color: var(--vn-text-color);
@@ -149,11 +153,6 @@ select:-webkit-autofill {
cursor: pointer;
}
-.vn-table-separation-row {
- height: 16px !important;
- background-color: var(--vn-section-color) !important;
-}
-
/* Estilo para el asterisco en campos requeridos */
.q-field.required .q-field__label:after {
content: ' *';
@@ -212,6 +211,10 @@ select:-webkit-autofill {
justify-content: center;
}
+.q-card__section[dense] {
+ padding: 0;
+}
+
input[type='number'] {
-moz-appearance: textfield;
}
@@ -226,10 +229,12 @@ input::-webkit-inner-spin-button {
max-width: 100%;
}
-.q-table__container {
- /* ===== Scrollbar CSS ===== /
- / Firefox */
+.remove-bg {
+ filter: brightness(1.1);
+ mix-blend-mode: multiply;
+}
+.q-table__container {
* {
scrollbar-width: auto;
scrollbar-color: var(--vn-label-color) transparent;
@@ -270,8 +275,6 @@ input::-webkit-inner-spin-button {
font-size: 11pt;
}
td {
- font-size: 11pt;
- border-top: 1px solid var(--vn-page-color);
border-collapse: collapse;
}
}
@@ -315,9 +318,6 @@ input::-webkit-inner-spin-button {
max-width: fit-content;
}
-.row > .column:has(.q-checkbox) {
- max-width: fit-content;
-}
.q-field__inner {
.q-field__control {
min-height: auto !important;
diff --git a/src/css/quasar.variables.scss b/src/css/quasar.variables.scss
index d6e992437..22c6d2b56 100644
--- a/src/css/quasar.variables.scss
+++ b/src/css/quasar.variables.scss
@@ -13,7 +13,7 @@
// Tip: Use the "Theme Builder" on Quasar's documentation website.
// Tip: to add new colors https://quasar.dev/style/color-palette/#adding-your-own-colors
$primary: #ec8916;
-$secondary: $primary;
+$secondary: #89be34;
$positive: #c8e484;
$negative: #fb5252;
$info: #84d0e2;
@@ -30,7 +30,9 @@ $color-spacer: #7979794d;
$border-thin-light: 1px solid $color-spacer-light;
$primary-light: #f5b351;
$dark-shadow-color: black;
-$layout-shadow-dark: 0 0 10px 2px #00000033, 0 0px 10px #0000003d;
+$layout-shadow-dark:
+ 0 0 10px 2px #00000033,
+ 0 0px 10px #0000003d;
$spacing-md: 16px;
$color-font-secondary: #777;
$width-xs: 400px;
diff --git a/src/i18n/locale/en.yml b/src/i18n/locale/en.yml
index d1fbdc312..acfdefb67 100644
--- a/src/i18n/locale/en.yml
+++ b/src/i18n/locale/en.yml
@@ -33,6 +33,7 @@ globals:
reset: Reset
close: Close
cancel: Cancel
+ isSaveAndContinue: Save and continue
clone: Clone
confirm: Confirm
assign: Assign
@@ -155,6 +156,7 @@ globals:
changeState: Change state
raid: 'Raid {daysInForward} days'
isVies: Vies
+ noData: No data available
pageTitles:
logIn: Login
addressEdit: Update address
@@ -167,6 +169,7 @@ globals:
workCenters: Work centers
modes: Modes
zones: Zones
+ negative: Negative
zonesList: List
deliveryDays: Delivery days
upcomingDeliveries: Upcoming deliveries
@@ -174,6 +177,7 @@ globals:
alias: Alias
aliasUsers: Users
subRoles: Subroles
+ myAccount: Mi cuenta
inheritedRoles: Inherited Roles
customers: Customers
customerCreate: New customer
@@ -332,10 +336,13 @@ globals:
wasteRecalc: Waste recaclulate
operator: Operator
parking: Parking
+ vehicleList: Vehicles
+ vehicle: Vehicle
unsavedPopup:
title: Unsaved changes will be lost
subtitle: Are you sure exit without saving?
params:
+ description: Description
clientFk: Client id
salesPersonFk: Sales person
warehouseFk: Warehouse
@@ -358,7 +365,13 @@ globals:
correctingFk: Rectificative
daysOnward: Days onward
countryFk: Country
+ countryCodeFk: Country
companyFk: Company
+ model: Model
+ fuel: Fuel
+ active: Active
+ inactive: Inactive
+ deliveryPoint: Delivery point
errors:
statusUnauthorized: Access denied
statusInternalServerError: An internal server error has ocurred
@@ -397,6 +410,106 @@ cau:
subtitle: By sending this ticket, all the data related to the error, the section, the user, etc., are already sent.
inputLabel: Explain why this error should not appear
askPrivileges: Ask for privileges
+entry:
+ list:
+ newEntry: New entry
+ tableVisibleColumns:
+ isExcludedFromAvailable: Exclude from inventory
+ isOrdered: Ordered
+ isConfirmed: Ready to label
+ isReceived: Received
+ 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
+ summary:
+ invoiceAmount: Amount
+ commission: Commission
+ currency: Currency
+ invoiceNumber: Invoice number
+ ordered: Ordered
+ booked: Booked
+ excludedFromAvailable: Inventory
+ travelReference: Reference
+ travelAgency: Agency
+ travelShipped: Shipped
+ travelDelivered: Delivered
+ travelLanded: Landed
+ travelReceived: Received
+ buys: Buys
+ stickers: Stickers
+ package: Package
+ packing: Pack.
+ grouping: Group.
+ buyingValue: Buying value
+ import: Import
+ pvp: PVP
+ basicData:
+ travel: Travel
+ currency: Currency
+ commission: Commission
+ observation: Observation
+ booked: Booked
+ excludedFromAvailable: Inventory
+ buys:
+ observations: Observations
+ packagingFk: Box
+ color: Color
+ printedStickers: Printed stickers
+ notes:
+ observationType: Observation type
+ latestBuys:
+ tableVisibleColumns:
+ image: Picture
+ itemFk: Item ID
+ weightByPiece: Weight/Piece
+ isActive: Active
+ family: Family
+ entryFk: Entry
+ freightValue: Freight value
+ comissionValue: Commission value
+ packageValue: Package value
+ isIgnored: Is ignored
+ price2: Grouping
+ price3: Packing
+ minPrice: Min
+ ektFk: Ekt
+ packingOut: Package out
+ landing: Landing
+ isExcludedFromAvailable: Exclude from inventory
+ isRaid: Raid
+ invoiceNumber: Invoice
+ reference: Ref/Alb/Guide
+ params:
+ isExcludedFromAvailable: Excluir del inventario
+ isOrdered: Pedida
+ isConfirmed: Lista para etiquetar
+ isReceived: Recibida
+ isRaid: Redada
+ 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
ticket:
params:
ticketFk: Ticket ID
@@ -626,6 +739,8 @@ wagon:
name: Name
supplier:
+ search: Search supplier
+ searchInfo: Search supplier by id or name
list:
payMethod: Pay method
account: Account
@@ -715,6 +830,8 @@ travel:
CloneTravelAndEntries: Clone travel and his entries
deleteTravel: Delete travel
AddEntry: Add entry
+ availabled: Availabled
+ availabledHour: Availabled hour
thermographs: Thermographs
hb: HB
basicData:
diff --git a/src/i18n/locale/es.yml b/src/i18n/locale/es.yml
index bfab41a75..6bf3affc0 100644
--- a/src/i18n/locale/es.yml
+++ b/src/i18n/locale/es.yml
@@ -33,9 +33,11 @@ globals:
reset: Restaurar
close: Cerrar
cancel: Cancelar
+ isSaveAndContinue: Guardar y continuar
clone: Clonar
confirm: Confirmar
assign: Asignar
+ replace: Sustituir
back: Volver
yes: Si
no: No
@@ -48,6 +50,7 @@ globals:
rowRemoved: Fila eliminada
pleaseWait: Por favor espera...
noPinnedModules: No has fijado ningún módulo
+ split: Split
summary:
basicData: Datos básicos
daysOnward: Días adelante
@@ -55,8 +58,8 @@ globals:
today: Hoy
yesterday: Ayer
dateFormat: es-ES
- microsip: Abrir en MicroSIP
noSelectedRows: No tienes ninguna línea seleccionada
+ microsip: Abrir en MicroSIP
downloadCSVSuccess: Descarga de CSV exitosa
reference: Referencia
agency: Agencia
@@ -76,8 +79,10 @@ globals:
requiredField: Campo obligatorio
class: clase
type: Tipo
- reason: motivo
+ reason: Motivo
+ removeSelection: Eliminar selección
noResults: Sin resultados
+ results: resultados
system: Sistema
notificationSent: Notificación enviada
warehouse: Almacén
@@ -155,6 +160,7 @@ globals:
changeState: Cambiar estado
raid: 'Redada {daysInForward} días'
isVies: Vies
+ noData: Datos no disponibles
pageTitles:
logIn: Inicio de sesión
addressEdit: Modificar consignatario
@@ -166,6 +172,7 @@ globals:
agency: Agencia
workCenters: Centros de trabajo
modes: Modos
+ negative: Tickets negativos
zones: Zonas
zonesList: Listado
deliveryDays: Días de entrega
@@ -286,9 +293,9 @@ globals:
buyRequest: Peticiones de compra
wasteBreakdown: Deglose de mermas
itemCreate: Nuevo artículo
- tax: 'IVA'
- botanical: 'Botánico'
- barcode: 'Código de barras'
+ tax: IVA
+ botanical: Botánico
+ barcode: Código de barras
itemTypeCreate: Nueva familia
family: Familia
lastEntries: Últimas entradas
@@ -332,10 +339,13 @@ globals:
wasteRecalc: Recalcular mermas
operator: Operario
parking: Parking
+ vehicleList: Vehículos
+ vehicle: Vehículo
unsavedPopup:
title: Los cambios que no haya guardado se perderán
subtitle: ¿Seguro que quiere salir sin guardar?
params:
+ description: Descripción
clientFk: Id cliente
salesPersonFk: Comercial
warehouseFk: Almacén
@@ -349,13 +359,14 @@ globals:
from: Desde
to: Hasta
supplierFk: Proveedor
- supplierRef: Ref. proveedor
+ supplierRef: Nº factura
serial: Serie
amount: Importe
awbCode: AWB
daysOnward: Días adelante
packing: ITP
countryFk: País
+ countryCodeFk: País
companyFk: Empresa
errors:
statusUnauthorized: Acceso denegado
@@ -393,6 +404,87 @@ cau:
subtitle: Al enviar este cau ya se envían todos los datos relacionados con el error, la sección, el usuario, etc
inputLabel: Explique el motivo por el que no deberia aparecer este fallo
askPrivileges: Solicitar permisos
+entry:
+ list:
+ newEntry: Nueva entrada
+ tableVisibleColumns:
+ isExcludedFromAvailable: Excluir del inventario
+ isOrdered: Pedida
+ isConfirmed: Lista para etiquetar
+ isReceived: Recibida
+ isRaid: Redada
+ 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
+ summary:
+ invoiceAmount: Importe
+ commission: Comisión
+ currency: Moneda
+ invoiceNumber: Núm. factura
+ ordered: Pedida
+ booked: Contabilizada
+ excludedFromAvailable: Inventario
+ travelReference: Referencia
+ travelAgency: Agencia
+ travelShipped: F. envio
+ travelWarehouseOut: Alm. salida
+ travelDelivered: Enviada
+ travelLanded: F. entrega
+ travelReceived: Recibida
+ buys: Compras
+ stickers: Etiquetas
+ package: Embalaje
+ packing: Pack.
+ grouping: Group.
+ buyingValue: Coste
+ import: Importe
+ pvp: PVP
+ basicData:
+ travel: Envío
+ currency: Moneda
+ observation: Observación
+ commission: Comisión
+ booked: Asentado
+ excludedFromAvailable: Inventario
+ buys:
+ observations: Observaciónes
+ packagingFk: Embalaje
+ color: Color
+ printedStickers: Etiquetas impresas
+ notes:
+ observationType: Tipo de observación
+ latestBuys:
+ tableVisibleColumns:
+ image: Foto
+ itemFk: Id Artículo
+ weightByPiece: Peso (gramos)/tallo
+ isActive: Activo
+ family: Familia
+ entryFk: Entrada
+ freightValue: Porte
+ comissionValue: Comisión
+ packageValue: Embalaje
+ isIgnored: Ignorado
+ price2: Grouping
+ price3: Packing
+ minPrice: Min
+ ektFk: Ekt
+ packingOut: Embalaje envíos
+ landing: Llegada
+ isExcludedFromAvailable: Excluir del inventario
+ isRaid: Redada
+ invoiceNumber: Nº Factura
+ reference: Ref/Alb/Guía
ticket:
params:
ticketFk: ID de ticket
@@ -406,6 +498,38 @@ ticket:
freightItemName: Nombre
packageItemName: Embalaje
longName: Descripción
+ pageTitles:
+ tickets: Tickets
+ list: Listado
+ ticketCreate: Nuevo ticket
+ summary: Resumen
+ basicData: Datos básicos
+ boxing: Encajado
+ sms: Sms
+ notes: Notas
+ sale: Lineas del pedido
+ dms: Gestión documental
+ negative: Tickets negativos
+ volume: Volumen
+ observation: Notas
+ ticketAdvance: Adelantar tickets
+ futureTickets: Tickets a futuro
+ expedition: Expedición
+ purchaseRequest: Petición de compra
+ weeklyTickets: Tickets programados
+ saleTracking: Líneas preparadas
+ services: Servicios
+ tracking: Estados
+ components: Componentes
+ pictures: Fotos
+ packages: Bultos
+ list:
+ nickname: Alias
+ state: Estado
+ shipped: Enviado
+ landed: Entregado
+ salesPerson: Comercial
+ total: Total
card:
customerId: ID cliente
customerCard: Ficha del cliente
@@ -452,15 +576,11 @@ ticket:
consigneeStreet: Dirección
create:
address: Dirección
-order:
- field:
- salesPersonFk: Comercial
- form:
- clientFk: Cliente
- addressFk: Dirección
- agencyModeFk: Agencia
- list:
- newOrder: Nuevo Pedido
+invoiceOut:
+ card:
+ issued: Fecha emisión
+ customerCard: Ficha del cliente
+ ticketList: Listado de tickets
summary:
issued: Fecha
dued: Fecha límite
@@ -471,6 +591,71 @@ order:
fee: Cuota
tickets: Tickets
totalWithVat: Importe
+ globalInvoices:
+ errors:
+ chooseValidClient: Selecciona un cliente válido
+ chooseValidCompany: Selecciona una empresa válida
+ chooseValidPrinter: Selecciona una impresora válida
+ chooseValidSerialType: Selecciona una tipo de serie válida
+ fillDates: La fecha de la factura y la fecha máxima deben estar completas
+ invoiceDateLessThanMaxDate: La fecha de la factura no puede ser menor que la fecha máxima
+ invoiceWithFutureDate: Existe una factura con una fecha futura
+ noTicketsToInvoice: No existen tickets para facturar
+ criticalInvoiceError: Error crítico en la facturación proceso detenido
+ invalidSerialTypeForAll: El tipo de serie debe ser global cuando se facturan todos los clientes
+ table:
+ addressId: Id dirección
+ streetAddress: Dirección fiscal
+ statusCard:
+ percentageText: '{getPercentage}% {getAddressNumber} de {getNAddresses}'
+ pdfsNumberText: '{nPdfs} de {totalPdfs} PDFs'
+ negativeBases:
+ clientId: Id cliente
+ base: Base
+ active: Activo
+ hasToInvoice: Facturar
+ verifiedData: Datos comprobados
+ comercial: Comercial
+ errors:
+ downloadCsvFailed: Error al descargar CSV
+order:
+ field:
+ salesPersonFk: Comercial
+ form:
+ clientFk: Cliente
+ addressFk: Dirección
+ agencyModeFk: Agencia
+ list:
+ newOrder: Nuevo Pedido
+ summary:
+ basket: Cesta
+ notConfirmed: No confirmada
+ created: Creado
+ createdFrom: Creado desde
+ address: Dirección
+ total: Total
+ vat: IVA
+ state: Estado
+ alias: Alias
+ items: Artículos
+ orderTicketList: Tickets del pedido
+ amount: Monto
+ confirm: Confirmar
+ confirmLines: Confirmar lineas
+shelving:
+ list:
+ parking: Parking
+ priority: Prioridad
+ newShelving: Nuevo Carro
+ summary:
+ recyclable: Reciclable
+parking:
+ pickingOrder: Orden de recogida
+ row: Fila
+ column: Columna
+ searchBar:
+ info: Puedes buscar por código de parking
+ label: Buscar parking...
department:
chat: Chat
bossDepartment: Jefe de departamento
@@ -631,8 +816,8 @@ wagon:
volumeNotEmpty: El volumen no puede estar vacío
typeNotEmpty: El tipo no puede estar vacío
maxTrays: Has alcanzado el número máximo de bandejas
- minHeightBetweenTrays: 'La distancia mínima entre bandejas es '
- maxWagonHeight: 'La altura máxima del vagón es '
+ minHeightBetweenTrays: La distancia mínima entre bandejas es
+ maxWagonHeight: La altura máxima del vagón es
uncompleteTrays: Hay bandejas sin completar
params:
label: Etiqueta
@@ -640,6 +825,8 @@ wagon:
volume: Volumen
name: Nombre
supplier:
+ search: Buscar proveedor
+ searchInfo: Buscar proveedor por id o nombre
list:
payMethod: Método de pago
account: Cuenta
@@ -730,6 +917,8 @@ travel:
deleteTravel: Eliminar envío
AddEntry: Añadir entrada
thermographs: Termógrafos
+ availabled: F. Disponible
+ availabledHour: Hora Disponible
hb: HB
basicData:
daysInForward: Desplazamiento automatico (redada)
@@ -778,7 +967,7 @@ components:
cardDescriptor:
mainList: Listado principal
summary: Resumen
- moreOptions: 'Más opciones'
+ moreOptions: Más opciones
leftMenu:
addToPinned: Añadir a fijados
removeFromPinned: Eliminar de fijados
diff --git a/src/layouts/MainLayout.vue b/src/layouts/MainLayout.vue
index 2a84e5aa1..3ad1c79bc 100644
--- a/src/layouts/MainLayout.vue
+++ b/src/layouts/MainLayout.vue
@@ -2,7 +2,7 @@
import Navbar from 'src/components/NavBar.vue';
-
+
diff --git a/src/layouts/OutLayout.vue b/src/layouts/OutLayout.vue
index 4ccc6bf9e..eba57c198 100644
--- a/src/layouts/OutLayout.vue
+++ b/src/layouts/OutLayout.vue
@@ -1,12 +1,12 @@
diff --git a/src/pages/Account/AccountAliasList.vue b/src/pages/Account/AccountAliasList.vue
index f6016fb6c..19682286c 100644
--- a/src/pages/Account/AccountAliasList.vue
+++ b/src/pages/Account/AccountAliasList.vue
@@ -3,6 +3,7 @@ import { useI18n } from 'vue-i18n';
import { ref, computed } from 'vue';
import VnTable from 'components/VnTable/VnTable.vue';
import VnSection from 'src/components/common/VnSection.vue';
+import exprBuilder from './Alias/AliasExprBuilder';
const tableRef = ref();
const { t } = useI18n();
@@ -31,15 +32,6 @@ const columns = computed(() => [
create: true,
},
]);
-
-const exprBuilder = (param, value) => {
- switch (param) {
- case 'search':
- return /^\d+$/.test(value)
- ? { id: value }
- : { alias: { like: `%${value}%` } };
- }
-};
diff --git a/src/pages/Account/AccountExprBuilder.js b/src/pages/Account/AccountExprBuilder.js
new file mode 100644
index 000000000..6497a9d30
--- /dev/null
+++ b/src/pages/Account/AccountExprBuilder.js
@@ -0,0 +1,18 @@
+export default (param, value) => {
+ switch (param) {
+ case 'search':
+ return /^\d+$/.test(value)
+ ? { id: value }
+ : {
+ or: [
+ { name: { like: `%${value}%` } },
+ { nickname: { like: `%${value}%` } },
+ ],
+ };
+ case 'name':
+ case 'nickname':
+ return { [param]: { like: `%${value}%` } };
+ case 'roleFk':
+ return { [param]: value };
+ }
+};
diff --git a/src/pages/Account/AccountList.vue b/src/pages/Account/AccountList.vue
index ea8daba0d..976af1d19 100644
--- a/src/pages/Account/AccountList.vue
+++ b/src/pages/Account/AccountList.vue
@@ -4,15 +4,16 @@ import { computed, ref } from 'vue';
import VnTable from 'components/VnTable/VnTable.vue';
import AccountSummary from './Card/AccountSummary.vue';
import { useSummaryDialog } from 'src/composables/useSummaryDialog';
+import exprBuilder from './AccountExprBuilder.js';
+import filter from './Card/AccountFilter.js';
import VnSection from 'src/components/common/VnSection.vue';
import FetchData from 'src/components/FetchData.vue';
import VnInputPassword from 'src/components/common/VnInputPassword.vue';
const { t } = useI18n();
const { viewSummary } = useSummaryDialog();
-const filter = {
- include: { relation: 'role', scope: { fields: ['id', 'name'] } },
-};
+const tableRef = ref();
+
const dataKey = 'AccountList';
const roles = ref([]);
const columns = computed(() => [
@@ -117,25 +118,6 @@ const columns = computed(() => [
],
},
]);
-
-function exprBuilder(param, value) {
- switch (param) {
- case 'search':
- return /^\d+$/.test(value)
- ? { id: value }
- : {
- or: [
- { name: { like: `%${value}%` } },
- { nickname: { like: `%${value}%` } },
- ],
- };
- case 'name':
- case 'nickname':
- return { [param]: { like: `%${value}%` } };
- case 'roleFk':
- return { [param]: value };
- }
-}
(roles = data)" auto-load />
diff --git a/src/pages/Account/Alias/AliasExprBuilder.js b/src/pages/Account/Alias/AliasExprBuilder.js
new file mode 100644
index 000000000..f7a5a104c
--- /dev/null
+++ b/src/pages/Account/Alias/AliasExprBuilder.js
@@ -0,0 +1,8 @@
+export default (param, value) => {
+ switch (param) {
+ case 'search':
+ return /^\d+$/.test(value)
+ ? { id: value }
+ : { alias: { like: `%${value}%` } };
+ }
+};
diff --git a/src/pages/Account/Alias/Card/AliasCard.vue b/src/pages/Account/Alias/Card/AliasCard.vue
index 3a814edc0..f37bd7d0f 100644
--- a/src/pages/Account/Alias/Card/AliasCard.vue
+++ b/src/pages/Account/Alias/Card/AliasCard.vue
@@ -1,21 +1,13 @@
diff --git a/src/pages/Account/Alias/Card/AliasDescriptor.vue b/src/pages/Account/Alias/Card/AliasDescriptor.vue
index 2e01fad01..671ef7fbc 100644
--- a/src/pages/Account/Alias/Card/AliasDescriptor.vue
+++ b/src/pages/Account/Alias/Card/AliasDescriptor.vue
@@ -7,7 +7,6 @@ import { useQuasar } from 'quasar';
import CardDescriptor from 'components/ui/CardDescriptor.vue';
import VnLv from 'src/components/ui/VnLv.vue';
-import useCardDescription from 'src/composables/useCardDescription';
import axios from 'axios';
import useNotify from 'src/composables/useNotify.js';
@@ -29,9 +28,6 @@ const entityId = computed(() => {
return $props.id || route.params.id;
});
-const data = ref(useCardDescription());
-const setData = (entity) => (data.value = useCardDescription(entity.alias, entity.id));
-
const removeAlias = () => {
quasar
.dialog({
@@ -55,11 +51,8 @@ const removeAlias = () => {
diff --git a/src/pages/Account/Alias/Card/AliasSummary.vue b/src/pages/Account/Alias/Card/AliasSummary.vue
index 1f76fe7c2..b4b9abd25 100644
--- a/src/pages/Account/Alias/Card/AliasSummary.vue
+++ b/src/pages/Account/Alias/Card/AliasSummary.vue
@@ -1,13 +1,11 @@
- (alias = data)"
- data-key="MailAliasesSummary"
- >
- {{ alias.id }} - {{ alias.alias }}
-
+
+
+ {{ alias.id }} - {{ alias.alias }}
+
+
-import { useRoute } from 'vue-router';
-import { useI18n } from 'vue-i18n';
import VnSelect from 'src/components/common/VnSelect.vue';
import VnSelectEnum from 'src/components/common/VnSelectEnum.vue';
import FormModel from 'components/FormModel.vue';
import VnInput from 'src/components/common/VnInput.vue';
-import { ref, watch } from 'vue';
-
-const route = useRoute();
-const { t } = useI18n();
-const formModelRef = ref(null);
-
-const accountFilter = {
- where: { id: route.params.id },
- fields: ['id', 'email', 'nickname', 'name', 'accountStateFk', 'packages', 'pickup'],
- include: [],
-};
-
-watch(
- () => route.params.id,
- () => formModelRef.value.reset()
-);
-
+
-
-
-
+
+
+
@@ -49,7 +23,7 @@ watch(
table="user"
column="twoFactor"
v-model="data.twoFactor"
- :label="t('account.card.twoFactor')"
+ :label="$t('account.card.twoFactor')"
option-value="code"
option-label="code"
/>
diff --git a/src/pages/Account/Card/AccountCard.vue b/src/pages/Account/Card/AccountCard.vue
index 35ff7e732..a5037e301 100644
--- a/src/pages/Account/Card/AccountCard.vue
+++ b/src/pages/Account/Card/AccountCard.vue
@@ -1,8 +1,14 @@
-
-
+
diff --git a/src/pages/Account/Card/AccountDescriptor.vue b/src/pages/Account/Card/AccountDescriptor.vue
index 4e5328de6..49328fe87 100644
--- a/src/pages/Account/Card/AccountDescriptor.vue
+++ b/src/pages/Account/Card/AccountDescriptor.vue
@@ -1,36 +1,18 @@
(account = data)"
>
- {{ account.id }} - {{ account.nickname }}
-
+ {{ entity.id }} - {{ entity.nickname }}
+
-
+
-
-
+
+
diff --git a/src/pages/Account/Role/AccountRoles.vue b/src/pages/Account/Role/AccountRoles.vue
index 3c3d6b243..02f5400c6 100644
--- a/src/pages/Account/Role/AccountRoles.vue
+++ b/src/pages/Account/Role/AccountRoles.vue
@@ -5,6 +5,7 @@ import VnTable from 'components/VnTable/VnTable.vue';
import { useRoute } from 'vue-router';
import { useSummaryDialog } from 'src/composables/useSummaryDialog';
import RoleSummary from './Card/RoleSummary.vue';
+import exprBuilder from './RoleExprBuilder.js';
import VnSection from 'src/components/common/VnSection.vue';
const route = useRoute();
@@ -66,24 +67,7 @@ const columns = computed(() => [
],
},
]);
-const exprBuilder = (param, value) => {
- switch (param) {
- case 'search':
- return /^\d+$/.test(value)
- ? { id: value }
- : {
- or: [
- { name: { like: `%${value}%` } },
- { nickname: { like: `%${value}%` } },
- ],
- };
- case 'name':
- case 'description':
- return { [param]: { like: `%${value}%` } };
- }
-};
-
-import { useRoute } from 'vue-router';
-import { useI18n } from 'vue-i18n';
import FormModel from 'components/FormModel.vue';
import VnRow from 'components/ui/VnRow.vue';
import VnInput from 'src/components/common/VnInput.vue';
-const route = useRoute();
-const { t } = useI18n();
-
+
-
-
-
+
-
-
-
+
diff --git a/src/pages/Account/Role/Card/RoleCard.vue b/src/pages/Account/Role/Card/RoleCard.vue
index 7664deca8..ef5b9db04 100644
--- a/src/pages/Account/Role/Card/RoleCard.vue
+++ b/src/pages/Account/Role/Card/RoleCard.vue
@@ -3,5 +3,10 @@ import VnCardBeta from 'components/common/VnCardBeta.vue';
import RoleDescriptor from './RoleDescriptor.vue';
-
+
diff --git a/src/pages/Account/Role/Card/RoleDescriptor.vue b/src/pages/Account/Role/Card/RoleDescriptor.vue
index 0a555346d..517517af0 100644
--- a/src/pages/Account/Role/Card/RoleDescriptor.vue
+++ b/src/pages/Account/Role/Card/RoleDescriptor.vue
@@ -1,10 +1,9 @@
(role = data)"
+ url="VnRoles"
+ :filter="{ where: { id: entityId } }"
data-key="Role"
>
- {{ role.id }} - {{ role.name }}
-
+ {{ entity.id }} - {{ entity.name }}
+
-
-
-
+
+
+
diff --git a/src/pages/Account/Role/Card/SubRoles.vue b/src/pages/Account/Role/Card/SubRoles.vue
index 0077f12b0..99cf5e8f0 100644
--- a/src/pages/Account/Role/Card/SubRoles.vue
+++ b/src/pages/Account/Role/Card/SubRoles.vue
@@ -63,7 +63,7 @@ watch(
store.url = urlPath.value;
store.filter = filter.value;
fetchSubRoles();
- }
+ },
);
const fetchSubRoles = () => paginateRef.value.fetch();
@@ -109,7 +109,7 @@ const redirectToRoleSummary = (id) =>
openConfirmationModal(
t('El rol va a ser eliminado'),
t('¿Seguro que quieres continuar?'),
- () => deleteSubRole(row, rows, rowIndex)
+ () => deleteSubRole(row, rows, rowIndex),
)
"
>
@@ -131,7 +131,7 @@ const redirectToRoleSummary = (id) =>
diff --git a/src/pages/Account/Role/RoleExprBuilder.js b/src/pages/Account/Role/RoleExprBuilder.js
new file mode 100644
index 000000000..cc4fab399
--- /dev/null
+++ b/src/pages/Account/Role/RoleExprBuilder.js
@@ -0,0 +1,16 @@
+export default (param, value) => {
+ switch (param) {
+ case 'search':
+ return /^\d+$/.test(value)
+ ? { id: value }
+ : {
+ or: [
+ { name: { like: `%${value}%` } },
+ { nickname: { like: `%${value}%` } },
+ ],
+ };
+ case 'name':
+ case 'description':
+ return { [param]: { like: `%${value}%` } };
+ }
+};
diff --git a/src/pages/Claim/Card/ClaimBasicData.vue b/src/pages/Claim/Card/ClaimBasicData.vue
index 63b0b7c0d..67034da1a 100644
--- a/src/pages/Claim/Card/ClaimBasicData.vue
+++ b/src/pages/Claim/Card/ClaimBasicData.vue
@@ -28,7 +28,6 @@ const workersOptions = ref([]);
model="Claim"
:url-update="`Claims/updateClaim/${route.params.id}`"
auto-load
- :reload="true"
>
diff --git a/src/pages/Claim/Card/ClaimCard.vue b/src/pages/Claim/Card/ClaimCard.vue
index e1e000815..05f3b53a8 100644
--- a/src/pages/Claim/Card/ClaimCard.vue
+++ b/src/pages/Claim/Card/ClaimCard.vue
@@ -4,10 +4,11 @@ import ClaimDescriptor from './ClaimDescriptor.vue';
import filter from './ClaimFilter.js';
-
diff --git a/src/pages/Claim/Card/ClaimDescriptor.vue b/src/pages/Claim/Card/ClaimDescriptor.vue
index 02b63dd8e..4551c58fe 100644
--- a/src/pages/Claim/Card/ClaimDescriptor.vue
+++ b/src/pages/Claim/Card/ClaimDescriptor.vue
@@ -3,12 +3,10 @@ import { ref, computed, onMounted } from 'vue';
import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n';
import { toDateHourMinSec, toPercentage } from 'src/filters';
-import { useState } from 'src/composables/useState';
import TicketDescriptorProxy from 'pages/Ticket/Card/TicketDescriptorProxy.vue';
import ClaimDescriptorMenu from 'pages/Claim/Card/ClaimDescriptorMenu.vue';
import CardDescriptor from 'components/ui/CardDescriptor.vue';
import VnLv from 'src/components/ui/VnLv.vue';
-import useCardDescription from 'src/composables/useCardDescription';
import VnUserLink from 'src/components/ui/VnUserLink.vue';
import { getUrl } from 'src/composables/getUrl';
import ZoneDescriptorProxy from 'src/pages/Zone/Card/ZoneDescriptorProxy.vue';
@@ -23,7 +21,6 @@ const $props = defineProps({
});
const route = useRoute();
-const state = useState();
const { t } = useI18n();
const salixUrl = ref();
const entityId = computed(() => {
@@ -39,12 +36,7 @@ const STATE_COLOR = {
function stateColor(code) {
return STATE_COLOR[code];
}
-const data = ref(useCardDescription());
-const setData = (entity) => {
- if (!entity) return;
- data.value = useCardDescription(entity?.client?.name, entity.id);
- state.set('ClaimDescriptor', entity);
-};
+
onMounted(async () => {
salixUrl.value = await getUrl('');
});
@@ -54,9 +46,7 @@ onMounted(async () => {
@@ -95,7 +85,7 @@ onMounted(async () => {
/>
-
+
{{ entity.ticket?.zone?.name }}
@@ -107,11 +97,10 @@ onMounted(async () => {
:label="t('claim.province')"
:value="entity.ticket?.address?.province?.name"
/>
-
+
{{ entity.ticketFk }}
-
diff --git a/src/pages/Claim/Card/ClaimLines.vue b/src/pages/Claim/Card/ClaimLines.vue
index 33fadd020..dee03b95d 100644
--- a/src/pages/Claim/Card/ClaimLines.vue
+++ b/src/pages/Claim/Card/ClaimLines.vue
@@ -317,7 +317,13 @@ async function saveWhenHasChanges() {
-
+
diff --git a/src/pages/Claim/Card/ClaimNotes.vue b/src/pages/Claim/Card/ClaimNotes.vue
index 134ee33ab..cc6e33779 100644
--- a/src/pages/Claim/Card/ClaimNotes.vue
+++ b/src/pages/Claim/Card/ClaimNotes.vue
@@ -1,5 +1,5 @@
-
+
diff --git a/src/pages/Customer/Card/CustomerConsumption.vue b/src/pages/Customer/Card/CustomerConsumption.vue
index f0d8dea47..f3949bb32 100644
--- a/src/pages/Customer/Card/CustomerConsumption.vue
+++ b/src/pages/Customer/Card/CustomerConsumption.vue
@@ -61,6 +61,23 @@ const columns = computed(() => [
columnFilter: false,
cardVisible: true,
},
+ {
+ align: 'left',
+ name: 'buyerId',
+ label: t('customer.params.buyerId'),
+ component: 'select',
+ attrs: {
+ url: 'TicketRequests/getItemTypeWorker',
+ optionLabel: 'nickname',
+ optionValue: 'id',
+
+ fields: ['id', 'nickname'],
+ sortBy: ['nickname ASC'],
+ optionFilter: 'firstName',
+ },
+ cardVisible: false,
+ visible: false,
+ },
{
name: 'description',
align: 'left',
@@ -74,6 +91,7 @@ const columns = computed(() => [
name: 'quantity',
label: t('globals.quantity'),
cardVisible: true,
+ visible: true,
columnFilter: {
inWhere: true,
},
@@ -119,7 +137,7 @@ const openSendEmailDialog = async () => {
openConfirmationModal(
t('The consumption report will be sent'),
t('Please, confirm'),
- () => sendCampaignMetricsEmail({ address: arrayData.store.data.email })
+ () => sendCampaignMetricsEmail({ address: arrayData.store.data.email }),
);
};
const sendCampaignMetricsEmail = ({ address }) => {
@@ -138,11 +156,11 @@ const updateDateParams = (value, params) => {
const campaign = campaignList.value.find((c) => c.id === value);
if (!campaign) return;
- const { dated, previousDays, scopeDays } = campaign;
- const _date = new Date(dated);
- const [from, to] = dateRange(_date);
- params.from = new Date(from.setDate(from.getDate() - previousDays)).toISOString();
- params.to = new Date(to.setDate(to.getDate() + scopeDays)).toISOString();
+ const { dated, scopeDays } = campaign;
+ const from = new Date(dated);
+ from.setDate(from.getDate() - scopeDays);
+ params.from = from;
+ params.to = dated;
return params;
};
@@ -152,7 +170,7 @@ const updateDateParams = (value, params) => {
v-if="campaignList"
data-key="CustomerConsumption"
url="Clients/consumption"
- :order="['itemTypeFk', 'itemName', 'itemSize', 'description']"
+ :order="['itemTypeFk', 'itemName', 'itemSize', 'description']"
:filter="{ where: { clientFk: route.params.id } }"
:columns="columns"
search-url="consumption"
@@ -200,29 +218,60 @@ const updateDateParams = (value, params) => {
{{ row.subName }}
-
+
+
+
+
+
+ {{ scope.opt?.name }}
+ {{
+ scope.opt?.category?.name
+ }}
+
+
+
+
+
updateDateParams(data, params)"
+ dense
>
-
- {{ scope.opt?.code }}
- {{
- new Date(scope.opt?.dated).getFullYear()
- }}
+ {{ t(scope.opt?.code) }}
+
+ {{ new Date(scope.opt?.dated).getFullYear() }}
+
@@ -247,7 +296,21 @@ const updateDateParams = (value, params) => {
+en:
+
+ valentinesDay: Valentine's Day
+ mothersDay: Mother's Day
+ allSaints: All Saints' Day
+ frenchMothersDay: Mother's Day in France
es:
Enter a new search: Introduce una nueva búsqueda
Group by items: Agrupar por artículos
+ valentinesDay: Día de San Valentín
+ mothersDay: Día de la Madre
+ allSaints: Día de Todos los Santos
+ frenchMothersDay: (Francia) Día de la Madre
+ Campaign consumption: Consumo campaña
+ Campaign: Campaña
+ From: Desde
+ To: Hasta
diff --git a/src/pages/Customer/Card/CustomerContacts.vue b/src/pages/Customer/Card/CustomerContacts.vue
index c420f650e..d03f71244 100644
--- a/src/pages/Customer/Card/CustomerContacts.vue
+++ b/src/pages/Customer/Card/CustomerContacts.vue
@@ -62,7 +62,7 @@ const customerContactsRef = ref(null);
color="primary"
flat
icon="add"
- shortcut="+"
+ v-shortcut="'+'"
>
{{ t('Add contact') }}
diff --git a/src/pages/Customer/Card/CustomerCreditContracts.vue b/src/pages/Customer/Card/CustomerCreditContracts.vue
index 7dc53db72..a49faeb8d 100644
--- a/src/pages/Customer/Card/CustomerCreditContracts.vue
+++ b/src/pages/Customer/Card/CustomerCreditContracts.vue
@@ -195,7 +195,7 @@ const updateData = () => {
color="primary"
fab
icon="add"
- shortcut="+"
+ v-shortcut="'+'"
/>
{{ t('New contract') }}
diff --git a/src/pages/Customer/Card/CustomerDescriptor.vue b/src/pages/Customer/Card/CustomerDescriptor.vue
index d7a8a59a1..89f9d9449 100644
--- a/src/pages/Customer/Card/CustomerDescriptor.vue
+++ b/src/pages/Customer/Card/CustomerDescriptor.vue
@@ -1,5 +1,5 @@
@@ -69,6 +79,13 @@ const openCreateForm = (type) => {
{{ t('globals.pageTitles.createTicket') }}
+
+ {{
+ $props.customer.substitutionAllowed
+ ? t('Disable substitution')
+ : t('Allow substitution')
+ }}
+
{{ t('Send SMS') }}
diff --git a/src/pages/Customer/Card/CustomerFileManagement.vue b/src/pages/Customer/Card/CustomerFileManagement.vue
index 134d8dbd6..b565db6e7 100644
--- a/src/pages/Customer/Card/CustomerFileManagement.vue
+++ b/src/pages/Customer/Card/CustomerFileManagement.vue
@@ -236,7 +236,7 @@ const toCustomerFileManagementCreate = () => {
@click.stop="toCustomerFileManagementCreate()"
color="primary"
fab
- shortcut="+"
+ v-shortcut="'+'"
icon="add"
/>
diff --git a/src/pages/Customer/Card/CustomerFiscalData.vue b/src/pages/Customer/Card/CustomerFiscalData.vue
index ceeb70bb6..93909eb9c 100644
--- a/src/pages/Customer/Card/CustomerFiscalData.vue
+++ b/src/pages/Customer/Card/CustomerFiscalData.vue
@@ -12,6 +12,7 @@ import VnRow from 'components/ui/VnRow.vue';
import VnInput from 'src/components/common/VnInput.vue';
import VnSelect from 'src/components/common/VnSelect.vue';
import VnLocation from 'src/components/common/VnLocation.vue';
+import VnCheckbox from 'src/components/common/VnCheckbox.vue';
import { getDifferences, getUpdatedValues } from 'src/filters';
import VnConfirm from 'src/components/ui/VnConfirm.vue';
@@ -73,7 +74,7 @@ async function acceptPropagate({ isEqualizated }) {
-
-
-
-
- {{ t('whenActivatingIt') }}
-
-
-
+
@@ -170,17 +168,11 @@ async function acceptPropagate({ isEqualizated }) {
-
-
-
-
- {{ t('inOrderToInvoice') }}
-
-
-
+
diff --git a/src/pages/Customer/Card/CustomerNotes.vue b/src/pages/Customer/Card/CustomerNotes.vue
index b85174696..189b59904 100644
--- a/src/pages/Customer/Card/CustomerNotes.vue
+++ b/src/pages/Customer/Card/CustomerNotes.vue
@@ -23,5 +23,6 @@ const noteFilter = computed(() => {
:body="{ clientFk: route.params.id }"
style="overflow-y: auto"
:select-type="true"
+ required
/>
diff --git a/src/pages/Customer/Card/CustomerSamples.vue b/src/pages/Customer/Card/CustomerSamples.vue
index f12691112..19a7f8759 100644
--- a/src/pages/Customer/Card/CustomerSamples.vue
+++ b/src/pages/Customer/Card/CustomerSamples.vue
@@ -104,7 +104,7 @@ const tableRef = ref();
color="primary"
fab
icon="add"
- shortcut="+"
+ v-shortcut="'+'"
/>
{{ t('Send sample') }}
diff --git a/src/pages/Customer/Card/CustomerWebAccess.vue b/src/pages/Customer/Card/CustomerWebAccess.vue
index 3c4106846..809f10918 100644
--- a/src/pages/Customer/Card/CustomerWebAccess.vue
+++ b/src/pages/Customer/Card/CustomerWebAccess.vue
@@ -27,7 +27,7 @@ async function hasCustomerRole() {
-
+
diff --git a/src/pages/Customer/CustomerList.vue b/src/pages/Customer/CustomerList.vue
index 3c638b612..b8c1a743e 100644
--- a/src/pages/Customer/CustomerList.vue
+++ b/src/pages/Customer/CustomerList.vue
@@ -264,6 +264,7 @@ const columns = computed(() => [
align: 'left',
name: 'isActive',
label: t('customer.summary.isActive'),
+ component: 'checkbox',
chip: {
color: null,
condition: (value) => !value,
@@ -302,6 +303,7 @@ const columns = computed(() => [
align: 'left',
name: 'isFreezed',
label: t('customer.extendedList.tableVisibleColumns.isFreezed'),
+ component: 'checkbox',
chip: {
color: null,
condition: (value) => value,
@@ -419,7 +421,7 @@ function handleLocation(data, location) {
handleLocation(data, location)"
>
@@ -336,7 +336,7 @@ function handleLocation(data, location) {
class="cursor-pointer add-icon q-mt-md"
flat
icon="add"
- shortcut="+"
+ v-shortcut="'+'"
>
{{ t('Add note') }}
diff --git a/src/pages/Customer/components/CustomerNewPayment.vue b/src/pages/Customer/components/CustomerNewPayment.vue
index c2c38b55a..7f45cd7db 100644
--- a/src/pages/Customer/components/CustomerNewPayment.vue
+++ b/src/pages/Customer/components/CustomerNewPayment.vue
@@ -84,7 +84,7 @@ function setPaymentType(accounting) {
viewReceipt.value = isCash.value;
if (accountingType.value.daysInFuture)
initialData.payed.setDate(
- initialData.payed.getDate() + accountingType.value.daysInFuture
+ initialData.payed.getDate() + accountingType.value.daysInFuture,
);
maxAmount.value = accountingType.value && accountingType.value.maxAmount;
diff --git a/src/pages/Customer/components/CustomerSamplesCreate.vue b/src/pages/Customer/components/CustomerSamplesCreate.vue
index 754693672..8d241441d 100644
--- a/src/pages/Customer/components/CustomerSamplesCreate.vue
+++ b/src/pages/Customer/components/CustomerSamplesCreate.vue
@@ -39,7 +39,7 @@ const optionsSamplesVisible = ref([]);
const sampleType = ref({ hasPreview: false });
const initialData = reactive({});
const entityId = computed(() => route.params.id);
-const customer = computed(() => state.get('customer'));
+const customer = computed(() => state.get('Customer'));
const filterEmailUsers = { where: { userFk: user.value.id } };
const filterClientsAddresses = {
include: [
diff --git a/src/pages/Customer/locale/en.yml b/src/pages/Customer/locale/en.yml
index 118f04a31..b6d495335 100644
--- a/src/pages/Customer/locale/en.yml
+++ b/src/pages/Customer/locale/en.yml
@@ -107,6 +107,9 @@ customer:
defaulterSinced: Defaulted Since
hasRecovery: Has Recovery
socialName: Social name
+ typeId: Type
+ buyerId: Buyer
+ categoryId: Category
city: City
phone: Phone
postcode: Postcode
diff --git a/src/pages/Customer/locale/es.yml b/src/pages/Customer/locale/es.yml
index 7c33ffee8..f50d049da 100644
--- a/src/pages/Customer/locale/es.yml
+++ b/src/pages/Customer/locale/es.yml
@@ -108,6 +108,9 @@ customer:
hasRecovery: Tiene recobro
socialName: Razón social
campaign: Campaña
+ typeId: Familia
+ buyerId: Comprador
+ categoryId: Reino
city: Ciudad
phone: Teléfono
postcode: Código postal
diff --git a/src/pages/Entry/Card/EntryBasicData.vue b/src/pages/Entry/Card/EntryBasicData.vue
index 689eea686..6462ed24a 100644
--- a/src/pages/Entry/Card/EntryBasicData.vue
+++ b/src/pages/Entry/Card/EntryBasicData.vue
@@ -1,30 +1,32 @@
@@ -52,46 +54,24 @@ const onFilterTravelSelected = (formData, id) => {
>
+
-
-
-
-
-
-
-
-
- {{ scope.opt?.agencyModeName }} -
- {{ scope.opt?.warehouseInName }}
- ({{ toDate(scope.opt?.shipped) }}) →
- {{ scope.opt?.warehouseOutName }}
- ({{ toDate(scope.opt?.landed) }})
-
-
-
-
-
+
{
{
:label="t('entry.summary.excludedFromAvailable')"
/>
diff --git a/src/pages/Entry/Card/EntryBuys.vue b/src/pages/Entry/Card/EntryBuys.vue
index 6194ce5b8..f3b73cb04 100644
--- a/src/pages/Entry/Card/EntryBuys.vue
+++ b/src/pages/Entry/Card/EntryBuys.vue
@@ -1,478 +1,800 @@
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
-
-
-
-
-
-
+
+
+
-
-
-
-
- {{ col.value }}
-
-
-
-
-
-
-
-
- {{ props.row.item.itemType.code }}
-
-
- {{ props.row.item.size }}
-
-
- {{ toCurrency(props.row.item.minPrice) }}
-
-
- {{ props.row.item.concept }}
-
- {{ props.row.item.subName }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {{ col.label + ': ' + col.value }}
-
-
-
-
-
-
-
-
+ -
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (footer = data[0])"
+ auto-load
+ />
+ footerFetchDataRef.fetch()"
+ :table="
+ editableMode
+ ? {
+ 'row-key': 'id',
+ selection: 'multiple',
+ }
+ : {}
+ "
+ :create="
+ editableMode
+ ? {
+ urlCreate: 'Buys',
+ title: t('Create buy'),
+ onDataSaved: () => {
+ entryBuysRef.reload();
+ },
+ formInitialData: { entryFk: entityId, isIgnored: false },
+ showSaveAndContinueBtn: true,
+ }
+ : null
+ "
+ :create-complement="{
+ isFullWidth: true,
+ containerStyle: {
+ display: 'flex',
+ 'flex-wrap': 'wrap',
+ gap: '16px',
+ position: 'relative',
+ height: '450px',
+ },
+ columnGridStyle: {
+ 'max-width': '50%',
+ flex: 1,
+ 'margin-right': '30px',
+ },
+ }"
+ :is-editable="editableMode"
+ :without-header="!editableMode"
+ :with-filters="editableMode"
+ :right-search="false"
+ :right-search-icon="false"
+ :row-click="false"
+ :columns="columns"
+ :beforeSaveFn="beforeSave"
+ class="buyList"
+ :table-height="$props.tableHeight ?? '84vh'"
+ auto-load
+ footer
+ data-cy="entry-buys"
+ >
+
+
-
-
-
-
-
- {{ t('Import buys') }}
-
-
+
+
+ {{ row?.name }}
+
+
+
+
+
+
+
+
+
+ {{ row.printedStickers }}
+
+ /{{ row.stickers }}
+
+
+
+
+
+ {{ footer?.printedStickers }}
+ /
+ {{ footer?.stickers }}
+
+
+
+ {{ footer?.weight }}
+
+
+
+ {{ footer?.quantity }}
+
+
+
+
+ {{ footer?.amount }}
+
+
+
+ {
+ await setBuyUltimate(value, data);
+ }
+ "
+ :required="true"
+ data-cy="itemFk-create-popup"
+ sort-by="nickname DESC"
+ >
+
+
+
+
+ {{ scope.opt.name }}
+
+
+ #{{ scope.opt.id }}, {{ scope.opt?.size }},
+ {{ scope.opt?.producerName }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ t('globals.noData') }}
+
+
+
+
-
-
-
es:
- Import buys: Importar compras
- Buy deleted: Compra eliminada
- Buys deleted: Compras eliminadas
- Confirm deletion: Confirmar eliminación
- Are you sure you want to delete this buy?: Seguro que quieres eliminar esta compra?
- Are you sure you want to delete this buys?: Seguro que quieres eliminar estas compras?
+ Article: Artículo
+ Siz.: Med.
+ Size: Medida
+ Sti.: Eti.
+ Bucket: Cubo
+ Quantity: Cantidad
+ Amount: Importe
+ Pack.: Paq.
+ Package: Paquete
+ Box: Caja
+ P.Sen: P.Env
+ Packing sent: Packing envíos
+ Com.: Ref.
+ Comment: Referencia
+ Minimum price: Precio mínimo
+ Stickers: Etiquetas
+ Printed Stickers/Stickers: Etiquetas impresas/Etiquetas
+ Cost: Cost.
+ Buying value: Coste
+ Producer: Productor
+ Company: Compañia
+ Tags: Etiquetas
+ Grouping mode: Modo de agrupación
+ C.min: P.min
+ Ignore: Ignorar
+ Ignored for available: Ignorado para disponible
+ Grouping selector: Selector de grouping
+ Check min price: Marcar precio mínimo
+ Create buy: Crear compra
+ Invert quantity value: Invertir valor de cantidad
+ Check buy amount: Marcar como correcta la cantidad de compra
+
diff --git a/src/pages/Entry/Card/EntryCard.vue b/src/pages/Entry/Card/EntryCard.vue
index e00623a21..be82289f4 100644
--- a/src/pages/Entry/Card/EntryCard.vue
+++ b/src/pages/Entry/Card/EntryCard.vue
@@ -1,13 +1,13 @@
diff --git a/src/pages/Entry/Card/EntryDescriptor.vue b/src/pages/Entry/Card/EntryDescriptor.vue
index 19d13e51a..69b300cb2 100644
--- a/src/pages/Entry/Card/EntryDescriptor.vue
+++ b/src/pages/Entry/Card/EntryDescriptor.vue
@@ -1,12 +1,19 @@
{
width="lg-width"
>
-
+
+ {{ t('Show entry report') }}
+
+
+ {{ t('Recalculate rates') }}
+
+
+ {{ t('Clone') }}
+
+
+ {{ t('Delete') }}
+
-
-
-
+
+
+
+ {{ entity.travel?.agency?.name }}
+ {{ entity.travel?.warehouseOut?.code }} →
+ {{ entity.travel?.warehouseIn?.code }}
+
+
+
+
+
+
+
+
@@ -131,6 +230,14 @@ const getEntryRedirectionFilter = (entry) => {
}}
+
+ {{ t('This entry is deleted') }}
+
@@ -143,21 +250,6 @@ const getEntryRedirectionFilter = (entry) => {
>
{{ t('Supplier card') }}
-
- {{ t('All travels with current agency') }}
-
diff --git a/src/pages/Entry/Card/EntrySummary.vue b/src/pages/Entry/Card/EntrySummary.vue
index 8c46fb6e6..c40e2ba46 100644
--- a/src/pages/Entry/Card/EntrySummary.vue
+++ b/src/pages/Entry/Card/EntrySummary.vue
@@ -2,19 +2,17 @@
import { onMounted, ref, computed } from 'vue';
import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n';
+import { toDate } from 'src/filters';
+import { getUrl } from 'src/composables/getUrl';
+import axios from 'axios';
import CardSummary from 'components/ui/CardSummary.vue';
import VnLv from 'src/components/ui/VnLv.vue';
import TravelDescriptorProxy from 'src/pages/Travel/Card/TravelDescriptorProxy.vue';
-
-import { toDate, toCurrency, toCelsius } from 'src/filters';
-import { getUrl } from 'src/composables/getUrl';
-import axios from 'axios';
-import FetchedTags from 'src/components/ui/FetchedTags.vue';
-import VnToSummary from 'src/components/ui/VnToSummary.vue';
-import EntryDescriptorMenu from './EntryDescriptorMenu.vue';
-import VnRow from 'src/components/ui/VnRow.vue';
+import EntryBuys from './EntryBuys.vue';
import VnTitle from 'src/components/common/VnTitle.vue';
+import VnCheckbox from 'src/components/common/VnCheckbox.vue';
+import VnToSummary from 'src/components/ui/VnToSummary.vue';
const route = useRoute();
const { t } = useI18n();
@@ -33,117 +31,6 @@ const entry = ref();
const entryBuys = ref([]);
const entryUrl = ref();
-onMounted(async () => {
- entryUrl.value = (await getUrl('entry/')) + entityId.value;
-});
-
-const tableColumnComponents = {
- quantity: {
- component: () => 'span',
- props: () => {},
- },
- stickers: {
- component: () => 'span',
- props: () => {},
- event: () => {},
- },
- packagingFk: {
- component: () => 'span',
- props: () => {},
- event: () => {},
- },
- weight: {
- component: () => 'span',
- props: () => {},
- event: () => {},
- },
- packing: {
- component: () => 'span',
- props: () => {},
- event: () => {},
- },
- grouping: {
- component: () => 'span',
- props: () => {},
- event: () => {},
- },
- buyingValue: {
- component: () => 'span',
- props: () => {},
- event: () => {},
- },
- amount: {
- component: () => 'span',
- props: () => {},
- event: () => {},
- },
- pvp: {
- component: () => 'span',
- props: () => {},
- event: () => {},
- },
-};
-
-const entriesTableColumns = computed(() => {
- return [
- {
- label: t('globals.quantity'),
- field: 'quantity',
- name: 'quantity',
- align: 'left',
- },
- {
- label: t('entry.summary.stickers'),
- field: 'stickers',
- name: 'stickers',
- align: 'left',
- },
- {
- label: t('entry.summary.package'),
- field: 'packagingFk',
- name: 'packagingFk',
- align: 'left',
- },
- {
- label: t('globals.weight'),
- field: 'weight',
- name: 'weight',
- align: 'left',
- },
- {
- label: t('entry.summary.packing'),
- field: 'packing',
- name: 'packing',
- align: 'left',
- },
- {
- label: t('entry.summary.grouping'),
- field: 'grouping',
- name: 'grouping',
- align: 'left',
- },
- {
- label: t('entry.summary.buyingValue'),
- field: 'buyingValue',
- name: 'buyingValue',
- align: 'left',
- format: (value) => toCurrency(value),
- },
- {
- label: t('entry.summary.import'),
- name: 'amount',
- align: 'left',
- format: (_, row) => toCurrency(row.buyingValue * row.quantity),
- },
- {
- label: t('entry.summary.pvp'),
- name: 'pvp',
- align: 'left',
- format: (_, row) => toCurrency(row.price2) + ' / ' + toCurrency(row.price3),
- },
- ];
-});
-
async function setEntryData(data) {
if (data) entry.value = data;
await fetchEntryBuys();
@@ -153,14 +40,18 @@ const fetchEntryBuys = async () => {
const { data } = await axios.get(`Entries/${entry.value.id}/getBuys`);
if (data) entryBuys.value = data;
};
-
+onMounted(async () => {
+ entryUrl.value = (await getUrl('entry/')) + entityId.value;
+});
+
setEntryData(data)"
data-key="EntrySummary"
+ data-cy="entry-summary"
>
{
{{ entry.id }} - {{ entry.supplier.nickname }}
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
-
-
- {{ entry.travel.ref }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+ {{ entry.travel.ref }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
- {{ col.value }}
- {{
- col.toolTip
- }}
-
-
-
-
-
- {{ row.item.itemType.code }}
-
-
- {{ row.item.id }}
-
-
- {{ row.item.size }}
-
-
- {{ toCurrency(row.item.minPrice) }}
-
-
- {{ row.item.concept }}
-
- {{ row.item.subName }}
-
-
-
-
-
-
-
-
-
-
+
-
-
es:
- Travel data: Datos envío
+ Travel: Envío
+ InvoiceIn data: Datos factura
diff --git a/src/pages/Entry/EntryFilter.vue b/src/pages/Entry/EntryFilter.vue
index 0f632c0ef..8c60918a8 100644
--- a/src/pages/Entry/EntryFilter.vue
+++ b/src/pages/Entry/EntryFilter.vue
@@ -19,6 +19,7 @@ const props = defineProps({
const currenciesOptions = ref([]);
const companiesOptions = ref([]);
+const entryFilterPanel = ref();
@@ -38,7 +39,7 @@ const companiesOptions = ref([]);
@on-fetch="(data) => (currenciesOptions = data)"
auto-load
/>
-
+
{{ t(`entryFilter.params.${tag.label}`) }}:
@@ -48,70 +49,65 @@ const companiesOptions = ref([]);
-
+
+
+ {{ t('params.isExcludedFromAvailable') }}
+
+
+
+
+
+
+ {{ t('entry.list.tableVisibleColumns.isOrdered') }}
+
+
-
+
+
+ {{ t('entry.list.tableVisibleColumns.isReceived') }}
+
+
+
+
+
+
+ {{ t('entry.list.tableVisibleColumns.isConfirmed') }}
+
+
-
-
-
-
-
-
-
-
-
-
-
-
+
@@ -125,62 +121,165 @@ const companiesOptions = ref([]);
rounded
/>
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+ {{ scope.opt?.name }}
+
+
+ {{ `#${scope.opt?.id} , ${scope.opt?.nickname}` }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+en:
+ params:
+ isExcludedFromAvailable: Inventory
+ isOrdered: Ordered
+ isReceived: Received
+ isConfirmed: Confirmed
+ isRaid: Raid
+ landed: Date
+ id: Id
+ supplierFk: Supplier
+ invoiceNumber: Invoice number
+ reference: Ref/Alb/Guide
+ agencyModeId: Agency mode
+ evaNotes: Notes
+ warehouseOutFk: Origin
+ warehouseInFk: Destiny
+ entryTypeCode: Entry type
+ hasToShowDeletedEntries: Show deleted entries
+es:
+ params:
+ isExcludedFromAvailable: Inventario
+ isOrdered: Pedida
+ isConfirmed: Confirmado
+ isReceived: Recibida
+ isRaid: Raid
+ landed: Fecha
+ id: Id
+ supplierFk: Proveedor
+ invoiceNumber: Núm. factura
+ reference: Ref/Alb/Guía
+ agencyModeId: Modo agencia
+ evaNotes: Notas
+ warehouseOutFk: Origen
+ warehouseInFk: Destino
+ entryTypeCode: Tipo de entrada
+ hasToShowDeletedEntries: Mostrar entradas eliminadas
+
diff --git a/src/pages/Entry/EntryList.vue b/src/pages/Entry/EntryList.vue
index 3172c6d0e..d50f6b219 100644
--- a/src/pages/Entry/EntryList.vue
+++ b/src/pages/Entry/EntryList.vue
@@ -1,21 +1,25 @@
-
+
-
-
-
- {{
- t(
- 'entry.list.tableVisibleColumns.isExcludedFromAvailable',
- )
- }}
-
-
-
- {{
- t('globals.raid', {
- daysInForward: row.daysInForward,
- })
- }}
-
-
+
+
+ {{ toDate(row.landed) }}
+
@@ -252,13 +319,27 @@ const columns = computed(() => [
-
-
- {{ row.travelRef }}
-
-
+
+
+
+
+es:
+ Inventory entry: Es inventario
+ Virtual entry: Es una redada
+ Search entries: Buscar entradas
+ You can search by entry reference: Puedes buscar por referencia de la entrada
+ Create entry: Crear entrada
+ Type: Tipo
+
diff --git a/src/pages/Entry/EntryStockBought.vue b/src/pages/Entry/EntryStockBought.vue
index fa0bdc12e..da8557828 100644
--- a/src/pages/Entry/EntryStockBought.vue
+++ b/src/pages/Entry/EntryStockBought.vue
@@ -34,18 +34,20 @@ const columns = computed(() => [
label: t('entryStockBought.buyer'),
isTitle: true,
component: 'select',
+ isEditable: false,
cardVisible: true,
create: true,
attrs: {
url: 'Workers/activeWithInheritedRole',
- fields: ['id', 'name'],
+ fields: ['id', 'name', 'nickname'],
where: { role: 'buyer' },
optionFilter: 'firstName',
- optionLabel: 'name',
+ optionLabel: 'nickname',
optionValue: 'id',
useLike: false,
},
columnFilter: false,
+ width: '70px',
},
{
align: 'center',
@@ -55,6 +57,7 @@ const columns = computed(() => [
create: true,
component: 'number',
summation: true,
+ width: '60px',
},
{
align: 'center',
@@ -78,6 +81,7 @@ const columns = computed(() => [
actions: [
{
title: t('entryStockBought.viewMoreDetails'),
+ name: 'searchBtn',
icon: 'search',
isPrimary: true,
action: (row) => {
@@ -91,6 +95,7 @@ const columns = computed(() => [
},
},
],
+ 'data-cy': 'table-actions',
},
]);
@@ -158,7 +163,7 @@ function round(value) {
@on-fetch="
(data) => {
travel = data.find(
- (data) => data.warehouseIn?.code.toLowerCase() === 'vnh'
+ (data) => data.warehouseIn?.code.toLowerCase() === 'vnh',
);
}
"
@@ -179,6 +184,7 @@ function round(value) {
@click="openDialog()"
:title="t('entryStockBought.editTravel')"
color="primary"
+ data-cy="edit-travel"
/>
@@ -239,10 +245,11 @@ function round(value) {
table-height="80vh"
auto-load
:column-search="false"
+ :without-header="true"
>
- {{ row?.worker?.user?.name }}
+ {{ row?.worker?.user?.nickname }}
@@ -279,10 +286,11 @@ function round(value) {
justify-content: center;
}
.column {
+ min-width: 30%;
+ margin-top: 5%;
display: flex;
flex-direction: column;
align-items: center;
- min-width: 35%;
}
.text-negative {
color: $negative !important;
diff --git a/src/pages/Entry/EntryStockBoughtDetail.vue b/src/pages/Entry/EntryStockBoughtDetail.vue
index 812171825..9d382f23a 100644
--- a/src/pages/Entry/EntryStockBoughtDetail.vue
+++ b/src/pages/Entry/EntryStockBoughtDetail.vue
@@ -21,7 +21,7 @@ const $props = defineProps({
const customUrl = `StockBoughts/getStockBoughtDetail?workerFk=${$props.workerFk}&dated=${$props.dated}`;
const columns = [
{
- align: 'left',
+ align: 'right',
label: t('Entry'),
name: 'entryFk',
isTitle: true,
@@ -29,7 +29,7 @@ const columns = [
columnFilter: false,
},
{
- align: 'left',
+ align: 'right',
name: 'itemFk',
label: t('Item'),
columnFilter: false,
@@ -44,21 +44,21 @@ const columns = [
cardVisible: true,
},
{
- align: 'left',
+ align: 'right',
name: 'volume',
label: t('Volume'),
columnFilter: false,
cardVisible: true,
},
{
- align: 'left',
+ align: 'right',
label: t('Packaging'),
name: 'packagingFk',
columnFilter: false,
cardVisible: true,
},
{
- align: 'left',
+ align: 'right',
label: 'Packing',
name: 'packing',
columnFilter: false,
@@ -73,12 +73,14 @@ const columns = [
ref="tableRef"
data-key="StockBoughtsDetail"
:url="customUrl"
- order="itemName DESC"
+ order="volume DESC"
:columns="columns"
:right-search="false"
:disable-infinite-scroll="true"
:disable-option="{ card: true }"
:limit="0"
+ :without-header="true"
+ :with-filters="false"
auto-load
>
@@ -105,7 +107,7 @@ const columns = [
align-items: center;
margin: auto;
background-color: var(--vn-section-color);
- padding: 4px;
+ padding: 2%;
}
.container > div > div > .q-table__top.relative-position.row.items-center {
background-color: red !important;
diff --git a/src/pages/Entry/locale/en.yml b/src/pages/Entry/locale/en.yml
index 80f3491a8..88b16cb03 100644
--- a/src/pages/Entry/locale/en.yml
+++ b/src/pages/Entry/locale/en.yml
@@ -1,21 +1,36 @@
entry:
+ lock:
+ title: Lock entry
+ message: This entry has been locked by {userName} for {time} minutes. Do you want to unlock it?
+ success: The entry has been locked successfully
list:
newEntry: New entry
tableVisibleColumns:
- created: Creation
- supplierFk: Supplier
- isBooked: Booked
- isConfirmed: Confirmed
+ isExcludedFromAvailable: Exclude from inventory
isOrdered: Ordered
+ isConfirmed: Ready to label
+ isReceived: Received
+ isRaid: Raid
+ landed: Date
+ supplierFk: Supplier
+ reference: Ref/Alb/Guide
+ invoiceNumber: Invoice
+ agencyModeId: Agency
+ isBooked: Booked
companyFk: Company
- travelFk: Travel
- isExcludedFromAvailable: Inventory
+ evaNotes: Notes
+ warehouseOutFk: Origin
+ warehouseInFk: Destiny
+ 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
@@ -33,6 +48,7 @@ entry:
buyingValue: Buying value
import: Import
pvp: PVP
+ entryType: Entry type
basicData:
travel: Travel
currency: Currency
@@ -69,17 +85,55 @@ 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
descriptorMenu:
showEntryReport: Show entry report
entryFilter:
params:
+ isExcludedFromAvailable: Exclude from inventory
invoiceNumber: Invoice number
travelFk: Travel
companyFk: Company
@@ -91,8 +145,16 @@ entryFilter:
isBooked: Booked
isConfirmed: Confirmed
isOrdered: Ordered
+ isReceived: Received
search: General search
reference: Reference
+ landed: Landed
+ id: Id
+ agencyModeId: Agency
+ evaNotes: Notes
+ warehouseOutFk: Origin
+ warehouseInFk: Destiny
+ entryTypeCode: Entry type
myEntries:
id: ID
landed: Landed
diff --git a/src/pages/Entry/locale/es.yml b/src/pages/Entry/locale/es.yml
index a5b968016..3025d64cb 100644
--- a/src/pages/Entry/locale/es.yml
+++ b/src/pages/Entry/locale/es.yml
@@ -1,21 +1,36 @@
entry:
+ lock:
+ title: Entrada bloqueada
+ message: Esta entrada ha sido bloqueada por {userName} hace {time} minutos. ¿Quieres desbloquearla?
+ success: La entrada ha sido bloqueada correctamente
list:
newEntry: Nueva entrada
tableVisibleColumns:
- created: Creación
- supplierFk: Proveedor
- isBooked: Asentado
- isConfirmed: Confirmado
+ isExcludedFromAvailable: Excluir del inventario
isOrdered: Pedida
+ isConfirmed: Lista para etiquetar
+ isReceived: Recibida
+ isRaid: Redada
+ landed: Fecha
+ supplierFk: Proveedor
+ invoiceNumber: Nº Factura
+ reference: Ref/Alb/Guía
+ agencyModeId: Agencia
+ isBooked: Asentado
companyFk: Empresa
travelFk: Envio
- isExcludedFromAvailable: Inventario
+ evaNotes: Notas
+ warehouseOutFk: Origen
+ 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
@@ -34,12 +49,13 @@ entry:
buyingValue: Coste
import: Importe
pvp: PVP
+ entryType: Tipo entrada
basicData:
travel: Envío
currency: Moneda
observation: Observación
commission: Comisión
- booked: Asentado
+ booked: Contabilizada
excludedFromAvailable: Inventario
initialTemperature: Ini °C
finalTemperature: Fin °C
@@ -69,31 +85,70 @@ 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
- descriptorMenu:
- showEntryReport: Ver informe del pedido
+
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
- travelFk: Envío
- companyFk: Empresa
- currencyFk: Moneda
- supplierFk: Proveedor
- from: Desde
- to: Hasta
- created: Fecha creación
- isBooked: Asentado
- isConfirmed: Confirmado
+ isExcludedFromAvailable: Inventario
isOrdered: Pedida
- search: Búsqueda general
- reference: Referencia
+ isConfirmed: Confirmado
+ isReceived: Recibida
+ isRaid: Raid
+ landed: Fecha
+ id: Id
+ supplierFk: Proveedor
+ invoiceNumber: Núm. factura
+ reference: Ref/Alb/Guía
+ agencyModeId: Modo agencia
+ evaNotes: Notas
+ warehouseOutFk: Origen
+ warehouseInFk: Destino
+ entryTypeCode: Tipo de entrada
+ hasToShowDeletedEntries: Mostrar entradas eliminadas
myEntries:
id: ID
landed: F. llegada
diff --git a/src/pages/InvoiceIn/Card/InvoiceInBasicData.vue b/src/pages/InvoiceIn/Card/InvoiceInBasicData.vue
index c01ec4ab4..905ddebb2 100644
--- a/src/pages/InvoiceIn/Card/InvoiceInBasicData.vue
+++ b/src/pages/InvoiceIn/Card/InvoiceInBasicData.vue
@@ -125,7 +125,7 @@ function deleteFile(dmsFk) {
@@ -149,6 +149,7 @@ function deleteFile(dmsFk) {
option-value="id"
option-label="id"
:filter-options="['id', 'name']"
+ data-cy="UnDeductibleVatSelect"
>
@@ -215,7 +216,7 @@ function deleteFile(dmsFk) {
v-else
icon="add_circle"
round
- shortcut="+"
+ v-shortcut="'+'"
padding="xs"
@click="
() => {
@@ -310,7 +311,6 @@ function deleteFile(dmsFk) {
supplierFk: Supplier
es:
supplierFk: Proveedor
- Supplier ref: Ref. proveedor
Expedition date: Fecha expedición
Operation date: Fecha operación
Undeductible VAT: Iva no deducible
diff --git a/src/pages/InvoiceIn/Card/InvoiceInCard.vue b/src/pages/InvoiceIn/Card/InvoiceInCard.vue
index 8aa35f4d8..34cc26437 100644
--- a/src/pages/InvoiceIn/Card/InvoiceInCard.vue
+++ b/src/pages/InvoiceIn/Card/InvoiceInCard.vue
@@ -1,47 +1,18 @@
diff --git a/src/pages/InvoiceIn/Card/InvoiceInDescriptor.vue b/src/pages/InvoiceIn/Card/InvoiceInDescriptor.vue
index da7bd4426..3843f5bf7 100644
--- a/src/pages/InvoiceIn/Card/InvoiceInDescriptor.vue
+++ b/src/pages/InvoiceIn/Card/InvoiceInDescriptor.vue
@@ -7,6 +7,7 @@ import { toCurrency, toDate } from 'src/filters';
import VnLv from 'src/components/ui/VnLv.vue';
import CardDescriptor from 'components/ui/CardDescriptor.vue';
import SupplierDescriptorProxy from 'src/pages/Supplier/Card/SupplierDescriptorProxy.vue';
+import filter from './InvoiceInFilter.js';
import InvoiceInDescriptorMenu from './InvoiceInDescriptorMenu.vue';
const $props = defineProps({ id: { type: Number, default: null } });
@@ -16,33 +17,10 @@ const { t } = useI18n();
const cardDescriptorRef = ref();
const entityId = computed(() => $props.id || +currentRoute.value.params.id);
const totalAmount = ref();
-
-const filter = {
- include: [
- {
- relation: 'supplier',
- scope: {
- include: {
- relation: 'contacts',
- scope: {
- where: {
- email: { neq: null },
- },
- },
- },
- },
- },
- {
- relation: 'invoiceInDueDay',
- },
- {
- relation: 'company',
- },
- {
- relation: 'currency',
- },
- ],
-};
+const config = ref();
+const cplusRectificationTypes = ref([]);
+const siiTypeInvoiceIns = ref([]);
+const invoiceCorrectionTypes = ref([]);
const invoiceInCorrection = reactive({ correcting: [], corrected: null });
const routes = reactive({
getSupplier: (id) => {
@@ -112,7 +90,6 @@ async function setInvoiceCorrection(id) {
{
clickable
@click="book(entityId)"
>
- {{ t('invoiceIn.descriptorMenu.toBook') }}
+ {{ t('invoiceIn.descriptorMenu.book') }}
@@ -197,7 +197,7 @@ const createInvoiceInCorrection = async () => {
@click="triggerMenu('unbook')"
>
- {{ t('invoiceIn.descriptorMenu.toUnbook') }}
+ {{ t('invoiceIn.descriptorMenu.unbook') }}
-import { ref, computed } from 'vue';
+import { ref, computed, onBeforeMount } from 'vue';
import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n';
import axios from 'axios';
@@ -11,6 +11,7 @@ import VnSelect from 'src/components/common/VnSelect.vue';
import useNotify from 'src/composables/useNotify.js';
import VnInputDate from 'src/components/common/VnInputDate.vue';
import VnInputNumber from 'src/components/common/VnInputNumber.vue';
+import { toCurrency } from 'filters/index';
const route = useRoute();
const { notify } = useNotify();
@@ -24,7 +25,7 @@ const invoiceInFormRef = ref();
const invoiceId = +route.params.id;
const filter = { where: { invoiceInFk: invoiceId } };
const areRows = ref(false);
-
+const totals = ref();
const columns = computed(() => [
{
name: 'duedate',
@@ -63,6 +64,8 @@ const columns = computed(() => [
},
]);
+const totalAmount = computed(() => getTotal(invoiceInFormRef.value.formData, 'amount'));
+
const isNotEuro = (code) => code != 'EUR';
async function insert() {
@@ -70,6 +73,10 @@ async function insert() {
await invoiceInFormRef.value.reload();
notify(t('globals.dataSaved'), 'positive');
}
+
+onBeforeMount(async () => {
+ totals.value = (await axios.get(`InvoiceIns/${invoiceId}/getTotals`)).data;
+});
- {{ getTotal(rows, 'amount', { currency: 'default' }) }}
+ {{ toCurrency(totalAmount) }}
@@ -222,10 +229,19 @@ async function insert() {
{
+ if (!areRows) insert();
+ else
+ invoiceInFormRef.insert({
+ amount: (totals.totalTaxableBase - totalAmount).toFixed(2),
+ invoiceInFk: invoiceId,
+ });
+ }
+ "
/>
diff --git a/src/pages/InvoiceIn/Card/InvoiceInFilter.js b/src/pages/InvoiceIn/Card/InvoiceInFilter.js
new file mode 100644
index 000000000..6df8b5830
--- /dev/null
+++ b/src/pages/InvoiceIn/Card/InvoiceInFilter.js
@@ -0,0 +1,33 @@
+export default {
+ include: [
+ {
+ relation: 'supplier',
+ scope: {
+ include: {
+ relation: 'contacts',
+ scope: { where: { email: { neq: null } } },
+ },
+ },
+ },
+ { relation: 'invoiceInDueDay' },
+ { relation: 'company' },
+ { relation: 'currency' },
+ {
+ relation: 'dms',
+ scope: {
+ fields: [
+ 'dmsTypeFk',
+ 'reference',
+ 'hardCopyNumber',
+ 'workerFk',
+ 'description',
+ 'hasFile',
+ 'file',
+ 'created',
+ 'companyFk',
+ 'warehouseFk',
+ ],
+ },
+ },
+ ],
+};
diff --git a/src/pages/InvoiceIn/Card/InvoiceInIntrastat.vue b/src/pages/InvoiceIn/Card/InvoiceInIntrastat.vue
index e529ea6cd..6f8642313 100644
--- a/src/pages/InvoiceIn/Card/InvoiceInIntrastat.vue
+++ b/src/pages/InvoiceIn/Card/InvoiceInIntrastat.vue
@@ -218,7 +218,7 @@ const columns = computed(() => [
`#/invoice-in/${entityId.value}/${param}`;
`#/invoice-in/${entityId.value}/${param}`;
-
+
`#/invoice-in/${entityId.value}/${param}`;
entity.totals.totalTaxableBaseForeignValue &&
toCurrency(
entity.totals.totalTaxableBaseForeignValue,
- currency
+ currency,
)
}}
@@ -392,7 +389,7 @@ const getLink = (param) => `#/invoice-in/${entityId.value}/${param}`;
entity.totals.totalDueDayForeignValue &&
toCurrency(
entity.totals.totalDueDayForeignValue,
- currency
+ currency,
)
}}
@@ -472,5 +469,5 @@ const getLink = (param) => `#/invoice-in/${entityId.value}/${param}`;
Search invoice: Buscar factura recibida
You can search by invoice reference: Puedes buscar por referencia de la factura
Totals: Totales
- To book: Contabilizar
+ Book: Contabilizar
diff --git a/src/pages/InvoiceIn/Card/InvoiceInVat.vue b/src/pages/InvoiceIn/Card/InvoiceInVat.vue
index f99e060b8..e77453bc0 100644
--- a/src/pages/InvoiceIn/Card/InvoiceInVat.vue
+++ b/src/pages/InvoiceIn/Card/InvoiceInVat.vue
@@ -1,5 +1,5 @@
{
@@ -214,7 +228,7 @@ const combinedTotal = computed(() => {
-
+
{
@@ -248,11 +266,15 @@ const combinedTotal = computed(() => {
@@ -270,7 +292,7 @@ const combinedTotal = computed(() => {
-
+
{
color="primary"
icon="add"
size="lg"
- shortcut="+"
+ v-shortcut="'+'"
round
@click="invoiceInFormRef.insert()"
>
diff --git a/src/pages/InvoiceIn/InvoiceInList.vue b/src/pages/InvoiceIn/InvoiceInList.vue
index e1723e3b1..0960d0d6c 100644
--- a/src/pages/InvoiceIn/InvoiceInList.vue
+++ b/src/pages/InvoiceIn/InvoiceInList.vue
@@ -29,6 +29,7 @@ const cols = computed(() => [
name: 'isBooked',
label: t('invoiceIn.isBooked'),
columnFilter: false,
+ component: 'checkbox',
},
{
align: 'left',
@@ -56,7 +57,7 @@ const cols = computed(() => [
{
align: 'left',
name: 'supplierRef',
- label: t('invoiceIn.list.supplierRef'),
+ label: t('invoiceIn.supplierRef'),
},
{
align: 'left',
@@ -177,7 +178,7 @@ const cols = computed(() => [
:required="true"
/>
await toBook(id));
+ if (!messages.length) toBook(id);
+ else
+ dialog({
+ component: VnConfirm,
+ componentProps: {
+ title: t('Are you sure you want to book this invoice?'),
+ message: messages.reduce((acc, msg) => `${acc}${msg}
`, ''),
+ },
+ }).onOk(() => toBook(id));
}
async function toBook(id) {
@@ -59,4 +82,7 @@ async function toBook(id) {
es:
Are you sure you want to book this invoice?: ¿Estás seguro de querer asentar esta factura?
It was not able to book the invoice: No se pudo contabilizar la factura
+ Some due dates are less than or equal to today: Algún vencimiento tiene una fecha menor o igual que hoy
+ The sum of the taxable bases does not match the due dates: La suma de las bases imponibles no coincide con la de los vencimientos
+ The VAT and Transaction fields have not been informed: No se han informado los campos de iva y/o transacción
diff --git a/src/pages/InvoiceIn/locale/en.yml b/src/pages/InvoiceIn/locale/en.yml
index 6b21b316b..548e6c201 100644
--- a/src/pages/InvoiceIn/locale/en.yml
+++ b/src/pages/InvoiceIn/locale/en.yml
@@ -3,10 +3,10 @@ invoiceIn:
searchInfo: Search incoming invoices by ID or supplier fiscal name
serial: Serial
isBooked: Is booked
+ supplierRef: Invoice nº
list:
ref: Reference
supplier: Supplier
- supplierRef: Supplier ref.
file: File
issued: Issued
dueDated: Due dated
@@ -19,8 +19,6 @@ invoiceIn:
unbook: Unbook
delete: Delete
clone: Clone
- toBook: To book
- toUnbook: To unbook
deleteInvoice: Delete invoice
invoiceDeleted: invoice deleted
cloneInvoice: Clone invoice
@@ -70,4 +68,3 @@ invoiceIn:
isBooked: Is booked
account: Ledger account
correctingFk: Rectificative
-
\ No newline at end of file
diff --git a/src/pages/InvoiceIn/locale/es.yml b/src/pages/InvoiceIn/locale/es.yml
index 3f27c895c..142d95f92 100644
--- a/src/pages/InvoiceIn/locale/es.yml
+++ b/src/pages/InvoiceIn/locale/es.yml
@@ -3,10 +3,10 @@ invoiceIn:
searchInfo: Buscar facturas recibidas por ID o nombre fiscal del proveedor
serial: Serie
isBooked: Contabilizada
+ supplierRef: Nº factura
list:
ref: Referencia
supplier: Proveedor
- supplierRef: Ref. proveedor
issued: F. emisión
dueDated: F. vencimiento
file: Fichero
@@ -15,12 +15,10 @@ invoiceIn:
descriptor:
ticketList: Listado de tickets
descriptorMenu:
- book: Asentar
- unbook: Desasentar
+ book: Contabilizar
+ unbook: Descontabilizar
delete: Eliminar
clone: Clonar
- toBook: Contabilizar
- toUnbook: Descontabilizar
deleteInvoice: Eliminar factura
invoiceDeleted: Factura eliminada
cloneInvoice: Clonar factura
@@ -68,4 +66,3 @@ invoiceIn:
isBooked: Contabilizada
account: Cuenta contable
correctingFk: Rectificativa
-
diff --git a/src/pages/InvoiceOut/Card/InvoiceOutCard.vue b/src/pages/InvoiceOut/Card/InvoiceOutCard.vue
index 93e3fe042..a50c9d247 100644
--- a/src/pages/InvoiceOut/Card/InvoiceOutCard.vue
+++ b/src/pages/InvoiceOut/Card/InvoiceOutCard.vue
@@ -1,11 +1,13 @@
diff --git a/src/pages/InvoiceOut/Card/InvoiceOutDescriptor.vue b/src/pages/InvoiceOut/Card/InvoiceOutDescriptor.vue
index 209f1531e..dfaf6c109 100644
--- a/src/pages/InvoiceOut/Card/InvoiceOutDescriptor.vue
+++ b/src/pages/InvoiceOut/Card/InvoiceOutDescriptor.vue
@@ -8,8 +8,8 @@ import CustomerDescriptorProxy from 'pages/Customer/Card/CustomerDescriptorProxy
import VnLv from 'src/components/ui/VnLv.vue';
import InvoiceOutDescriptorMenu from './InvoiceOutDescriptorMenu.vue';
-import useCardDescription from 'src/composables/useCardDescription';
import { toCurrency, toDate } from 'src/filters';
+import filter from './InvoiceOutFilter.js';
const $props = defineProps({
id: {
@@ -26,42 +26,20 @@ const entityId = computed(() => {
return $props.id || route.params.id;
});
-const filter = {
- include: [
- {
- relation: 'company',
- scope: {
- fields: ['id', 'code'],
- },
- },
- {
- relation: 'client',
- scope: {
- fields: ['id', 'name', 'email'],
- },
- },
- ],
-};
-
const descriptor = ref();
function ticketFilter(invoice) {
return JSON.stringify({ refFk: invoice.ref });
}
-const data = ref(useCardDescription());
-const setData = (entity) => (data.value = useCardDescription(entity.ref, entity.id));
diff --git a/src/pages/InvoiceOut/Card/InvoiceOutFilter.js b/src/pages/InvoiceOut/Card/InvoiceOutFilter.js
new file mode 100644
index 000000000..48b20faf6
--- /dev/null
+++ b/src/pages/InvoiceOut/Card/InvoiceOutFilter.js
@@ -0,0 +1,16 @@
+export default {
+ include: [
+ {
+ relation: 'company',
+ scope: {
+ fields: ['id', 'code'],
+ },
+ },
+ {
+ relation: 'client',
+ scope: {
+ fields: ['id', 'name', 'email'],
+ },
+ },
+ ],
+};
diff --git a/src/pages/Item/Card/ItemBarcode.vue b/src/pages/Item/Card/ItemBarcode.vue
index 6db5943c7..590b524cd 100644
--- a/src/pages/Item/Card/ItemBarcode.vue
+++ b/src/pages/Item/Card/ItemBarcode.vue
@@ -92,7 +92,7 @@ const submit = async (rows) => {
class="cursor-pointer fill-icon-on-hover"
color="primary"
icon="add_circle"
- shortcut="+"
+ v-shortcut="'+'"
flat
>
diff --git a/src/pages/Item/Card/ItemBasicData.vue b/src/pages/Item/Card/ItemBasicData.vue
index 4c96401f3..df7e71684 100644
--- a/src/pages/Item/Card/ItemBasicData.vue
+++ b/src/pages/Item/Card/ItemBasicData.vue
@@ -11,6 +11,7 @@ import VnSelect from 'src/components/common/VnSelect.vue';
import VnSelectDialog from 'src/components/common/VnSelectDialog.vue';
import FilterItemForm from 'src/components/FilterItemForm.vue';
import CreateIntrastatForm from './CreateIntrastatForm.vue';
+import VnCheckbox from 'src/components/common/VnCheckbox.vue';
const route = useRoute();
const { t } = useI18n();
@@ -54,9 +55,8 @@ const onIntrastatCreated = (response, formData) => {
auto-load
/>
@@ -209,30 +209,20 @@ const onIntrastatCreated = (response, formData) => {
/>
-
-
-
-
- {{ t('item.basicData.isFragileTooltip') }}
-
-
-
-
-
-
-
- {{ t('item.basicData.isPhotoRequestedTooltip') }}
-
-
-
+
+
diff --git a/src/pages/Item/Card/ItemDescriptor.vue b/src/pages/Item/Card/ItemDescriptor.vue
index c6fee8540..a4c58ef4b 100644
--- a/src/pages/Item/Card/ItemDescriptor.vue
+++ b/src/pages/Item/Card/ItemDescriptor.vue
@@ -7,7 +7,6 @@ import CardDescriptor from 'src/components/ui/CardDescriptor.vue';
import VnLv from 'src/components/ui/VnLv.vue';
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
import ItemDescriptorImage from 'src/pages/Item/Card/ItemDescriptorImage.vue';
-import useCardDescription from 'src/composables/useCardDescription';
import axios from 'axios';
import { dashIfEmpty } from 'src/filters';
import { useArrayData } from 'src/composables/useArrayData';
@@ -35,6 +34,10 @@ const $props = defineProps({
type: Number,
default: null,
},
+ proxyRender: {
+ type: Boolean,
+ default: false,
+ },
});
const route = useRoute();
@@ -55,10 +58,8 @@ onMounted(async () => {
mounted.value = true;
});
-const data = ref(useCardDescription());
const setData = async (entity) => {
if (!entity) return;
- data.value = useCardDescription(entity.name, entity.id);
await updateStock();
};
@@ -90,10 +91,7 @@ const updateStock = async () => {
{
{{ entity.itemType?.worker?.user?.name }}
-
+
@@ -152,7 +150,7 @@ const updateStock = async () => {
-
+
+ {{ t('item.descriptor.itemLastEntries') }}
+
diff --git a/src/pages/Item/Card/ItemDescriptorProxy.vue b/src/pages/Item/Card/ItemDescriptorProxy.vue
index 2ffc9080f..f686e8221 100644
--- a/src/pages/Item/Card/ItemDescriptorProxy.vue
+++ b/src/pages/Item/Card/ItemDescriptorProxy.vue
@@ -4,7 +4,7 @@ import ItemSummary from './ItemSummary.vue';
const $props = defineProps({
id: {
- type: Number,
+ type: [Number, String],
required: true,
},
dated: {
@@ -21,9 +21,8 @@ const $props = defineProps({
},
});
-
-
+
diff --git a/src/pages/Item/Card/ItemShelving.vue b/src/pages/Item/Card/ItemShelving.vue
index 7ad60c9e0..b29e2a2a5 100644
--- a/src/pages/Item/Card/ItemShelving.vue
+++ b/src/pages/Item/Card/ItemShelving.vue
@@ -110,10 +110,16 @@ const columns = computed(() => [
attrs: { inWhere: true },
align: 'left',
},
+ {
+ label: t('globals.visible'),
+ name: 'stock',
+ attrs: { inWhere: true },
+ align: 'left',
+ },
]);
const totalLabels = computed(() =>
- rows.value.reduce((acc, row) => acc + row.stock / row.packing, 0).toFixed(2)
+ rows.value.reduce((acc, row) => acc + row.stock / row.packing, 0).toFixed(2),
);
const removeLines = async () => {
@@ -157,7 +163,7 @@ watchEffect(selectedRows);
openConfirmationModal(
t('shelvings.removeConfirmTitle'),
t('shelvings.removeConfirmSubtitle'),
- removeLines
+ removeLines,
)
"
>
diff --git a/src/pages/Item/Card/ItemTags.vue b/src/pages/Item/Card/ItemTags.vue
index 5876cf8dc..ed23ab5a6 100644
--- a/src/pages/Item/Card/ItemTags.vue
+++ b/src/pages/Item/Card/ItemTags.vue
@@ -175,7 +175,7 @@ const insertTag = (rows) => {
@click="insertTag(rows)"
color="primary"
icon="add"
- shortcut="+"
+ v-shortcut="'+'"
fab
>
diff --git a/src/pages/Item/ItemFixedPrice.vue b/src/pages/Item/ItemFixedPrice.vue
index 1c4382fbd..fdfa1d3d1 100644
--- a/src/pages/Item/ItemFixedPrice.vue
+++ b/src/pages/Item/ItemFixedPrice.vue
@@ -65,10 +65,19 @@ const columns = computed(() => [
name: 'name',
...defaultColumnAttrs,
create: true,
+ columnFilter: {
+ component: 'select',
+ attrs: {
+ url: 'Items',
+ fields: ['id', 'name', 'subName'],
+ optionLabel: 'name',
+ optionValue: 'name',
+ uppercase: false,
+ },
+ },
},
{
label: t('item.fixedPrice.groupingPrice'),
- field: 'rate2',
name: 'rate2',
...defaultColumnAttrs,
component: 'input',
@@ -76,7 +85,6 @@ const columns = computed(() => [
},
{
label: t('item.fixedPrice.packingPrice'),
- field: 'rate3',
name: 'rate3',
...defaultColumnAttrs,
component: 'input',
@@ -85,7 +93,6 @@ const columns = computed(() => [
{
label: t('item.fixedPrice.minPrice'),
- field: 'minPrice',
name: 'minPrice',
...defaultColumnAttrs,
component: 'input',
@@ -108,7 +115,6 @@ const columns = computed(() => [
},
{
label: t('item.fixedPrice.ended'),
- field: 'ended',
name: 'ended',
...defaultColumnAttrs,
columnField: {
@@ -124,7 +130,6 @@ const columns = computed(() => [
{
label: t('globals.warehouse'),
- field: 'warehouseFk',
name: 'warehouseFk',
...defaultColumnAttrs,
columnClass: 'shrink',
@@ -415,7 +420,6 @@ function handleOnDataSave({ CrudModelRef }) {
'row-key': 'id',
selection: 'multiple',
}"
- :use-model="true"
v-model:selected="rowsSelected"
:create-as-dialog="false"
:create="{
diff --git a/src/pages/Item/ItemType/Card/ItemTypeBasicData.vue b/src/pages/Item/ItemType/Card/ItemTypeBasicData.vue
index b4032ff8a..475dffd8b 100644
--- a/src/pages/Item/ItemType/Card/ItemTypeBasicData.vue
+++ b/src/pages/Item/ItemType/Card/ItemTypeBasicData.vue
@@ -40,12 +40,7 @@ const itemPackingTypesOptions = ref([]);
}"
auto-load
/>
-
+
diff --git a/src/pages/Item/ItemType/Card/ItemTypeCard.vue b/src/pages/Item/ItemType/Card/ItemTypeCard.vue
index fa51e428e..84e810de5 100644
--- a/src/pages/Item/ItemType/Card/ItemTypeCard.vue
+++ b/src/pages/Item/ItemType/Card/ItemTypeCard.vue
@@ -1,12 +1,14 @@
diff --git a/src/pages/Item/ItemType/Card/ItemTypeDescriptor.vue b/src/pages/Item/ItemType/Card/ItemTypeDescriptor.vue
index 09d3dbce5..725fb30aa 100644
--- a/src/pages/Item/ItemType/Card/ItemTypeDescriptor.vue
+++ b/src/pages/Item/ItemType/Card/ItemTypeDescriptor.vue
@@ -1,12 +1,11 @@
-
-
-
-
+
+
+
{{ entity.worker?.firstName }}
-
+
-
diff --git a/src/pages/Item/ItemType/Card/ItemTypeFilter.js b/src/pages/Item/ItemType/Card/ItemTypeFilter.js
new file mode 100644
index 000000000..5651d368d
--- /dev/null
+++ b/src/pages/Item/ItemType/Card/ItemTypeFilter.js
@@ -0,0 +1,8 @@
+export default {
+ include: [
+ { relation: 'worker' },
+ { relation: 'category' },
+ { relation: 'itemPackingType' },
+ { relation: 'temperature' },
+ ],
+};
diff --git a/src/pages/Item/ItemType/Card/ItemTypeSummary.vue b/src/pages/Item/ItemType/Card/ItemTypeSummary.vue
index 9ba774ca4..3b63c4b63 100644
--- a/src/pages/Item/ItemType/Card/ItemTypeSummary.vue
+++ b/src/pages/Item/ItemType/Card/ItemTypeSummary.vue
@@ -3,7 +3,7 @@ import { ref, computed, onUpdated } from 'vue';
import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n';
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
-
+import filter from './ItemTypeFilter.js';
import CardSummary from 'components/ui/CardSummary.vue';
import VnLv from 'src/components/ui/VnLv.vue';
import VnToSummary from 'src/components/ui/VnToSummary.vue';
@@ -21,15 +21,6 @@ const $props = defineProps({
},
});
-const itemTypeFilter = {
- include: [
- { relation: 'worker' },
- { relation: 'category' },
- { relation: 'itemPackingType' },
- { relation: 'temperature' },
- ],
-};
-
const entityId = computed(() => $props.id || route.params.id);
const summaryRef = ref();
const itemType = ref();
@@ -43,8 +34,8 @@ async function setItemTypeData(data) {
setItemTypeData(data)"
class="full-width"
>
diff --git a/src/pages/Item/Card/CreateGenusForm.vue b/src/pages/Item/components/CreateGenusForm.vue
similarity index 100%
rename from src/pages/Item/Card/CreateGenusForm.vue
rename to src/pages/Item/components/CreateGenusForm.vue
diff --git a/src/pages/Item/Card/CreateSpecieForm.vue b/src/pages/Item/components/CreateSpecieForm.vue
similarity index 100%
rename from src/pages/Item/Card/CreateSpecieForm.vue
rename to src/pages/Item/components/CreateSpecieForm.vue
diff --git a/src/pages/Item/components/ItemProposal.vue b/src/pages/Item/components/ItemProposal.vue
new file mode 100644
index 000000000..d2dbea7b3
--- /dev/null
+++ b/src/pages/Item/components/ItemProposal.vue
@@ -0,0 +1,332 @@
+
+
+
+
+
+
+
+
+ {{ statusConditionalValue(row) }}%
+
+
+
+ {{ row.longName }}
+
+
+
+
+
+
+ {{ row.value5 }}
+
+
+ {{ row.value6 }}
+
+
+ {{ row.value7 }}
+
+
+ {{ row.counter }}
+
+
+ {{ row.minQuantity }}
+
+
+
+
+ {{
+ toCurrency(row.price2)
+ }}
+
+
+
+
+
diff --git a/src/pages/Item/components/ItemProposalProxy.vue b/src/pages/Item/components/ItemProposalProxy.vue
new file mode 100644
index 000000000..7da0ce398
--- /dev/null
+++ b/src/pages/Item/components/ItemProposalProxy.vue
@@ -0,0 +1,56 @@
+
+
+
+
+
+ {{ $t('Item proposal') }}
+
+
+
+
+ {
+ emit('itemReplaced', data);
+ dialogRef.hide();
+ }
+ "
+ >
+
+
+
+
diff --git a/src/pages/Item/locale/en.yml b/src/pages/Item/locale/en.yml
index bc73abb12..9d27fc96e 100644
--- a/src/pages/Item/locale/en.yml
+++ b/src/pages/Item/locale/en.yml
@@ -112,6 +112,7 @@ item:
available: Available
warehouseText: 'Calculated on the warehouse of { warehouseName }'
itemDiary: Item diary
+ itemLastEntries: Last entries
producer: Producer
clone:
title: All its properties will be copied
@@ -130,6 +131,7 @@ item:
origin: Orig.
userName: Buyer
weight: Weight
+ color: Color
weightByPiece: Weight/stem
stemMultiplier: Multiplier
producer: Producer
@@ -215,4 +217,24 @@ item:
specie: Specie
search: 'Search item'
searchInfo: 'You can search by id'
- regularizeStock: Regularize stock
\ No newline at end of file
+ regularizeStock: Regularize stock
+itemProposal: Items proposal
+proposal:
+ difference: Difference
+ title: Items proposal
+ itemFk: Item
+ longName: Name
+ subName: Producer
+ value5: value5
+ value6: value6
+ value7: value7
+ value8: value8
+ available: Available
+ minQuantity: minQuantity
+ price2: Price
+ located: Located
+ counter: Counter
+ groupingPrice: Grouping Price
+ itemOldPrice: itemOld Price
+ status: State
+ quantityToReplace: Quanity to replace
diff --git a/src/pages/Item/locale/es.yml b/src/pages/Item/locale/es.yml
index dd5074f5f..935f5160b 100644
--- a/src/pages/Item/locale/es.yml
+++ b/src/pages/Item/locale/es.yml
@@ -118,6 +118,7 @@ item:
available: Disponible
warehouseText: 'Calculado sobre el almacén de { warehouseName }'
itemDiary: Registro de compra-venta
+ itemLastEntries: Últimas entradas
producer: Productor
clone:
title: Todas sus propiedades serán copiadas
@@ -135,6 +136,7 @@ item:
size: Medida
origin: Orig.
weight: Peso
+ color: Color
weightByPiece: Peso/tallo
userName: Comprador
stemMultiplier: Multiplicador
@@ -220,5 +222,30 @@ item:
achieved: 'Conseguido'
concept: 'Concepto'
state: 'Estado'
- search: 'Buscar artículo'
- searchInfo: 'Puedes buscar por id'
+itemProposal: Artículos similares
+proposal:
+ substitutionAvailable: Sustitución disponible
+ notSubstitutionAvailableByPrice: Sustitución no disponible, 30% de diferencia por precio o cantidad
+ compatibility: Compatibilidad
+ title: Items de sustitución para los tickets seleccionados
+ itemFk: Item
+ longName: Nombre
+ subName: Productor
+ value5: value5
+ value6: value6
+ value7: value7
+ value8: value8
+ available: Disponible
+ minQuantity: Min. cantidad
+ price2: Precio
+ located: Ubicado
+ counter: Contador
+ difference: Diferencial
+ groupingPrice: Precio Grouping
+ itemOldPrice: Precio itemOld
+ status: Estado
+ quantityToReplace: Cantidad a reemplazar
+ replace: Sustituir
+ replaceAndConfirm: Sustituir y confirmar precio
+search: 'Buscar artículo'
+searchInfo: 'Puedes buscar por id'
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/Monitor/locale/en.yml b/src/pages/Monitor/locale/en.yml
index 21324087c..496c8761a 100644
--- a/src/pages/Monitor/locale/en.yml
+++ b/src/pages/Monitor/locale/en.yml
@@ -38,6 +38,7 @@ salesTicketsTable:
payMethod: Pay method
department: Department
packing: ITP
+ hasItemLost: Item lost
searchBar:
label: Search tickets
info: Search tickets by id or alias
diff --git a/src/pages/Monitor/locale/es.yml b/src/pages/Monitor/locale/es.yml
index 30afb1904..f6a29879f 100644
--- a/src/pages/Monitor/locale/es.yml
+++ b/src/pages/Monitor/locale/es.yml
@@ -39,6 +39,7 @@ salesTicketsTable:
payMethod: Método de pago
department: Departamento
packing: ITP
+ hasItemLost: Artículo perdido
searchBar:
label: Buscar tickets
info: Buscar tickets por identificador o alias
diff --git a/src/pages/Order/Card/CatalogFilterValueDialog.vue b/src/pages/Order/Card/CatalogFilterValueDialog.vue
index b91e7d229..d1bd48c9e 100644
--- a/src/pages/Order/Card/CatalogFilterValueDialog.vue
+++ b/src/pages/Order/Card/CatalogFilterValueDialog.vue
@@ -110,7 +110,7 @@ const getSelectedTagValues = async (tag) => {
{
});
addressList.value = data;
if (addressList.value?.length === 1) {
- state.get(ORDER_MODEL).addressFk = addressList.value[0].id;
+ state.get('Order').addressFk = addressList.value[0].id;
}
};
@@ -91,9 +90,8 @@ const onClientChange = async (clientId) => {
import VnCardBeta from 'components/common/VnCardBeta.vue';
import OrderDescriptor from 'pages/Order/Card/OrderDescriptor.vue';
+import filter from './OrderFilter.js';
diff --git a/src/pages/Order/Card/OrderCatalogFilter.vue b/src/pages/Order/Card/OrderCatalogFilter.vue
index 262f503fd..76e608983 100644
--- a/src/pages/Order/Card/OrderCatalogFilter.vue
+++ b/src/pages/Order/Card/OrderCatalogFilter.vue
@@ -184,7 +184,7 @@ function addOrder(value, field, params) {
{{
t(
categoryList.find((c) => c.id == customTag.value)?.name ||
- ''
+ '',
)
}}
@@ -296,7 +296,7 @@ function addOrder(value, field, params) {
state.get('orderData'));
+const orderData = computed(() => state.get('Order'));
const prices = ref((props.item.prices || []).map((item) => ({ ...item, quantity: 0 })));
const isLoading = ref(false);
@@ -39,11 +39,11 @@ const addToOrder = async () => {
});
const { data: orderTotal } = await axios.get(
- `Orders/${Number(route.params.id)}/getTotal`
+ `Orders/${Number(route.params.id)}/getTotal`,
);
state.set('orderTotal', orderTotal);
- state.set('orderData', {
+ state.set('Order', {
...orderData.value,
items,
});
@@ -56,7 +56,7 @@ const canAddToOrder = () => {
if (canAddToOrder) {
const excedQuantity = prices.value.reduce(
(acc, { quantity }) => acc + quantity,
- 0
+ 0,
);
if (excedQuantity > props.item.available) {
canAddToOrder = false;
diff --git a/src/pages/Order/Card/OrderDescriptor.vue b/src/pages/Order/Card/OrderDescriptor.vue
index 0d5f0146f..0d18864dc 100644
--- a/src/pages/Order/Card/OrderDescriptor.vue
+++ b/src/pages/Order/Card/OrderDescriptor.vue
@@ -4,8 +4,7 @@ import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n';
import { toCurrency, toDate } from 'src/filters';
import { useState } from 'src/composables/useState';
-import useCardDescription from 'src/composables/useCardDescription';
-
+import filter from './OrderFilter.js';
import CardDescriptor from 'components/ui/CardDescriptor.vue';
import VnLv from 'src/components/ui/VnLv.vue';
import FetchData from 'components/FetchData.vue';
@@ -24,44 +23,15 @@ const $props = defineProps({
const route = useRoute();
const state = useState();
const { t } = useI18n();
-const data = ref(useCardDescription());
const getTotalRef = ref();
const entityId = computed(() => {
return $props.id || route.params.id;
});
-const filter = {
- include: [
- { relation: 'agencyMode', scope: { fields: ['name'] } },
- {
- relation: 'address',
- scope: { fields: ['nickname'] },
- },
- { relation: 'rows', scope: { fields: ['id'] } },
- {
- relation: 'client',
- scope: {
- fields: [
- 'salesPersonFk',
- 'name',
- 'isActive',
- 'isFreezed',
- 'isTaxDataChecked',
- ],
- include: {
- relation: 'salesPersonUser',
- scope: { fields: ['id', 'name'] },
- },
- },
- },
- ],
-};
-
const setData = (entity) => {
if (!entity) return;
getTotalRef.value && getTotalRef.value.fetch();
- data.value = useCardDescription(entity?.client?.name, entity?.id);
state.set('orderTotal', total);
};
@@ -87,11 +57,9 @@ const total = ref(0);
ref="descriptor"
:url="`Orders/${entityId}`"
:filter="filter"
- module="Order"
- :title="data.title"
- :subtitle="data.subtitle"
+ title="client.name"
@on-fetch="setData"
- data-key="orderData"
+ data-key="Order"
>
diff --git a/src/pages/Order/Card/OrderSummary.vue b/src/pages/Order/Card/OrderSummary.vue
index a289688e4..a4bdb2881 100644
--- a/src/pages/Order/Card/OrderSummary.vue
+++ b/src/pages/Order/Card/OrderSummary.vue
@@ -27,7 +27,7 @@ const $props = defineProps({
const entityId = computed(() => $props.id || route.params.id);
const summary = ref();
const quasar = useQuasar();
-const descriptorData = useArrayData('orderData');
+const descriptorData = useArrayData('Order');
const detailsColumns = ref([
{
name: 'item',
diff --git a/src/pages/Order/OrderList.vue b/src/pages/Order/OrderList.vue
index 21cb5ed7e..40990f329 100644
--- a/src/pages/Order/OrderList.vue
+++ b/src/pages/Order/OrderList.vue
@@ -71,8 +71,9 @@ const columns = computed(() => [
format: (row) => row?.name,
},
{
- align: 'left',
+ align: 'center',
name: 'isConfirmed',
+ component: 'checkbox',
label: t('module.isConfirmed'),
},
{
@@ -95,7 +96,9 @@ const columns = computed(() => [
columnField: {
component: null,
},
- style: 'color="positive"',
+ style: () => {
+ return { color: 'positive' };
+ },
},
{
align: 'left',
diff --git a/src/pages/Route/Agency/AgencyList.vue b/src/pages/Route/Agency/AgencyList.vue
index 4322b9bc8..5c2904bf3 100644
--- a/src/pages/Route/Agency/AgencyList.vue
+++ b/src/pages/Route/Agency/AgencyList.vue
@@ -51,7 +51,6 @@ const columns = computed(() => [
name: 'isAnyVolumeAllowed',
component: 'checkbox',
cardVisible: true,
- disable: true,
},
{
align: 'right',
@@ -72,7 +71,7 @@ const columns = computed(() => [
:data-key
:columns="columns"
prefix="agency"
- :right-filter="false"
+ :right-filter="true"
:array-data-props="{
url: 'Agencies',
order: 'name',
@@ -83,6 +82,7 @@ const columns = computed(() => [
(warehouses = data)"
auto-load
/>
-
+
diff --git a/src/pages/Route/Agency/Card/AgencyCard.vue b/src/pages/Route/Agency/Card/AgencyCard.vue
index 35685790a..7dc31f8ba 100644
--- a/src/pages/Route/Agency/Card/AgencyCard.vue
+++ b/src/pages/Route/Agency/Card/AgencyCard.vue
@@ -3,5 +3,5 @@ import AgencyDescriptor from 'pages/Route/Agency/Card/AgencyDescriptor.vue';
import VnCardBeta from 'src/components/common/VnCardBeta.vue';
-
+
diff --git a/src/pages/Route/Agency/Card/AgencyDescriptor.vue b/src/pages/Route/Agency/Card/AgencyDescriptor.vue
index b9772037c..a0472c6c3 100644
--- a/src/pages/Route/Agency/Card/AgencyDescriptor.vue
+++ b/src/pages/Route/Agency/Card/AgencyDescriptor.vue
@@ -22,7 +22,6 @@ const card = computed(() => store.data);
-
+
import RouteDescriptor from 'pages/Route/Card/RouteDescriptor.vue';
import VnCardBeta from 'src/components/common/VnCardBeta.vue';
+import filter from './RouteFilter.js';
diff --git a/src/pages/Route/Card/RouteDescriptor.vue b/src/pages/Route/Card/RouteDescriptor.vue
index 68c08b821..503cd1941 100644
--- a/src/pages/Route/Card/RouteDescriptor.vue
+++ b/src/pages/Route/Card/RouteDescriptor.vue
@@ -1,13 +1,14 @@
-
-
-
-
+
+
+
-
+
diff --git a/src/pages/Route/Card/RouteFilter.js b/src/pages/Route/Card/RouteFilter.js
new file mode 100644
index 000000000..90ee71bf7
--- /dev/null
+++ b/src/pages/Route/Card/RouteFilter.js
@@ -0,0 +1,39 @@
+export default {
+ fields: [
+ 'code',
+ 'id',
+ 'workerFk',
+ 'agencyModeFk',
+ 'created',
+ 'm3',
+ 'warehouseFk',
+ 'description',
+ 'vehicleFk',
+ 'kmStart',
+ 'kmEnd',
+ 'started',
+ 'finished',
+ 'cost',
+ 'isOk',
+ ],
+ include: [
+ { relation: 'agencyMode', scope: { fields: ['id', 'name'] } },
+ {
+ relation: 'vehicle',
+ scope: { fields: ['id', 'm3'] },
+ },
+ {
+ relation: 'worker',
+ scope: {
+ fields: ['id'],
+ include: {
+ relation: 'user',
+ scope: {
+ fields: ['id'],
+ include: { relation: 'emailUser', scope: { fields: ['email'] } },
+ },
+ },
+ },
+ },
+ ],
+};
diff --git a/src/pages/Route/Card/RouteFilter.vue b/src/pages/Route/Card/RouteFilter.vue
index 72bfed1da..21858102b 100644
--- a/src/pages/Route/Card/RouteFilter.vue
+++ b/src/pages/Route/Card/RouteFilter.vue
@@ -100,7 +100,7 @@ const emit = defineEmits(['search']);
{
if (isNew) {
axios.post(`Routes/${response?.id}/updateWorkCenter`);
@@ -89,11 +44,10 @@ const onSave = (data, response) => {
sort-by="id ASC"
/>
{
{
router.push({ name: 'RoadmapSummary', params: { id: response?.id } });
};
diff --git a/src/pages/Route/Roadmap/RoadmapCard.vue b/src/pages/Route/Roadmap/RoadmapCard.vue
index 0b81de673..48ba516a1 100644
--- a/src/pages/Route/Roadmap/RoadmapCard.vue
+++ b/src/pages/Route/Roadmap/RoadmapCard.vue
@@ -3,5 +3,5 @@ import VnCardBeta from 'components/common/VnCardBeta.vue';
import RoadmapDescriptor from 'pages/Route/Roadmap/RoadmapDescriptor.vue';
-
+
diff --git a/src/pages/Route/Roadmap/RoadmapDescriptor.vue b/src/pages/Route/Roadmap/RoadmapDescriptor.vue
index 788173688..baa864a15 100644
--- a/src/pages/Route/Roadmap/RoadmapDescriptor.vue
+++ b/src/pages/Route/Roadmap/RoadmapDescriptor.vue
@@ -1,13 +1,13 @@
-
+
diff --git a/src/pages/Route/Roadmap/RoadmapFilter.js b/src/pages/Route/Roadmap/RoadmapFilter.js
new file mode 100644
index 000000000..0ae890363
--- /dev/null
+++ b/src/pages/Route/Roadmap/RoadmapFilter.js
@@ -0,0 +1,3 @@
+export default {
+ include: [{ relation: 'supplier' }],
+};
diff --git a/src/pages/Route/Roadmap/RoadmapStops.vue b/src/pages/Route/Roadmap/RoadmapStops.vue
index d8215ea49..e4085d572 100644
--- a/src/pages/Route/Roadmap/RoadmapStops.vue
+++ b/src/pages/Route/Roadmap/RoadmapStops.vue
@@ -68,7 +68,7 @@ const updateDefaultStop = (data) => {
@@ -76,7 +75,7 @@ const filter = {
diff --git a/src/pages/Route/RouteExtendedList.vue b/src/pages/Route/RouteExtendedList.vue
index 221fc4754..46bc1a690 100644
--- a/src/pages/Route/RouteExtendedList.vue
+++ b/src/pages/Route/RouteExtendedList.vue
@@ -3,7 +3,7 @@ import { computed, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { useSummaryDialog } from 'src/composables/useSummaryDialog';
import { useQuasar } from 'quasar';
-import { toDate } from 'src/filters';
+import { dashIfEmpty, toDate, toHour } from 'src/filters';
import { useRouter } from 'vue-router';
import { usePrintService } from 'src/composables/usePrintService';
@@ -38,7 +38,7 @@ const routeFilter = {
};
const columns = computed(() => [
{
- align: 'left',
+ align: 'center',
name: 'id',
label: 'Id',
chip: {
@@ -48,7 +48,7 @@ const columns = computed(() => [
columnFilter: false,
},
{
- align: 'left',
+ align: 'center',
name: 'workerFk',
label: t('route.Worker'),
create: true,
@@ -68,10 +68,10 @@ const columns = computed(() => [
},
useLike: false,
cardVisible: true,
- format: (row, dashIfEmpty) => dashIfEmpty(row.travelRef),
+ format: (row, dashIfEmpty) => dashIfEmpty(row.workerUserName),
},
{
- align: 'left',
+ align: 'center',
name: 'agencyModeFk',
label: t('route.Agency'),
isTitle: true,
@@ -87,17 +87,17 @@ const columns = computed(() => [
},
},
columnClass: 'expand',
+ format: (row, dashIfEmpty) => dashIfEmpty(row.agencyName),
},
{
- align: 'left',
+ align: 'center',
name: 'vehicleFk',
label: t('route.Vehicle'),
cardVisible: true,
create: true,
component: 'select',
attrs: {
- url: 'vehicles',
- fields: ['id', 'numberPlate'],
+ url: 'vehicles/active',
optionLabel: 'numberPlate',
optionFilterValue: 'numberPlate',
find: {
@@ -108,29 +108,31 @@ const columns = computed(() => [
columnFilter: {
inWhere: true,
},
+ format: (row, dashIfEmpty) => dashIfEmpty(row.vehiclePlateNumber),
},
{
- align: 'left',
+ align: 'center',
name: 'dated',
label: t('route.Date'),
columnFilter: false,
cardVisible: true,
create: true,
component: 'date',
- format: ({ date }) => toDate(date),
+ format: ({ dated }, dashIfEmpty) =>
+ dated === '0000-00-00' ? dashIfEmpty(null) : toDate(dated),
},
{
- align: 'left',
+ align: 'center',
name: 'from',
label: t('route.From'),
visible: false,
cardVisible: true,
create: true,
component: 'date',
- format: ({ date }) => toDate(date),
+ format: ({ from }) => toDate(from),
},
{
- align: 'left',
+ align: 'center',
name: 'to',
label: t('route.To'),
visible: false,
@@ -147,18 +149,20 @@ const columns = computed(() => [
columnClass: 'shrink',
},
{
- align: 'left',
+ align: 'center',
name: 'started',
label: t('route.hourStarted'),
component: 'time',
columnFilter: false,
+ format: ({ started }) => toHour(started),
},
{
- align: 'left',
+ align: 'center',
name: 'finished',
label: t('route.hourFinished'),
component: 'time',
columnFilter: false,
+ format: ({ finished }) => toHour(finished),
},
{
align: 'center',
@@ -177,7 +181,7 @@ const columns = computed(() => [
visible: false,
},
{
- align: 'left',
+ align: 'center',
name: 'description',
label: t('route.Description'),
isTitle: true,
@@ -186,7 +190,7 @@ const columns = computed(() => [
field: 'description',
},
{
- align: 'left',
+ align: 'center',
name: 'isOk',
label: t('route.Served'),
component: 'checkbox',
@@ -300,60 +304,62 @@ const openTicketsDialog = (id) => {
-
-
-
- {{ t('route.Clone Selected Routes') }}
-
-
- {{ t('route.Download selected routes as PDF') }}
-
-
- {{ t('route.Mark as served') }}
-
-
-
+
+
+
+
+ {{ t('route.Clone Selected Routes') }}
+
+
+ {{ t('route.Download selected routes as PDF') }}
+
+
+ {{ t('route.Mark as served') }}
+
+
+
+
diff --git a/src/pages/Route/RouteList.vue b/src/pages/Route/RouteList.vue
index bc3227f6c..9dad8ba22 100644
--- a/src/pages/Route/RouteList.vue
+++ b/src/pages/Route/RouteList.vue
@@ -38,6 +38,17 @@ const columns = computed(() => [
align: 'left',
name: 'workerFk',
label: t('route.Worker'),
+ component: 'select',
+ attrs: {
+ url: 'Workers/activeWithInheritedRole',
+ fields: ['id', 'name'],
+ useLike: false,
+ optionFilter: 'firstName',
+ find: {
+ value: 'workerFk',
+ label: 'workerUserName',
+ },
+ },
create: true,
cardVisible: true,
format: (row, dashIfEmpty) => dashIfEmpty(row.travelRef),
@@ -48,6 +59,15 @@ const columns = computed(() => [
name: 'agencyName',
label: t('route.Agency'),
cardVisible: true,
+ component: 'select',
+ attrs: {
+ url: 'agencyModes',
+ fields: ['id', 'name'],
+ find: {
+ value: 'agencyModeFk',
+ label: 'agencyName',
+ },
+ },
create: true,
columnClass: 'expand',
columnFilter: false,
@@ -57,6 +77,17 @@ const columns = computed(() => [
name: 'vehiclePlateNumber',
label: t('route.Vehicle'),
cardVisible: true,
+ component: 'select',
+ attrs: {
+ url: 'vehicles',
+ fields: ['id', 'numberPlate'],
+ optionLabel: 'numberPlate',
+ optionFilterValue: 'numberPlate',
+ find: {
+ value: 'vehicleFk',
+ label: 'vehiclePlateNumber',
+ },
+ },
create: true,
columnFilter: false,
},
diff --git a/src/pages/Route/RouteTickets.vue b/src/pages/Route/RouteTickets.vue
index 1416f77ce..adc7dfdaa 100644
--- a/src/pages/Route/RouteTickets.vue
+++ b/src/pages/Route/RouteTickets.vue
@@ -120,8 +120,8 @@ const deletePriorities = async () => {
try {
await Promise.all(
selectedRows.value.map((ticket) =>
- axios.patch(`Tickets/${ticket?.id}/`, { priority: null })
- )
+ axios.patch(`Tickets/${ticket?.id}/`, { priority: null }),
+ ),
);
} finally {
refreshKey.value++;
@@ -132,8 +132,8 @@ const setOrderedPriority = async () => {
try {
await Promise.all(
ticketList.value.map((ticket, index) =>
- axios.patch(`Tickets/${ticket?.id}/`, { priority: index + 1 })
- )
+ axios.patch(`Tickets/${ticket?.id}/`, { priority: index + 1 }),
+ ),
);
} finally {
refreshKey.value++;
@@ -162,7 +162,7 @@ const setHighestPriority = async (ticket, ticketList) => {
const goToBuscaman = async (ticket = null) => {
await openBuscaman(
routeEntity.value?.vehicleFk,
- ticket ? [ticket] : selectedRows.value
+ ticket ? [ticket] : selectedRows.value,
);
};
@@ -393,7 +393,13 @@ const openSmsDialog = async () => {
-
+
{{ t('Add ticket') }}
diff --git a/src/pages/Route/Vehicle/Card/VehicleBasicData.vue b/src/pages/Route/Vehicle/Card/VehicleBasicData.vue
new file mode 100644
index 000000000..e78bc6edd
--- /dev/null
+++ b/src/pages/Route/Vehicle/Card/VehicleBasicData.vue
@@ -0,0 +1,162 @@
+
+
+ (warehouses = data)"
+ auto-load
+ />
+ (companies = data)"
+ auto-load
+ />
+ (countries = data)"
+ auto-load
+ />
+ (fuelTypes = data)"
+ auto-load
+ />
+ (deliveryPoints = data)"
+ auto-load
+ />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/pages/Route/Vehicle/Card/VehicleCard.vue b/src/pages/Route/Vehicle/Card/VehicleCard.vue
new file mode 100644
index 000000000..f59420aa2
--- /dev/null
+++ b/src/pages/Route/Vehicle/Card/VehicleCard.vue
@@ -0,0 +1,13 @@
+
+
+
+
diff --git a/src/pages/Route/Vehicle/Card/VehicleDescriptor.vue b/src/pages/Route/Vehicle/Card/VehicleDescriptor.vue
new file mode 100644
index 000000000..d9a2434ab
--- /dev/null
+++ b/src/pages/Route/Vehicle/Card/VehicleDescriptor.vue
@@ -0,0 +1,49 @@
+
+
+
+
+ {
+ try {
+ await axios.delete(`Vehicles/${entity.id}`);
+ notify('vehicle.remove', 'positive');
+ $router.push({ name: 'VehicleList' });
+ } catch (e) {
+ throw e;
+ }
+ }
+ "
+ >
+
+ {{ $t('vehicle.delete') }}
+
+
+
+
+
+
+
+
+
+
+
+
+es:
+ Vehicle removed: Vehículo eliminado
+
diff --git a/src/pages/Route/Vehicle/Card/VehicleSummary.vue b/src/pages/Route/Vehicle/Card/VehicleSummary.vue
new file mode 100644
index 000000000..981870cb2
--- /dev/null
+++ b/src/pages/Route/Vehicle/Card/VehicleSummary.vue
@@ -0,0 +1,127 @@
+
+
+
+
+ {{ entity.id }} - {{ entity.numberPlate }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ entity.supplier?.name }}
+
+
+
+
+
+
+
+ {{ entity.supplierCooler?.name }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ $t('globals.download') }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/pages/Route/Vehicle/VehicleFilter.js b/src/pages/Route/Vehicle/VehicleFilter.js
new file mode 100644
index 000000000..cbf5cc621
--- /dev/null
+++ b/src/pages/Route/Vehicle/VehicleFilter.js
@@ -0,0 +1,76 @@
+export default {
+ fields: [
+ 'id',
+ 'description',
+ 'isActive',
+ 'isKmTruckRate',
+ 'warehouseFk',
+ 'companyFk',
+ 'numberPlate',
+ 'chassis',
+ 'supplierFk',
+ 'supplierCoolerFk',
+ 'tradeMark',
+ 'fuelTypeFk',
+ 'import',
+ 'importCooler',
+ 'vin',
+ 'model',
+ 'ppeFk',
+ 'countryCodeFk',
+ 'leasing',
+ 'bankPolicyFk',
+ 'vehicleTypeFk',
+ 'deliveryPointFk',
+ ],
+ include: [
+ {
+ relation: 'warehouse',
+ scope: {
+ fields: ['id', 'name'],
+ },
+ },
+ {
+ relation: 'company',
+ scope: {
+ fields: ['id', 'code'],
+ },
+ },
+ {
+ relation: 'supplier',
+ scope: {
+ fields: ['id', 'name'],
+ },
+ },
+ {
+ relation: 'supplierCooler',
+ scope: {
+ fields: ['id', 'name'],
+ },
+ },
+ {
+ relation: 'fuelType',
+ scope: {
+ fields: ['id', 'name'],
+ },
+ },
+ {
+ relation: 'bankPolicy',
+ scope: {
+ fields: ['id', 'ref', 'dmsFk'],
+ },
+ },
+ {
+ relation: 'ppe',
+ scope: {
+ fields: ['id'],
+ },
+ },
+ {
+ relation: 'deliveryPoint',
+ scope: {
+ fields: ['id', 'name'],
+ },
+ },
+ ],
+};
diff --git a/src/pages/Route/Vehicle/VehicleList.vue b/src/pages/Route/Vehicle/VehicleList.vue
new file mode 100644
index 000000000..e5b945010
--- /dev/null
+++ b/src/pages/Route/Vehicle/VehicleList.vue
@@ -0,0 +1,224 @@
+
+
+ (warehouses = data)"
+ auto-load
+ />
+ (companies = data)"
+ auto-load
+ />
+ (countries = data)"
+ auto-load
+ />
+ (vehicleStates = data)"
+ auto-load
+ />
+ (vehicleTypes = data)"
+ auto-load
+ />
+
+
+
+
+
+
+ {{ $t('globals.inactive') }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/pages/Route/Vehicle/locale/en.yml b/src/pages/Route/Vehicle/locale/en.yml
new file mode 100644
index 000000000..c92022f9d
--- /dev/null
+++ b/src/pages/Route/Vehicle/locale/en.yml
@@ -0,0 +1,20 @@
+vehicle:
+ tradeMark: Trade Mark
+ numberPlate: Nº Plate
+ chassis: Chassis
+ leasing: Leasing
+ isKmTruckRate: Trailer
+ delete: Delete Vehicle
+ supplierCooler: Supplier Cooler
+ vin: VIN
+ ppe: Ppe
+ isActive: Active
+ nLeasing: Nº Leasing
+ create: Create Vehicle
+ amountCooler: Amount cooler
+ remove: Vehicle removed
+ search: Search Vehicle
+ searchInfo: Search by id or number plate
+ params:
+ vehicleTypeFk: Type
+ vehicleStateFk: State
diff --git a/src/pages/Route/Vehicle/locale/es.yml b/src/pages/Route/Vehicle/locale/es.yml
new file mode 100644
index 000000000..c878f97ac
--- /dev/null
+++ b/src/pages/Route/Vehicle/locale/es.yml
@@ -0,0 +1,20 @@
+vehicle:
+ tradeMark: Marca
+ numberPlate: Matrícula
+ chassis: Nº de bastidor
+ leasing: Leasing
+ isKmTruckRate: Trailer
+ delete: Eliminar vehículo
+ supplierCooler: Proveedor Frío
+ vin: VIN
+ ppe: Nº Inmovilizado
+ create: Crear vehículo
+ amountCooler: Importe frío
+ isActive: Activo
+ nLeasing: Nº leasing
+ remove: Vehículo eliminado
+ search: Buscar Vehículo
+ searchInfo: Buscar por id o matrícula
+ params:
+ vehicleTypeFk: Tipo
+ vehicleStateFk: Estado
diff --git a/src/pages/Shelving/Card/ShelvingCard.vue b/src/pages/Shelving/Card/ShelvingCard.vue
index 41a0db33c..9e0ac8ad2 100644
--- a/src/pages/Shelving/Card/ShelvingCard.vue
+++ b/src/pages/Shelving/Card/ShelvingCard.vue
@@ -1,12 +1,14 @@
diff --git a/src/pages/Shelving/Card/ShelvingDescriptor.vue b/src/pages/Shelving/Card/ShelvingDescriptor.vue
index b1ff4a8ae..5e618aa7f 100644
--- a/src/pages/Shelving/Card/ShelvingDescriptor.vue
+++ b/src/pages/Shelving/Card/ShelvingDescriptor.vue
@@ -1,12 +1,12 @@
-
diff --git a/src/pages/Shelving/Card/ShelvingFilter.js b/src/pages/Shelving/Card/ShelvingFilter.js
new file mode 100644
index 000000000..e302e1b9c
--- /dev/null
+++ b/src/pages/Shelving/Card/ShelvingFilter.js
@@ -0,0 +1,15 @@
+export default {
+ include: [
+ {
+ relation: 'worker',
+ scope: {
+ fields: ['id'],
+ include: {
+ relation: 'user',
+ scope: { fields: ['nickname'] },
+ },
+ },
+ },
+ { relation: 'parking' },
+ ],
+};
diff --git a/src/pages/Shelving/Card/ShelvingForm.vue b/src/pages/Shelving/Card/ShelvingForm.vue
index 3bbd94a0a..078058342 100644
--- a/src/pages/Shelving/Card/ShelvingForm.vue
+++ b/src/pages/Shelving/Card/ShelvingForm.vue
@@ -1,5 +1,4 @@
diff --git a/src/pages/Shelving/Card/ShelvingSummary.vue b/src/pages/Shelving/Card/ShelvingSummary.vue
index 39fa4639f..f89ff4d78 100644
--- a/src/pages/Shelving/Card/ShelvingSummary.vue
+++ b/src/pages/Shelving/Card/ShelvingSummary.vue
@@ -1,10 +1,10 @@
@@ -41,7 +25,7 @@ const filter = {
ref="summary"
:url="`Shelvings/${entityId}`"
:filter="filter"
- data-key="ShelvingSummary"
+ data-key="Shelving"
>
{{ entity.code }}
@@ -58,16 +42,19 @@ const filter = {
class="header header-link"
:to="{ name: 'ShelvingBasicData', params: { id: entityId } }"
>
- {{ t('globals.pageTitles.basicData') }}
+ {{ $t('globals.pageTitles.basicData') }}
-
+
-
-
+
+
diff --git a/src/pages/Parking/Card/ParkingBasicData.vue b/src/pages/Shelving/Parking/Card/ParkingBasicData.vue
similarity index 68%
rename from src/pages/Parking/Card/ParkingBasicData.vue
rename to src/pages/Shelving/Parking/Card/ParkingBasicData.vue
index 550a0684e..3de358002 100644
--- a/src/pages/Parking/Card/ParkingBasicData.vue
+++ b/src/pages/Shelving/Parking/Card/ParkingBasicData.vue
@@ -1,16 +1,11 @@
diff --git a/src/pages/Parking/Card/ParkingDescriptor.vue b/src/pages/Shelving/Parking/Card/ParkingDescriptor.vue
similarity index 58%
rename from src/pages/Parking/Card/ParkingDescriptor.vue
rename to src/pages/Shelving/Parking/Card/ParkingDescriptor.vue
index d36ea16fc..46c9f8ea0 100644
--- a/src/pages/Parking/Card/ParkingDescriptor.vue
+++ b/src/pages/Shelving/Parking/Card/ParkingDescriptor.vue
@@ -1,10 +1,9 @@
-
-
-
+
+
+
diff --git a/src/pages/Shelving/Parking/Card/ParkingFilter.js b/src/pages/Shelving/Parking/Card/ParkingFilter.js
new file mode 100644
index 000000000..fd1855c45
--- /dev/null
+++ b/src/pages/Shelving/Parking/Card/ParkingFilter.js
@@ -0,0 +1,4 @@
+export default {
+ fields: ['id', 'sectorFk', 'code', 'pickingOrder', 'row', 'column'],
+ include: [{ relation: 'sector', scope: { fields: ['id', 'description'] } }],
+};
diff --git a/src/pages/Parking/Card/ParkingLog.vue b/src/pages/Shelving/Parking/Card/ParkingLog.vue
similarity index 100%
rename from src/pages/Parking/Card/ParkingLog.vue
rename to src/pages/Shelving/Parking/Card/ParkingLog.vue
diff --git a/src/pages/Parking/Card/ParkingSummary.vue b/src/pages/Shelving/Parking/Card/ParkingSummary.vue
similarity index 100%
rename from src/pages/Parking/Card/ParkingSummary.vue
rename to src/pages/Shelving/Parking/Card/ParkingSummary.vue
diff --git a/src/pages/Shelving/Parking/ParkingExprBuilder.js b/src/pages/Shelving/Parking/ParkingExprBuilder.js
new file mode 100644
index 000000000..16d2262c8
--- /dev/null
+++ b/src/pages/Shelving/Parking/ParkingExprBuilder.js
@@ -0,0 +1,10 @@
+export default (param, value) => {
+ switch (param) {
+ case 'code':
+ return { [param]: { like: `%${value}%` } };
+ case 'sectorFk':
+ return { [param]: value };
+ case 'search':
+ return { or: [{ code: { like: `%${value}%` } }, { id: value }] };
+ }
+};
diff --git a/src/pages/Parking/ParkingFilter.vue b/src/pages/Shelving/Parking/ParkingFilter.vue
similarity index 100%
rename from src/pages/Parking/ParkingFilter.vue
rename to src/pages/Shelving/Parking/ParkingFilter.vue
diff --git a/src/pages/Parking/ParkingList.vue b/src/pages/Shelving/Parking/ParkingList.vue
similarity index 90%
rename from src/pages/Parking/ParkingList.vue
rename to src/pages/Shelving/Parking/ParkingList.vue
index bce87126e..fe6c93ba5 100644
--- a/src/pages/Parking/ParkingList.vue
+++ b/src/pages/Shelving/Parking/ParkingList.vue
@@ -9,6 +9,7 @@ import CardList from 'components/ui/CardList.vue';
import VnLv from 'components/ui/VnLv.vue';
import ParkingFilter from './ParkingFilter.vue';
import ParkingSummary from './Card/ParkingSummary.vue';
+import exprBuilder from './ParkingExprBuilder.js';
import VnSection from 'src/components/common/VnSection.vue';
const stateStore = useStateStore();
@@ -23,19 +24,7 @@ onUnmounted(() => (stateStore.rightDrawer = false));
const filter = {
fields: ['id', 'sectorFk', 'code', 'pickingOrder'],
};
-
-function exprBuilder(param, value) {
- switch (param) {
- case 'code':
- return { [param]: { like: `%${value}%` } };
- case 'sectorFk':
- return { [param]: value };
- case 'search':
- return { or: [{ code: { like: `%${value}%` } }, { id: value }] };
- }
-}
-
{
+ switch (param) {
+ case 'search':
+ return { code: { like: `%${value}%` } };
+ case 'parkingFk':
+ case 'userFk':
+ case 'isRecyclable':
+ return { [param]: value };
+ }
+};
diff --git a/src/pages/Shelving/ShelvingList.vue b/src/pages/Shelving/ShelvingList.vue
index cf158e76b..4e0c21100 100644
--- a/src/pages/Shelving/ShelvingList.vue
+++ b/src/pages/Shelving/ShelvingList.vue
@@ -1,6 +1,5 @@
@@ -62,18 +50,18 @@ function exprBuilder(param, value) {
>
@@ -84,9 +72,9 @@ function exprBuilder(param, value) {
-
+
- {{ t('shelving.list.newShelving') }}
+ {{ $t('shelving.list.newShelving') }}
diff --git a/src/pages/Supplier/Card/SupplierAccounts.vue b/src/pages/Supplier/Card/SupplierAccounts.vue
index 4a6901d1d..365eb67a1 100644
--- a/src/pages/Supplier/Card/SupplierAccounts.vue
+++ b/src/pages/Supplier/Card/SupplierAccounts.vue
@@ -71,7 +71,7 @@ function bankEntityFilter(val, update) {
filteredBankEntitiesOptions.value = bankEntitiesOptions.value.filter(
(bank) =>
bank.bic.toLowerCase().startsWith(needle) ||
- bank.name.toLowerCase().includes(needle)
+ bank.name.toLowerCase().includes(needle),
);
});
}
@@ -170,7 +170,7 @@ function bankEntityFilter(val, update) {
{{
t(
- 'Name of the bank account holder if different from the provider'
+ 'Name of the bank account holder if different from the provider',
)
}}
@@ -194,7 +194,7 @@ function bankEntityFilter(val, update) {
{
icon="add"
color="primary"
@click="redirectToCreateView()"
- shortcut="+"
+ v-shortcut="'+'"
/>
{{ t('New address') }}
diff --git a/src/pages/Supplier/Card/SupplierAgencyTerm.vue b/src/pages/Supplier/Card/SupplierAgencyTerm.vue
index 99b672cc4..ab21f1f76 100644
--- a/src/pages/Supplier/Card/SupplierAgencyTerm.vue
+++ b/src/pages/Supplier/Card/SupplierAgencyTerm.vue
@@ -114,7 +114,7 @@ const redirectToCreateView = () => {
icon="add"
color="primary"
@click="redirectToCreateView()"
- shortcut="+"
+ v-shortcut="'+'"
/>
{{ t('supplier.agencyTerms.addRow') }}
diff --git a/src/pages/Supplier/Card/SupplierBasicData.vue b/src/pages/Supplier/Card/SupplierBasicData.vue
index f6c13b7af..631700a4a 100644
--- a/src/pages/Supplier/Card/SupplierBasicData.vue
+++ b/src/pages/Supplier/Card/SupplierBasicData.vue
@@ -19,9 +19,8 @@ const companySizes = [
-import VnCard from 'components/common/VnCard.vue';
import SupplierDescriptor from './SupplierDescriptor.vue';
-import SupplierListFilter from '../SupplierListFilter.vue';
+import VnCardBeta from 'src/components/common/VnCardBeta.vue';
+import filter from './SupplierFilter.js';
-
diff --git a/src/pages/Supplier/Card/SupplierConsumption.vue b/src/pages/Supplier/Card/SupplierConsumption.vue
index 8a7021fb3..718de95dd 100644
--- a/src/pages/Supplier/Card/SupplierConsumption.vue
+++ b/src/pages/Supplier/Card/SupplierConsumption.vue
@@ -16,6 +16,7 @@ import axios from 'axios';
import { useStateStore } from 'stores/useStateStore';
import { useState } from 'src/composables/useState';
import { useArrayData } from 'composables/useArrayData';
+import RightMenu from 'src/components/common/RightMenu.vue';
const state = useState();
const stateStore = useStateStore();
@@ -173,59 +174,59 @@ onMounted(async () => {
-
-
+
+
-
-
-
-
-
- {{ t('supplier.consumption.entry') }}:
- {{ row.id }}
-
-
- {{ t('globals.date') }}:
- {{ toDate(row.shipped) }}
-
- {{ t('globals.reference') }}:
- {{ row.invoiceNumber }}
-
-
-
-
- {{ buy.itemName }}
-
-
+
+
+
+
+
+
+ {{ t('supplier.consumption.entry') }}:
+ {{ row.id }}
+
+
+ {{ t('globals.date') }}:
+ {{ toDate(row.shipped) }}
+
+ {{ t('globals.reference') }}:
+ {{ row.invoiceNumber }}
+
+
+
+
+ {{ buy.itemName }}
+
+
-
- {{ buy.subName }}
-
-
- {{ dashIfEmpty(buy.quantity) }}
- {{ dashIfEmpty(buy.price) }}
- {{ dashIfEmpty(buy.total) }}
-
-
-
- {{ t('Total entry') }}:
- {{ row.total }} €
-
-
- {{ t('Total stems') }}:
- {{ row.quantity }}
-
-
-
-
-
+
+ {{ buy.subName }}
+
+
+ {{ dashIfEmpty(buy.quantity) }}
+ {{ dashIfEmpty(buy.price) }}
+ {{ dashIfEmpty(buy.total) }}
+
+
+
+ {{ t('Total entry') }}:
+ {{ row.total }} €
+
+
+ {{ t('Total stems') }}:
+ {{ row.quantity }}
+
+
+
+
+
+es:
+ Sales to transfer: Líneas a transferir
+ Destination ticket: Ticket destinatario
+
diff --git a/src/pages/Ticket/Card/TicketSummary.vue b/src/pages/Ticket/Card/TicketSummary.vue
index 999240b7c..5df08b881 100644
--- a/src/pages/Ticket/Card/TicketSummary.vue
+++ b/src/pages/Ticket/Card/TicketSummary.vue
@@ -20,6 +20,7 @@ import ZoneDescriptorProxy from 'src/pages/Zone/Card/ZoneDescriptorProxy.vue';
import VnSelect from 'src/components/common/VnSelect.vue';
import VnToSummary from 'src/components/ui/VnToSummary.vue';
import TicketDescriptorMenu from './TicketDescriptorMenu.vue';
+import TicketProblems from 'src/components/TicketProblems.vue';
const route = useRoute();
const { notify } = useNotify();
@@ -40,7 +41,7 @@ const editableStates = ref([]);
const ticketUrl = ref();
const grafanaUrl = 'https://grafana.verdnatura.es';
const stateBtnDropdownRef = ref();
-const descriptorData = useArrayData('ticketData');
+const descriptorData = useArrayData('Ticket');
onMounted(async () => {
ticketUrl.value = (await getUrl('ticket/')) + entityId.value + '/';
@@ -311,83 +312,7 @@ onMounted(async () => {
-
-
- {{ t('ticket.summary.claim') }}:
- {{ props.row.claim.claimFk }}
-
-
-
-
- {{ t('ticket.summary.claim') }}:
- {{ props.row.claimBeginning.claimFk }}
-
-
-
-
- {{ t('globals.visible') }}:
- {{ props.row.visible }}
-
-
-
-
- {{ t('ticket.summary.reserved') }}
-
-
-
-
- {{ t('ticket.summary.itemShortage') }}
-
-
-
-
- {{ t('ticket.summary.hasComponentLack') }}
-
-
+
diff --git a/src/pages/Ticket/Card/TicketTracking.vue b/src/pages/Ticket/Card/TicketTracking.vue
index f4b8544d3..acf464fb1 100644
--- a/src/pages/Ticket/Card/TicketTracking.vue
+++ b/src/pages/Ticket/Card/TicketTracking.vue
@@ -19,7 +19,7 @@ watch(
async (val) => {
paginateFilter.where.ticketFk = val;
paginateRef.value.fetch();
- }
+ },
);
const paginateFilter = reactive({
@@ -119,7 +119,7 @@ const openCreateModal = () => createTrackingDialogRef.value.show();
color="primary"
fab
icon="add"
- shortcut="+"
+ v-shortcut="'+'"
/>
{{ t('tracking.addState') }}
diff --git a/src/pages/Ticket/Card/TicketTransfer.vue b/src/pages/Ticket/Card/TicketTransfer.vue
index 005d74a0e..ffa964c92 100644
--- a/src/pages/Ticket/Card/TicketTransfer.vue
+++ b/src/pages/Ticket/Card/TicketTransfer.vue
@@ -1,11 +1,11 @@
-
-
-
-
-
-
-
-
-
-
- handleRowClick(row)"
- >
-
-
-
- {{ row.nickname }}
- {{ row.name }}
- {{ row.street }}
- {{ row.postalCode }}
- {{ row.city }}
-
-
- {{ row.nickname }}
- {{ row.name }}
- {{ row.street }}
- {{ row.postalCode }}
- {{ row.city }}
-
-
-
+
+
+
+
+
+
+
+
+ handleRowClick(row)"
+ :no-data-label="t('globals.noResults')"
+ :pagination="{ rowsPerPage: 0 }"
+ >
+
+
+
+ {{ row.nickname }}
+ {{ row.name }}
+ {{ row.street }}
+ {{ row.postalCode }}
+ {{ row.city }}
+
+
+ {{ row.nickname }}
+ {{ row.name }}
+ {{ row.street }}
+ {{ row.postalCode }}
+ {{ row.city }}
+
+
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
+
es:
Sales to transfer: Líneas a transferir
Destination ticket: Ticket destinatario
- Transfer to ticket: Transferir a ticket
- New ticket: Nuevo ticket
diff --git a/src/pages/Ticket/Card/TicketTransferProxy.vue b/src/pages/Ticket/Card/TicketTransferProxy.vue
new file mode 100644
index 000000000..3f3f018df
--- /dev/null
+++ b/src/pages/Ticket/Card/TicketTransferProxy.vue
@@ -0,0 +1,54 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/pages/Ticket/Card/components/split.js b/src/pages/Ticket/Card/components/split.js
new file mode 100644
index 000000000..afa1d5cd6
--- /dev/null
+++ b/src/pages/Ticket/Card/components/split.js
@@ -0,0 +1,22 @@
+import axios from 'axios';
+import notifyResults from 'src/utils/notifyResults';
+
+export default async function (data, date) {
+ const reducedData = data.reduce((acc, item) => {
+ const existing = acc.find(({ ticketFk }) => ticketFk === item.id);
+ if (existing) {
+ existing.sales.push(item.saleFk);
+ } else {
+ acc.push({ ticketFk: item.id, sales: [item.saleFk], date });
+ }
+ return acc;
+ }, []);
+
+ const promises = reducedData.map((params) => axios.post(`Tickets/split`, params));
+
+ const results = await Promise.allSettled(promises);
+
+ notifyResults(results, 'ticketFk');
+
+ return results;
+}
diff --git a/src/pages/Ticket/Negative/TicketLackDetail.vue b/src/pages/Ticket/Negative/TicketLackDetail.vue
new file mode 100644
index 000000000..dcf835d03
--- /dev/null
+++ b/src/pages/Ticket/Negative/TicketLackDetail.vue
@@ -0,0 +1,198 @@
+
+
+
+ (editableStates = data)"
+ auto-load
+ />
+ (item = data)"
+ auto-load
+ />
+
+
+ (selectedRows = value)"
+ >
+
+
+
+
+
+
+
+ {{ t('ticketSale.transferLines') }}
+
+
+
+
+
+
+ {{ t('itemProposal') }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/pages/Ticket/Negative/TicketLackFilter.vue b/src/pages/Ticket/Negative/TicketLackFilter.vue
new file mode 100644
index 000000000..3762f453d
--- /dev/null
+++ b/src/pages/Ticket/Negative/TicketLackFilter.vue
@@ -0,0 +1,175 @@
+
+
+
+ (warehouses = data)" auto-load />
+ (categoriesOptions = data)"
+ auto-load
+ />
+
+ (itemTypesOptions = data)"
+ auto-load
+ />
+
+
+
+
+ {{ t(`negative.${tag.label}`) }}
+ {{ formatFn(tag.value) }}
+
+
+
+
+
+
+ {
+ setUserParams(params);
+ }
+ "
+ />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ onCategoryChange($event, searchFn)
+ "
+ :options="categoriesOptions"
+ option-value="id"
+ option-label="name"
+ hide-selected
+ dense
+ outlined
+ rounded
+ />
+
+
+
+
+
+
+
+
+
+ {{ scope.opt?.name }}
+ {{
+ scope.opt?.category?.name
+ }}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/pages/Ticket/Negative/TicketLackList.vue b/src/pages/Ticket/Negative/TicketLackList.vue
new file mode 100644
index 000000000..d1e8b823a
--- /dev/null
+++ b/src/pages/Ticket/Negative/TicketLackList.vue
@@ -0,0 +1,227 @@
+
+
+
+
+
+
+
+
+ {{ filterRef }}
+
+
+
+ {{ row.itemFk }}
+
+
+
+
+ {{ row.longName }}
+
+
+
+
+
+
+
diff --git a/src/pages/Ticket/Negative/TicketLackTable.vue b/src/pages/Ticket/Negative/TicketLackTable.vue
new file mode 100644
index 000000000..176e8f7ad
--- /dev/null
+++ b/src/pages/Ticket/Negative/TicketLackTable.vue
@@ -0,0 +1,356 @@
+
+
+
+ (itemLack = data[0])"
+ auto-load
+ />
+ (item = data)"
+ auto-load
+ />
+
+
+
+
+
+
+
+
+
+
+ {{ item?.longName ?? item.name }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ t('negative.detail.isBasket') }}
+
+
+ {{ t('negative.detail.hasToIgnore') }}
+
+
+ {{
+ t('negative.detail.hasObservation')
+ }}
+ {{ t('negative.detail.isRookie') }}
+
+
+ {{ t('negative.detail.peticionCompra') }}
+
+
+ {{ t('negative.detail.turno') }}
+
+
+
+
+
+ {{ row.nickname }}
+
+
+
+
+
+ {{ row.id }}
+
+
+
+
+
+
+
+
+ {{ row.zoneName }}
+
+
+
+
+
+
+
+
diff --git a/src/pages/Ticket/Negative/components/ChangeItemDialog.vue b/src/pages/Ticket/Negative/components/ChangeItemDialog.vue
new file mode 100644
index 000000000..e419b85c0
--- /dev/null
+++ b/src/pages/Ticket/Negative/components/ChangeItemDialog.vue
@@ -0,0 +1,90 @@
+
+
+
+
+
+ {{ showChangeItemDialog }}
+ {{ $t('negative.detail.modal.changeItem.title') }}
+
+
+
+
+
+
+
+
+
diff --git a/src/pages/Ticket/Negative/components/ChangeQuantityDialog.vue b/src/pages/Ticket/Negative/components/ChangeQuantityDialog.vue
new file mode 100644
index 000000000..2e9aac4f0
--- /dev/null
+++ b/src/pages/Ticket/Negative/components/ChangeQuantityDialog.vue
@@ -0,0 +1,84 @@
+
+
+
+
+
+ {{ $t('negative.detail.modal.changeQuantity.title') }}
+
+
+
+
+
+
+
+
diff --git a/src/pages/Ticket/Negative/components/ChangeStateDialog.vue b/src/pages/Ticket/Negative/components/ChangeStateDialog.vue
new file mode 100644
index 000000000..1acc7e0ef
--- /dev/null
+++ b/src/pages/Ticket/Negative/components/ChangeStateDialog.vue
@@ -0,0 +1,91 @@
+
+
+
+ (editableStates = data)"
+ auto-load
+ />
+
+
+ {{ $t('negative.detail.modal.changeState.title') }}
+
+
+
+
+
+
+
+
diff --git a/src/pages/Ticket/TicketFuture.vue b/src/pages/Ticket/TicketFuture.vue
index 0d216bed4..92911cd25 100644
--- a/src/pages/Ticket/TicketFuture.vue
+++ b/src/pages/Ticket/TicketFuture.vue
@@ -1,24 +1,22 @@
- (itemPackingTypesOptions = data)"
- />
@@ -293,7 +228,7 @@ onMounted(async () => {
t(`futureTickets.moveTicketDialogSubtitle`, {
selectedTickets: selectedTickets.length,
}),
- moveTicketsFuture
+ moveTicketsFuture,
)
"
>
@@ -305,235 +240,135 @@ onMounted(async () => {
-
+
-
-
-
-
-
- {{ t('advanceTickets.origin') }}
-
-
- {{ t('advanceTickets.destination') }}
-
-
-
-
-
-
-
- {{ col.label }}
-
-
-
-
-
-
-
-
-
-
-
-
-
- {{ col.label }}
-
-
-
-
+
+
-
- {{ t('futureTickets.noVerified') }}
+
+
+ {{
+ t('advanceTickets.originAgency', {
+ agency: row.futureAgency,
+ })
+ }}
+
+
+ {{
+ t('advanceTickets.destinationAgency', {
+ agency: row.agency,
+ })
+ }}
+
-
-
- {{ t('futureTickets.purchaseRequest') }}
-
-
-
-
- {{ t('ticketSale.noVisible') }}
-
-
-
-
- {{ t('futureTickets.clientFrozen') }}
-
-
-
-
- {{ t('futureTickets.risk') }}: {{ row.risk }}
-
-
-
-
- {{ t('futureTickets.componentLack') }}
-
-
-
-
- {{ t('futureTickets.rounding') }}
-
-
-
+
+
-
-
-
- {{ row.id }}
-
-
-
+
+
+ {{ row.id }}
+
+
-
-
-
- {{ toDateTimeFormat(row.shipped) }}
-
-
+
+
+ {{ toDateTimeFormat(row.shipped) }}
+
-
-
-
- {{ row.state }}
-
-
+
+
+ {{ row.state }}
+
+ {{ dashIfEmpty(row.state) }}
-
-
-
- {{ toCurrency(row.totalWithVat || 0) }}
-
-
+
+
+ {{ toCurrency(row.totalWithVat || 0) }}
+
-
-
-
- {{ row.futureId }}
-
-
-
+
+
+ {{ row.futureId }}
+
+
-
-
-
- {{ toDateTimeFormat(row.futureShipped) }}
-
-
+
+
+ {{ toDateTimeFormat(row.futureShipped) }}
+
-
-
-
- {{ row.futureState }}
-
-
+
+
+ {{ row.futureState }}
+
-
+
diff --git a/src/pages/Ticket/TicketFutureFilter.vue b/src/pages/Ticket/TicketFutureFilter.vue
index d28b0af71..64e060a39 100644
--- a/src/pages/Ticket/TicketFutureFilter.vue
+++ b/src/pages/Ticket/TicketFutureFilter.vue
@@ -12,7 +12,7 @@ import axios from 'axios';
import { onMounted } from 'vue';
const { t } = useI18n();
-const props = defineProps({
+defineProps({
dataKey: {
type: String,
required: true,
@@ -58,7 +58,7 @@ onMounted(async () => {
auto-load
/>
diff --git a/src/pages/Ticket/TicketList.vue b/src/pages/Ticket/TicketList.vue
index 8df19c0d9..88878076d 100644
--- a/src/pages/Ticket/TicketList.vue
+++ b/src/pages/Ticket/TicketList.vue
@@ -232,7 +232,7 @@ const columns = computed(() => [
function resetAgenciesSelector(formData) {
agenciesOptions.value = [];
- if(formData) formData.agencyModeId = null;
+ if (formData) formData.agencyModeId = null;
}
function redirectToLines(id) {
@@ -240,7 +240,7 @@ function redirectToLines(id) {
window.open(url, '_blank');
}
-const onClientSelected = async (formData) => {
+const onClientSelected = async (formData) => {
resetAgenciesSelector(formData);
await fetchClient(formData);
await fetchAddresses(formData);
@@ -248,14 +248,12 @@ const onClientSelected = async (formData) => {
const fetchAvailableAgencies = async (formData) => {
resetAgenciesSelector(formData);
- const response= await getAgencies(formData, selectedClient.value);
+ const response = await getAgencies(formData, selectedClient.value);
if (!response) return;
-
- const { options, agency } = response
- if(options)
- agenciesOptions.value = options;
- if(agency)
- formData.agencyModeId = agency;
+
+ const { options, agency } = response;
+ if (options) agenciesOptions.value = options;
+ if (agency) formData.agencyModeId = agency;
};
const fetchClient = async (formData) => {
@@ -330,7 +328,7 @@ function openBalanceDialog(ticket) {
const description = ref([]);
const firstTicketClientId = checkedTickets[0].clientFk;
const isSameClient = checkedTickets.every(
- (ticket) => ticket.clientFk === firstTicketClientId
+ (ticket) => ticket.clientFk === firstTicketClientId,
);
if (!isSameClient) {
@@ -369,7 +367,7 @@ async function onSubmit() {
description: dialogData.value.value.description,
clientFk: dialogData.value.value.clientFk,
email: email[0].email,
- }
+ },
);
if (data) notify('globals.dataSaved', 'positive');
@@ -388,32 +386,32 @@ function setReference(data) {
switch (data) {
case 1:
newDescription = `${t(
- 'ticketList.creditCard'
+ 'ticketList.creditCard',
)}, ${dialogData.value.value.description.replace(
/^(Credit Card, |Cash, |Transfers, )/,
- ''
+ '',
)}`;
break;
case 2:
newDescription = `${t(
- 'ticketList.cash'
+ 'ticketList.cash',
)}, ${dialogData.value.value.description.replace(
/^(Credit Card, |Cash, |Transfers, )/,
- ''
+ '',
)}`;
break;
case 3:
newDescription = `${newDescription.replace(
/^(Credit Card, |Cash, |Transfers, )/,
- ''
+ '',
)}`;
break;
case 4:
newDescription = `${t(
- 'ticketList.transfers'
+ 'ticketList.transfers',
)}, ${dialogData.value.value.description.replace(
/^(Credit Card, |Cash, |Transfers, )/,
- ''
+ '',
)}`;
break;
case 3317:
diff --git a/src/pages/Ticket/locale/en.yml b/src/pages/Ticket/locale/en.yml
index f11b32c3a..cdbb22d9b 100644
--- a/src/pages/Ticket/locale/en.yml
+++ b/src/pages/Ticket/locale/en.yml
@@ -23,6 +23,8 @@ ticketSale:
hasComponentLack: Component lack
ok: Ok
more: More
+ transferLines: Transfer lines(no basket)/ Split
+ transferBasket: Some row selected is basket
advanceTickets:
preparation: Preparation
origin: Origin
@@ -188,7 +190,6 @@ ticketList:
accountPayment: Account payment
sendDocuware: Set delivered and send delivery note(s) to the tablet
addPayment: Add payment
- date: Date
company: Company
amount: Amount
reference: Reference
@@ -202,9 +203,89 @@ ticketList:
creditCard: Credit card
transfers: Transfers
province: Province
- warehouse: Warehouse
- hour: Hour
closure: Closure
toLines: Go to lines
addressNickname: Address nickname
ref: Reference
+ rounding: Rounding
+ noVerifiedData: No verified data
+ purchaseRequest: Purchase request
+ notVisible: Not visible
+ clientFrozen: Client frozen
+ componentLack: Component lack
+negative:
+ hour: Hour
+ id: Id Article
+ longName: Article
+ supplier: Supplier
+ colour: Colour
+ size: Size
+ origen: Origin
+ value: Negative
+ itemFk: Article
+ producer: Producer
+ warehouse: Warehouse
+ warehouseFk: Warehouse
+ category: Category
+ categoryFk: Family
+ type: Type
+ typeFk: Type
+ lack: Negative
+ inkFk: inkFk
+ timed: timed
+ date: Date
+ minTimed: minTimed
+ negativeAction: Negative
+ totalNegative: Total negatives
+ days: Days
+ buttonsUpdate:
+ item: Item
+ state: State
+ quantity: Quantity
+ modalOrigin:
+ title: Update negatives
+ question: Select a state to update
+ modalSplit:
+ title: Confirm split selected
+ question: Select a state to update
+ detail:
+ saleFk: Sale
+ itemFk: Article
+ ticketFk: Ticket
+ code: Code
+ nickname: Alias
+ name: Name
+ zoneName: Agency name
+ shipped: Date
+ theoreticalhour: Theoretical hour
+ agName: Agency
+ quantity: Quantity
+ alertLevelCode: Group state
+ state: State
+ peticionCompra: Ticket request
+ isRookie: Is rookie
+ turno: Turn line
+ isBasket: Basket
+ hasObservation: Has substitution
+ hasToIgnore: VIP
+ modal:
+ changeItem:
+ title: Update item reference
+ placeholder: New item
+ changeState:
+ title: Update tickets state
+ placeholder: New state
+ changeQuantity:
+ title: Update tickets quantity
+ placeholder: New quantity
+ split:
+ title: Are you sure you want to split selected tickets?
+ subTitle: Confirm split action
+ handleSplited:
+ title: Handle splited tickets
+ subTitle: Confirm date and agency
+ split:
+ ticket: Old ticket
+ newTicket: New ticket
+ status: Result
+ message: Message
diff --git a/src/pages/Ticket/locale/es.yml b/src/pages/Ticket/locale/es.yml
index 945da8367..75d3c6a2b 100644
--- a/src/pages/Ticket/locale/es.yml
+++ b/src/pages/Ticket/locale/es.yml
@@ -127,6 +127,8 @@ ticketSale:
ok: Ok
more: Más
address: Consignatario
+ transferLines: Transferir líneas(no cesta)/ Separar
+ transferBasket: No disponible para una cesta
size: Medida
ticketComponents:
serie: Serie
@@ -213,3 +215,84 @@ ticketList:
toLines: Ir a lineas
addressNickname: Alias consignatario
ref: Referencia
+negative:
+ hour: Hora
+ id: Id Articulo
+ longName: Articulo
+ supplier: Productor
+ colour: Color
+ size: Medida
+ origen: Origen
+ value: Negativo
+ warehouseFk: Almacen
+ producer: Producer
+ category: Categoría
+ categoryFk: Familia
+ typeFk: Familia
+ warehouse: Almacen
+ lack: Negativo
+ inkFk: Color
+ timed: Hora
+ date: Fecha
+ minTimed: Hora
+ type: Tipo
+ negativeAction: Negativo
+ totalNegative: Total negativos
+ days: Rango de dias
+ buttonsUpdate:
+ item: artículo
+ state: Estado
+ quantity: Cantidad
+ modalOrigin:
+ title: Actualizar negativos
+ question: Seleccione un estado para guardar
+ modalSplit:
+ title: Confirmar acción de split
+ question: Selecciona un estado
+ detail:
+ saleFk: Línea
+ itemFk: Artículo
+ ticketFk: Ticket
+ code: code
+ nickname: Alias
+ name: Nombre
+ zoneName: Agencia
+ shipped: F. envío
+ theoreticalhour: Hora teórica
+ agName: Agencia
+ quantity: Cantidad
+ alertLevelCode: Estado agrupado
+ state: Estado
+ peticionCompra: Petición compra
+ isRookie: Cliente nuevo
+ turno: Linea turno
+ isBasket: Cesta
+ hasObservation: Tiene sustitución
+ hasToIgnore: VIP
+ modal:
+ changeItem:
+ title: Actualizar referencia artículo
+ placeholder: Nuevo articulo
+ changeState:
+ title: Actualizar estado
+ placeholder: Nuevo estado
+ changeQuantity:
+ title: Actualizar cantidad
+ placeholder: Nueva cantidad
+ split:
+ title: ¿Seguro de separar los tickets seleccionados?
+ subTitle: Confirma separar tickets seleccionados
+ handleSplited:
+ title: Gestionar tickets spliteados
+ subTitle: Confir fecha y agencia
+ split:
+ ticket: Ticket viejo
+ newTicket: Ticket nuevo
+ status: Estado
+ message: Mensaje
+ rounding: Redondeo
+ noVerifiedData: Sin datos comprobados
+ purchaseRequest: Petición de compra
+ notVisible: No visible
+ clientFrozen: Cliente congelado
+ componentLack: Faltan componentes
diff --git a/src/pages/Travel/Card/TravelBasicData.vue b/src/pages/Travel/Card/TravelBasicData.vue
index 4b9aa28ed..b1adc8126 100644
--- a/src/pages/Travel/Card/TravelBasicData.vue
+++ b/src/pages/Travel/Card/TravelBasicData.vue
@@ -9,6 +9,7 @@ import VnRow from 'components/ui/VnRow.vue';
import VnInput from 'src/components/common/VnInput.vue';
import VnSelect from 'src/components/common/VnSelect.vue';
import VnInputDate from 'components/common/VnInputDate.vue';
+import VnInputTime from 'components/common/VnInputTime.vue';
const route = useRoute();
const { t } = useI18n();
@@ -53,7 +54,16 @@ const warehousesOptionsIn = ref([]);
-
+
+
+
+
-
-
-es:
- raidDays: El travel se desplaza automáticamente cada día para estar desde hoy al número de días indicado. Si se deja vacio no se moverá
-en:
- raidDays: The travel adjusts itself daily to match the number of days set, starting from today. If left blank, it won’t move
-
diff --git a/src/pages/Travel/Card/TravelCard.vue b/src/pages/Travel/Card/TravelCard.vue
index 445675b90..cb09eafd6 100644
--- a/src/pages/Travel/Card/TravelCard.vue
+++ b/src/pages/Travel/Card/TravelCard.vue
@@ -1,43 +1,13 @@
diff --git a/src/pages/Travel/Card/TravelDescriptor.vue b/src/pages/Travel/Card/TravelDescriptor.vue
index 72acf91b8..922f89f33 100644
--- a/src/pages/Travel/Card/TravelDescriptor.vue
+++ b/src/pages/Travel/Card/TravelDescriptor.vue
@@ -32,7 +32,6 @@ const setData = (entity) => (data.value = useCardDescription(entity.ref, entity.
`#/travel/${entityId.value}/${param}`;
+
diff --git a/src/pages/Travel/Card/TravelThermographs.vue b/src/pages/Travel/Card/TravelThermographs.vue
index 2946c8814..2376bd6d2 100644
--- a/src/pages/Travel/Card/TravelThermographs.vue
+++ b/src/pages/Travel/Card/TravelThermographs.vue
@@ -217,7 +217,7 @@ const removeThermograph = async (id) => {
icon="add"
color="primary"
@click="redirectToThermographForm('create')"
- shortcut="+"
+ v-shortcut="'+'"
/>
{{ t('Add thermograph') }}
diff --git a/src/pages/Travel/ExtraCommunityFilter.vue b/src/pages/Travel/ExtraCommunityFilter.vue
index b903aeabf..b22574632 100644
--- a/src/pages/Travel/ExtraCommunityFilter.vue
+++ b/src/pages/Travel/ExtraCommunityFilter.vue
@@ -113,7 +113,7 @@ warehouses();
[
cardVisible: true,
create: true,
},
+ {
+ align: 'left',
+ name: 'availabled',
+ label: t('travel.summary.availabled'),
+ component: 'input',
+ columnClass: 'expand',
+ columnField: {
+ component: null,
+ },
+ format: (row, dashIfEmpty) => dashIfEmpty(toDateTimeFormat(row.availabled)),
+ },
{
align: 'right',
label: '',
@@ -269,6 +283,16 @@ const columns = computed(() => [
:class="{ 'is-active': row.isReceived }"
/>
+
+
+
+
-
+
diff --git a/src/pages/Wagon/Type/WagonTypeList.vue b/src/pages/Wagon/Type/WagonTypeList.vue
index c0943c58e..4c0b078a7 100644
--- a/src/pages/Wagon/Type/WagonTypeList.vue
+++ b/src/pages/Wagon/Type/WagonTypeList.vue
@@ -96,7 +96,13 @@ async function remove(row) {
>
-
+
-import { ref, onBeforeMount } from 'vue';
-import { useRoute } from 'vue-router';
+import { ref } from 'vue';
import { useI18n } from 'vue-i18n';
import VnInputDate from 'src/components/common/VnInputDate.vue';
import FetchData from 'components/FetchData.vue';
@@ -11,18 +10,13 @@ import VnSelect from 'src/components/common/VnSelect.vue';
import { useAdvancedSummary } from 'src/composables/useAdvancedSummary';
const { t } = useI18n();
+const form = ref();
const educationLevels = ref([]);
const countries = ref([]);
const maritalStatus = [
{ code: 'M', name: t('Married') },
{ code: 'S', name: t('Single') },
];
-const advancedSummary = ref({});
-
-onBeforeMount(async () => {
- advancedSummary.value =
- (await useAdvancedSummary('Workers', +useRoute().params.id)) ?? {};
-});
{
auto-load
/>
{
- Object.assign(data, advancedSummary);
+ Object.assign(data, (await useAdvancedSummary('Workers', data.id)) ?? {});
+ await $nextTick();
+ if (form) form.hasChanges = false;
}
"
>
diff --git a/src/pages/Worker/Card/WorkerCalendar.vue b/src/pages/Worker/Card/WorkerCalendar.vue
index 5ca95a1a4..df4616011 100644
--- a/src/pages/Worker/Card/WorkerCalendar.vue
+++ b/src/pages/Worker/Card/WorkerCalendar.vue
@@ -1,7 +1,8 @@
@@ -181,6 +193,20 @@ watch([year, businessFk], () => refreshData());
/>
+
+ {
+ saveUrl = `Businesses/${data.id}`;
+ }
+ "
+ :body="body"
+ />
+
diff --git a/src/pages/Worker/Card/WorkerCalendarFilter.vue b/src/pages/Worker/Card/WorkerCalendarFilter.vue
index 67b7df907..48fc4094b 100644
--- a/src/pages/Worker/Card/WorkerCalendarFilter.vue
+++ b/src/pages/Worker/Card/WorkerCalendarFilter.vue
@@ -180,8 +180,6 @@ const yearList = ref(generateYears());
:is-clearable="false"
/>
-
-
-
+
diff --git a/src/pages/Worker/Card/WorkerDescriptor.vue b/src/pages/Worker/Card/WorkerDescriptor.vue
index d87fd4a54..de3f634e2 100644
--- a/src/pages/Worker/Card/WorkerDescriptor.vue
+++ b/src/pages/Worker/Card/WorkerDescriptor.vue
@@ -10,7 +10,7 @@ import axios from 'axios';
import VnImg from 'src/components/ui/VnImg.vue';
import EditPictureForm from 'components/EditPictureForm.vue';
import WorkerDescriptorMenu from './WorkerDescriptorMenu.vue';
-import DepartmentDescriptorProxy from 'src/pages/Department/Card/DepartmentDescriptorProxy.vue';
+import DepartmentDescriptorProxy from 'src/pages/Worker/Department/Card/DepartmentDescriptorProxy.vue';
const $props = defineProps({
id: {
@@ -21,7 +21,7 @@ const $props = defineProps({
dataKey: {
type: String,
required: false,
- default: 'workerData',
+ default: 'Worker',
},
});
const image = ref(null);
@@ -50,9 +50,8 @@ const handlePhotoUpdated = (evt = false) => {
{
-
+
diff --git a/src/pages/Worker/Card/WorkerFormation.vue b/src/pages/Worker/Card/WorkerFormation.vue
index 6fd5a4eae..e05eca7f8 100644
--- a/src/pages/Worker/Card/WorkerFormation.vue
+++ b/src/pages/Worker/Card/WorkerFormation.vue
@@ -94,6 +94,7 @@ const columns = computed(() => [
align: 'left',
name: 'hasDiploma',
label: t('worker.formation.tableVisibleColumns.hasDiploma'),
+ component: 'checkbox',
create: true,
},
{
diff --git a/src/pages/Worker/Card/WorkerOperator.vue b/src/pages/Worker/Card/WorkerOperator.vue
index cdacc72c0..6faeefe67 100644
--- a/src/pages/Worker/Card/WorkerOperator.vue
+++ b/src/pages/Worker/Card/WorkerOperator.vue
@@ -1,7 +1,7 @@
@@ -67,6 +83,7 @@ async function insert() {
:data-required="{ workerFk: route.params.id }"
ref="crudModelRef"
search-url="operator"
+ :selected="selected"
auto-load
>
diff --git a/src/pages/Worker/Card/WorkerPda.vue b/src/pages/Worker/Card/WorkerPda.vue
index f6cb92aac..47e13cf6d 100644
--- a/src/pages/Worker/Card/WorkerPda.vue
+++ b/src/pages/Worker/Card/WorkerPda.vue
@@ -101,7 +101,7 @@ function reloadData() {
openConfirmationModal(
t(`Remove PDA`),
t('Do you want to remove this PDA?'),
- () => deallocatePDA(row.deviceProductionFk)
+ () => deallocatePDA(row.deviceProductionFk),
)
"
>
@@ -114,7 +114,13 @@ function reloadData() {
-
+
{
color="primary"
flat
icon="add"
- shortcut="+"
+ v-shortcut="'+'"
style="flex: 0"
data-cy="addRelative"
/>
diff --git a/src/pages/Worker/Card/WorkerSummary.vue b/src/pages/Worker/Card/WorkerSummary.vue
index 992f6ec71..78c5dfd82 100644
--- a/src/pages/Worker/Card/WorkerSummary.vue
+++ b/src/pages/Worker/Card/WorkerSummary.vue
@@ -9,7 +9,7 @@ import CardSummary from 'components/ui/CardSummary.vue';
import VnUserLink from 'src/components/ui/VnUserLink.vue';
import VnTitle from 'src/components/common/VnTitle.vue';
import RoleDescriptorProxy from 'src/pages/Account/Role/Card/RoleDescriptorProxy.vue';
-import DepartmentDescriptorProxy from 'src/pages/Department/Card/DepartmentDescriptorProxy.vue';
+import DepartmentDescriptorProxy from 'src/pages/Worker/Department/Card/DepartmentDescriptorProxy.vue';
import { useAdvancedSummary } from 'src/composables/useAdvancedSummary';
import WorkerDescriptorMenu from './WorkerDescriptorMenu.vue';
diff --git a/src/pages/Worker/Card/WorkerTimeControl.vue b/src/pages/Worker/Card/WorkerTimeControl.vue
index c580e5202..7def6e94c 100644
--- a/src/pages/Worker/Card/WorkerTimeControl.vue
+++ b/src/pages/Worker/Card/WorkerTimeControl.vue
@@ -64,17 +64,17 @@ const selectedCalendarDates = ref([]);
// Date formateada para bindear al componente QDate
const selectedDateFormatted = ref(toDateString(defaultDate.value));
-const arrayData = useArrayData('workerData');
+const arrayData = useArrayData('Worker');
const acl = useAcl();
const selectedDateYear = computed(() => moment(selectedDate.value).isoWeekYear());
const worker = computed(() => arrayData.store?.data);
const canSend = computed(() =>
- acl.hasAny([{ model: 'WorkerTimeControl', props: 'sendMail', accessType: 'WRITE' }])
+ acl.hasAny([{ model: 'WorkerTimeControl', props: 'sendMail', accessType: 'WRITE' }]),
);
const canUpdate = computed(() =>
acl.hasAny([
{ model: 'WorkerTimeControl', props: 'updateMailState', accessType: 'WRITE' },
- ])
+ ]),
);
const isHimself = computed(() => user.value.id === Number(route.params.id));
@@ -100,7 +100,7 @@ const getHeaderFormattedDate = (date) => {
};
const formattedWeekTotalHours = computed(() =>
- secondsToHoursMinutes(weekTotalHours.value)
+ secondsToHoursMinutes(weekTotalHours.value),
);
const onInputChange = async (date) => {
@@ -320,7 +320,7 @@ const getFinishTime = () => {
today.setHours(0, 0, 0, 0);
let todayInWeek = weekDays.value.find(
- (day) => day.dated.getTime() === today.getTime()
+ (day) => day.dated.getTime() === today.getTime(),
);
if (todayInWeek && todayInWeek.hours && todayInWeek.hours.length) {
@@ -472,7 +472,7 @@ onMounted(async () => {
openConfirmationModal(
t('Send time control email'),
t('Are you sure you want to send it?'),
- resendEmail
+ resendEmail,
)
"
>
@@ -561,7 +561,7 @@ onMounted(async () => {
@show-worker-time-form="
showWorkerTimeForm(
{ id: hour.id, entryCode: hour.direction },
- 'edit'
+ 'edit',
)
"
class="hour-chip"
@@ -577,7 +577,7 @@ onMounted(async () => {
-import { useRoute } from 'vue-router';
-import { useI18n } from 'vue-i18n';
-
import FormModel from 'components/FormModel.vue';
import VnRow from 'components/ui/VnRow.vue';
import VnInput from 'src/components/common/VnInput.vue';
import VnSelect from 'src/components/common/VnSelect.vue';
import VnSelectWorker from 'src/components/common/VnSelectWorker.vue';
-
-const route = useRoute();
-const { t } = useI18n();
-
+
diff --git a/src/pages/Department/Card/DepartmentCard.vue b/src/pages/Worker/Department/Card/DepartmentCard.vue
similarity index 70%
rename from src/pages/Department/Card/DepartmentCard.vue
rename to src/pages/Worker/Department/Card/DepartmentCard.vue
index 4b9fe419c..2e3f11521 100644
--- a/src/pages/Department/Card/DepartmentCard.vue
+++ b/src/pages/Worker/Department/Card/DepartmentCard.vue
@@ -1,13 +1,13 @@
diff --git a/src/pages/Department/Card/DepartmentDescriptor.vue b/src/pages/Worker/Department/Card/DepartmentDescriptor.vue
similarity index 84%
rename from src/pages/Department/Card/DepartmentDescriptor.vue
rename to src/pages/Worker/Department/Card/DepartmentDescriptor.vue
index b219ccfe1..4b7dfd9b8 100644
--- a/src/pages/Department/Card/DepartmentDescriptor.vue
+++ b/src/pages/Worker/Department/Card/DepartmentDescriptor.vue
@@ -5,7 +5,6 @@ import { useI18n } from 'vue-i18n';
import { useVnConfirm } from 'composables/useVnConfirm';
import VnLv from 'src/components/ui/VnLv.vue';
import CardDescriptor from 'src/components/ui/CardDescriptor.vue';
-import useCardDescription from 'src/composables/useCardDescription';
import axios from 'axios';
import useNotify from 'src/composables/useNotify.js';
@@ -32,15 +31,6 @@ const entityId = computed(() => {
return $props.id || route.params.id;
});
-const department = ref();
-
-const data = ref(useCardDescription());
-
-const setData = (entity) => {
- if (!entity) return;
- data.value = useCardDescription(entity.name, entity.id);
-};
-
const removeDepartment = async () => {
await axios.post(`/Departments/${entityId.value}/removeChild`, entityId.value);
router.push({ name: 'WorkerDepartment' });
@@ -52,19 +42,10 @@ const { openConfirmationModal } = useVnConfirm();
{
- department = data;
- setData(data);
- }
- "
- data-key="department"
+ data-key="Department"
>
diff --git a/src/pages/Department/Card/DepartmentDescriptorProxy.vue b/src/pages/Worker/Department/Card/DepartmentDescriptorProxy.vue
similarity index 100%
rename from src/pages/Department/Card/DepartmentDescriptorProxy.vue
rename to src/pages/Worker/Department/Card/DepartmentDescriptorProxy.vue
diff --git a/src/pages/Department/Card/DepartmentSummary.vue b/src/pages/Worker/Department/Card/DepartmentSummary.vue
similarity index 99%
rename from src/pages/Department/Card/DepartmentSummary.vue
rename to src/pages/Worker/Department/Card/DepartmentSummary.vue
index 3d481601f..3719137e4 100644
--- a/src/pages/Department/Card/DepartmentSummary.vue
+++ b/src/pages/Worker/Department/Card/DepartmentSummary.vue
@@ -27,7 +27,7 @@ onMounted(async () => {
diff --git a/src/pages/Zone/Card/ZoneBasicData.vue b/src/pages/Zone/Card/ZoneBasicData.vue
index 96b772a6f..b38d2749b 100644
--- a/src/pages/Zone/Card/ZoneBasicData.vue
+++ b/src/pages/Zone/Card/ZoneBasicData.vue
@@ -123,6 +123,8 @@ const setFilteredAddresses = (data) => {
hide-selected
map-options
:rules="validate('data.addressFk')"
+ :filter-options="['id']"
+ :where="filterWhere"
/>
diff --git a/src/pages/Zone/Card/ZoneCard.vue b/src/pages/Zone/Card/ZoneCard.vue
index a470cd5bd..41daff5c0 100644
--- a/src/pages/Zone/Card/ZoneCard.vue
+++ b/src/pages/Zone/Card/ZoneCard.vue
@@ -1,13 +1,12 @@
-
+
-
-
-
-
-
+
+
+
+
+
-
diff --git a/src/pages/Zone/Card/ZoneEvents.vue b/src/pages/Zone/Card/ZoneEvents.vue
index a5806bab9..1e6debd25 100644
--- a/src/pages/Zone/Card/ZoneEvents.vue
+++ b/src/pages/Zone/Card/ZoneEvents.vue
@@ -78,13 +78,13 @@ const onZoneEventFormClose = () => {
{
isNewMode: true,
},
- true
+ true,
)
"
color="primary"
fab
icon="add"
- shortcut="+"
+ v-shortcut="'+'"
/>
{{ t('eventsInclusionForm.addEvent') }}
diff --git a/src/pages/Zone/Card/ZoneFilter.js b/src/pages/Zone/Card/ZoneFilter.js
new file mode 100644
index 000000000..3298c7c8a
--- /dev/null
+++ b/src/pages/Zone/Card/ZoneFilter.js
@@ -0,0 +1,10 @@
+export default {
+ include: [
+ {
+ relation: 'agencyMode',
+ scope: {
+ fields: ['name', 'id'],
+ },
+ },
+ ],
+};
diff --git a/src/pages/Zone/Card/ZoneSummary.vue b/src/pages/Zone/Card/ZoneSummary.vue
index 124802633..5b29b495b 100644
--- a/src/pages/Zone/Card/ZoneSummary.vue
+++ b/src/pages/Zone/Card/ZoneSummary.vue
@@ -11,6 +11,7 @@ import { getUrl } from 'src/composables/getUrl';
import { toCurrency } from 'filters/index';
import { toTimeFormat } from 'src/filters/date';
import axios from 'axios';
+import filter from './ZoneFilter.js';
import ZoneDescriptorMenuItems from './ZoneDescriptorMenuItems.vue';
const route = useRoute();
@@ -26,19 +27,6 @@ const $props = defineProps({
const entityId = computed(() => $props.id || route.params.id);
const zoneUrl = ref();
-const filter = computed(() => {
- const filter = {
- include: {
- relation: 'agencyMode',
- fields: ['name'],
- },
- where: {
- id: entityId,
- },
- };
- return filter;
-});
-
const columns = computed(() => [
{
label: t('list.name'),
@@ -72,9 +60,9 @@ onMounted(async () => {
diff --git a/src/pages/Zone/Card/ZoneWarehouses.vue b/src/pages/Zone/Card/ZoneWarehouses.vue
index c96735697..165e9c840 100644
--- a/src/pages/Zone/Card/ZoneWarehouses.vue
+++ b/src/pages/Zone/Card/ZoneWarehouses.vue
@@ -109,7 +109,7 @@ const openCreateWarehouseForm = () => createWarehouseDialogRef.value.show();
icon="add"
color="primary"
@click="openCreateWarehouseForm()"
- shortcut="+"
+ v-shortcut="'+'"
>
{{ t('warehouses.add') }}
diff --git a/src/pages/Zone/Delivery/ZoneDeliveryList.vue b/src/pages/Zone/Delivery/ZoneDeliveryList.vue
index 975cbdb67..e3ec8cb2d 100644
--- a/src/pages/Zone/Delivery/ZoneDeliveryList.vue
+++ b/src/pages/Zone/Delivery/ZoneDeliveryList.vue
@@ -74,7 +74,7 @@ async function remove(row) {
-
+
diff --git a/src/pages/Zone/Upcoming/ZoneUpcomingList.vue b/src/pages/Zone/Upcoming/ZoneUpcomingList.vue
index 5a7f0bb4c..7b5c2ddbc 100644
--- a/src/pages/Zone/Upcoming/ZoneUpcomingList.vue
+++ b/src/pages/Zone/Upcoming/ZoneUpcomingList.vue
@@ -74,7 +74,7 @@ async function remove(row) {
-
+
diff --git a/src/router/modules/account/aliasCard.js b/src/router/modules/account/aliasCard.js
index cbbd31e51..a5b00f44b 100644
--- a/src/router/modules/account/aliasCard.js
+++ b/src/router/modules/account/aliasCard.js
@@ -3,7 +3,7 @@ export default {
path: ':id',
component: () => import('src/pages/Account/Alias/Card/AliasCard.vue'),
redirect: { name: 'AliasSummary' },
- meta: { menu: ['AliasBasicData', 'AliasUsers'] },
+ meta: { moduleName: 'Alias', menu: ['AliasBasicData', 'AliasUsers'] },
children: [
{
name: 'AliasSummary',
diff --git a/src/router/modules/account/roleCard.js b/src/router/modules/account/roleCard.js
index c36ce71b9..f8100071f 100644
--- a/src/router/modules/account/roleCard.js
+++ b/src/router/modules/account/roleCard.js
@@ -4,6 +4,7 @@ export default {
component: () => import('src/pages/Account/Role/Card/RoleCard.vue'),
redirect: { name: 'RoleSummary' },
meta: {
+ moduleName: 'Role',
menu: ['RoleBasicData', 'SubRoles', 'InheritedRoles', 'RoleLog'],
},
children: [
diff --git a/src/router/modules/entry.js b/src/router/modules/entry.js
index f362c7653..b5656dc5f 100644
--- a/src/router/modules/entry.js
+++ b/src/router/modules/entry.js
@@ -6,13 +6,7 @@ const entryCard = {
component: () => import('src/pages/Entry/Card/EntryCard.vue'),
redirect: { name: 'EntrySummary' },
meta: {
- menu: [
- 'EntryBasicData',
- 'EntryBuys',
- 'EntryNotes',
- 'EntryDms',
- 'EntryLog',
- ],
+ menu: ['EntryBasicData', 'EntryBuys', 'EntryNotes', 'EntryDms', 'EntryLog'],
},
children: [
{
@@ -91,7 +85,7 @@ export default {
'EntryLatestBuys',
'EntryStockBought',
'EntryWasteRecalc',
- ]
+ ],
},
component: RouterView,
redirect: { name: 'EntryMain' },
@@ -103,7 +97,7 @@ export default {
redirect: { name: 'EntryIndexMain' },
children: [
{
- path:'',
+ path: '',
name: 'EntryIndexMain',
redirect: { name: 'EntryList' },
component: () => import('src/pages/Entry/EntryList.vue'),
@@ -115,6 +109,7 @@ export default {
title: 'list',
icon: 'view_list',
},
+ component: () => import('src/pages/Entry/EntryList.vue'),
},
entryCard,
],
@@ -127,7 +122,7 @@ export default {
icon: 'add',
},
component: () => import('src/pages/Entry/EntryCreate.vue'),
- },
+ },
{
path: 'my',
name: 'MyEntries',
@@ -167,4 +162,4 @@ export default {
],
},
],
-};
\ No newline at end of file
+};
diff --git a/src/router/modules/route.js b/src/router/modules/route.js
index 946ad3e15..835324d20 100644
--- a/src/router/modules/route.js
+++ b/src/router/modules/route.js
@@ -160,6 +160,36 @@ const roadmapCard = {
],
};
+const vehicleCard = {
+ path: ':id',
+ name: 'VehicleCard',
+ component: () => import('src/pages/Route/Vehicle/Card/VehicleCard.vue'),
+ redirect: { name: 'VehicleSummary' },
+ meta: {
+ menu: ['VehicleBasicData'],
+ },
+ children: [
+ {
+ name: 'VehicleSummary',
+ path: 'summary',
+ meta: {
+ title: 'summary',
+ icon: 'view_list',
+ },
+ component: () => import('src/pages/Route/Vehicle/Card/VehicleSummary.vue'),
+ },
+ {
+ name: 'VehicleBasicData',
+ path: 'basic-data',
+ meta: {
+ title: 'basicData',
+ icon: 'vn:settings',
+ },
+ component: () => import('src/pages/Route/Vehicle/Card/VehicleBasicData.vue'),
+ },
+ ],
+};
+
export default {
name: 'Route',
path: '/route',
@@ -174,6 +204,7 @@ export default {
'RouteRoadmap',
'CmrList',
'AgencyList',
+ 'VehicleList',
],
},
component: RouterView,
@@ -280,6 +311,27 @@ export default {
agencyCard,
],
},
+ {
+ path: 'vehicle',
+ name: 'RouteVehicle',
+ redirect: { name: 'VehicleList' },
+ meta: {
+ title: 'vehicle',
+ icon: 'directions_car',
+ },
+ component: () => import('src/pages/Route/Vehicle/VehicleList.vue'),
+ children: [
+ {
+ path: 'list',
+ name: 'VehicleList',
+ meta: {
+ title: 'vehicleList',
+ icon: 'directions_car',
+ },
+ },
+ vehicleCard,
+ ],
+ },
],
},
],
diff --git a/src/router/modules/shelving.js b/src/router/modules/shelving.js
index 55fb04278..c085dd8dc 100644
--- a/src/router/modules/shelving.js
+++ b/src/router/modules/shelving.js
@@ -3,7 +3,7 @@ import { RouterView } from 'vue-router';
const parkingCard = {
name: 'ParkingCard',
path: ':id',
- component: () => import('src/pages/Parking/Card/ParkingCard.vue'),
+ component: () => import('src/pages/Shelving/Parking/Card/ParkingCard.vue'),
redirect: { name: 'ParkingSummary' },
meta: {
menu: ['ParkingBasicData', 'ParkingLog'],
@@ -16,7 +16,7 @@ const parkingCard = {
title: 'summary',
icon: 'launch',
},
- component: () => import('src/pages/Parking/Card/ParkingSummary.vue'),
+ component: () => import('src/pages/Shelving/Parking/Card/ParkingSummary.vue'),
},
{
path: 'basic-data',
@@ -25,7 +25,8 @@ const parkingCard = {
title: 'basicData',
icon: 'vn:settings',
},
- component: () => import('src/pages/Parking/Card/ParkingBasicData.vue'),
+ component: () =>
+ import('src/pages/Shelving/Parking/Card/ParkingBasicData.vue'),
},
{
path: 'log',
@@ -34,7 +35,7 @@ const parkingCard = {
title: 'log',
icon: 'history',
},
- component: () => import('src/pages/Parking/Card/ParkingLog.vue'),
+ component: () => import('src/pages/Shelving/Parking/Card/ParkingLog.vue'),
},
],
};
@@ -127,7 +128,7 @@ export default {
title: 'parkingList',
icon: 'view_list',
},
- component: () => import('src/pages/Parking/ParkingList.vue'),
+ component: () => import('src/pages/Shelving/Parking/ParkingList.vue'),
children: [
{
path: 'list',
diff --git a/src/router/modules/supplier.js b/src/router/modules/supplier.js
index 4ece4c784..19763cdf3 100644
--- a/src/router/modules/supplier.js
+++ b/src/router/modules/supplier.js
@@ -1,19 +1,12 @@
import { RouterView } from 'vue-router';
-export default {
- path: '/supplier',
- name: 'Supplier',
+const supplierCard = {
+ name: 'SupplierCard',
+ path: ':id',
+ component: () => import('src/pages/Supplier/Card/SupplierCard.vue'),
+ redirect: { name: 'SupplierSummary' },
meta: {
- title: 'suppliers',
- icon: 'vn:supplier',
- moduleName: 'Supplier',
- keyBinding: 'p',
- },
- component: RouterView,
- redirect: { name: 'SupplierMain' },
- menus: {
- main: ['SupplierList'],
- card: [
+ menu: [
'SupplierBasicData',
'SupplierFiscalData',
'SupplierBillingData',
@@ -27,21 +20,165 @@ export default {
'SupplierDms',
],
},
+ children: [
+ {
+ name: 'SupplierSummary',
+ path: 'summary',
+ meta: {
+ title: 'summary',
+ icon: 'launch',
+ },
+ component: () => import('src/pages/Supplier/Card/SupplierSummary.vue'),
+ },
+ {
+ path: 'basic-data',
+ name: 'SupplierBasicData',
+ meta: {
+ title: 'basicData',
+ icon: 'vn:settings',
+ },
+ component: () => import('src/pages/Supplier/Card/SupplierBasicData.vue'),
+ },
+ {
+ path: 'fiscal-data',
+ name: 'SupplierFiscalData',
+ meta: {
+ title: 'fiscalData',
+ icon: 'vn:dfiscales',
+ },
+ component: () => import('src/pages/Supplier/Card/SupplierFiscalData.vue'),
+ },
+ {
+ path: 'billing-data',
+ name: 'SupplierBillingData',
+ meta: {
+ title: 'billingData',
+ icon: 'vn:payment',
+ },
+ component: () => import('src/pages/Supplier/Card/SupplierBillingData.vue'),
+ },
+ {
+ path: 'log',
+ name: 'SupplierLog',
+ meta: {
+ title: 'log',
+ icon: 'vn:History',
+ },
+ component: () => import('src/pages/Supplier/Card/SupplierLog.vue'),
+ },
+ {
+ path: 'account',
+ name: 'SupplierAccounts',
+ meta: {
+ title: 'accounts',
+ icon: 'vn:credit',
+ },
+ component: () => import('src/pages/Supplier/Card/SupplierAccounts.vue'),
+ },
+ {
+ path: 'contact',
+ name: 'SupplierContacts',
+ meta: {
+ title: 'contacts',
+ icon: 'contact_phone',
+ },
+ component: () => import('src/pages/Supplier/Card/SupplierContacts.vue'),
+ },
+ {
+ path: 'address',
+ name: 'SupplierAddresses',
+ meta: {
+ title: 'addresses',
+ icon: 'vn:delivery',
+ },
+ component: () => import('src/pages/Supplier/Card/SupplierAddresses.vue'),
+ },
+ {
+ path: 'address/create',
+ name: 'SupplierAddressesCreate',
+ component: () =>
+ import('src/pages/Supplier/Card/SupplierAddressesCreate.vue'),
+ },
+ {
+ path: 'balance',
+ name: 'SupplierBalance',
+ meta: {
+ title: 'balance',
+ icon: 'balance',
+ },
+ component: () => import('src/pages/Supplier/Card/SupplierBalance.vue'),
+ },
+ {
+ path: 'consumption',
+ name: 'SupplierConsumption',
+ meta: {
+ title: 'consumption',
+ icon: 'show_chart',
+ },
+ component: () => import('src/pages/Supplier/Card/SupplierConsumption.vue'),
+ },
+ {
+ path: 'agency-term',
+ name: 'SupplierAgencyTerm',
+ meta: {
+ title: 'agencyTerm',
+ icon: 'vn:agency-term',
+ },
+ component: () => import('src/pages/Supplier/Card/SupplierAgencyTerm.vue'),
+ },
+ {
+ path: 'dms',
+ name: 'SupplierDms',
+ meta: {
+ title: 'dms',
+ icon: 'smb_share',
+ },
+ component: () => import('src/pages/Supplier/Card/SupplierDms.vue'),
+ },
+ {
+ path: 'agency-term/create',
+ name: 'SupplierAgencyTermCreate',
+ component: () =>
+ import('src/pages/Supplier/Card/SupplierAgencyTermCreate.vue'),
+ },
+ ],
+};
+
+export default {
+ name: 'Supplier',
+ path: '/supplier',
+ meta: {
+ title: 'suppliers',
+ icon: 'vn:supplier',
+ moduleName: 'Supplier',
+ keyBinding: 'p',
+ menu: ['SupplierList'],
+ },
+ component: RouterView,
+ redirect: { name: 'SupplierMain' },
children: [
{
path: '',
name: 'SupplierMain',
component: () => import('src/components/common/VnModule.vue'),
- redirect: { name: 'SupplierList' },
+ redirect: { name: 'SupplierIndexMain' },
children: [
{
- path: 'list',
- name: 'SupplierList',
- meta: {
- title: 'list',
- icon: 'view_list',
- },
+ path: '',
+ name: 'SupplierIndexMain',
+ redirect: { name: 'SupplierList' },
component: () => import('src/pages/Supplier/SupplierList.vue'),
+ children: [
+ {
+ path: 'list',
+ name: 'SupplierList',
+ meta: {
+ title: 'list',
+ icon: 'view_list',
+ },
+ },
+ supplierCard,
+ ],
},
{
path: 'create',
@@ -54,143 +191,5 @@ export default {
},
],
},
- {
- name: 'SupplierCard',
- path: ':id',
- component: () => import('src/pages/Supplier/Card/SupplierCard.vue'),
- redirect: { name: 'SupplierSummary' },
- children: [
- {
- name: 'SupplierSummary',
- path: 'summary',
- meta: {
- title: 'summary',
- icon: 'launch',
- },
- component: () =>
- import('src/pages/Supplier/Card/SupplierSummary.vue'),
- },
- {
- path: 'basic-data',
- name: 'SupplierBasicData',
- meta: {
- title: 'basicData',
- icon: 'vn:settings',
- },
- component: () =>
- import('src/pages/Supplier/Card/SupplierBasicData.vue'),
- },
- {
- path: 'fiscal-data',
- name: 'SupplierFiscalData',
- meta: {
- title: 'fiscalData',
- icon: 'vn:dfiscales',
- },
- component: () =>
- import('src/pages/Supplier/Card/SupplierFiscalData.vue'),
- },
- {
- path: 'billing-data',
- name: 'SupplierBillingData',
- meta: {
- title: 'billingData',
- icon: 'vn:payment',
- },
- component: () =>
- import('src/pages/Supplier/Card/SupplierBillingData.vue'),
- },
- {
- path: 'log',
- name: 'SupplierLog',
- meta: {
- title: 'log',
- icon: 'vn:History',
- },
- component: () => import('src/pages/Supplier/Card/SupplierLog.vue'),
- },
- {
- path: 'account',
- name: 'SupplierAccounts',
- meta: {
- title: 'accounts',
- icon: 'vn:credit',
- },
- component: () =>
- import('src/pages/Supplier/Card/SupplierAccounts.vue'),
- },
- {
- path: 'contact',
- name: 'SupplierContacts',
- meta: {
- title: 'contacts',
- icon: 'contact_phone',
- },
- component: () =>
- import('src/pages/Supplier/Card/SupplierContacts.vue'),
- },
- {
- path: 'address',
- name: 'SupplierAddresses',
- meta: {
- title: 'addresses',
- icon: 'vn:delivery',
- },
- component: () =>
- import('src/pages/Supplier/Card/SupplierAddresses.vue'),
- },
- {
- path: 'address/create',
- name: 'SupplierAddressesCreate',
- component: () =>
- import('src/pages/Supplier/Card/SupplierAddressesCreate.vue'),
- },
- {
- path: 'balance',
- name: 'SupplierBalance',
- meta: {
- title: 'balance',
- icon: 'balance',
- },
- component: () =>
- import('src/pages/Supplier/Card/SupplierBalance.vue'),
- },
- {
- path: 'consumption',
- name: 'SupplierConsumption',
- meta: {
- title: 'consumption',
- icon: 'show_chart',
- },
- component: () =>
- import('src/pages/Supplier/Card/SupplierConsumption.vue'),
- },
- {
- path: 'agency-term',
- name: 'SupplierAgencyTerm',
- meta: {
- title: 'agencyTerm',
- icon: 'vn:agency-term',
- },
- component: () =>
- import('src/pages/Supplier/Card/SupplierAgencyTerm.vue'),
- },
- {
- path: 'dms',
- name: 'SupplierDms',
- meta: {
- title: 'dms',
- icon: 'smb_share',
- },
- component: () => import('src/pages/Supplier/Card/SupplierDms.vue'),
- },
- {
- path: 'agency-term/create',
- name: 'SupplierAgencyTermCreate',
- component: () =>
- import('src/pages/Supplier/Card/SupplierAgencyTermCreate.vue'),
- },
- ],
- },
],
};
diff --git a/src/router/modules/ticket.js b/src/router/modules/ticket.js
index e5b423f64..bfcb78787 100644
--- a/src/router/modules/ticket.js
+++ b/src/router/modules/ticket.js
@@ -192,7 +192,13 @@ export default {
icon: 'vn:ticket',
moduleName: 'Ticket',
keyBinding: 't',
- menu: ['TicketList', 'TicketAdvance', 'TicketWeekly', 'TicketFuture'],
+ menu: [
+ 'TicketList',
+ 'TicketAdvance',
+ 'TicketWeekly',
+ 'TicketFuture',
+ 'TicketNegative',
+ ],
},
component: RouterView,
redirect: { name: 'TicketMain' },
@@ -229,6 +235,32 @@ export default {
},
component: () => import('src/pages/Ticket/TicketCreate.vue'),
},
+ {
+ path: 'negative',
+ redirect: { name: 'TicketNegative' },
+ children: [
+ {
+ name: 'TicketNegative',
+ meta: {
+ title: 'negative',
+ icon: 'exposure',
+ },
+ component: () =>
+ import('src/pages/Ticket/Negative/TicketLackList.vue'),
+ path: '',
+ },
+ {
+ name: 'NegativeDetail',
+ path: ':id',
+ meta: {
+ title: 'summary',
+ icon: 'launch',
+ },
+ component: () =>
+ import('src/pages/Ticket/Negative/TicketLackDetail.vue'),
+ },
+ ],
+ },
{
path: 'weekly',
name: 'TicketWeekly',
diff --git a/src/router/modules/worker.js b/src/router/modules/worker.js
index 1d013c596..3eb95a96e 100644
--- a/src/router/modules/worker.js
+++ b/src/router/modules/worker.js
@@ -201,9 +201,10 @@ const workerCard = {
const departmentCard = {
name: 'DepartmentCard',
path: ':id',
- component: () => import('src/pages/Department/Card/DepartmentCard.vue'),
+ component: () => import('src/pages/Worker/Department/Card/DepartmentCard.vue'),
redirect: { name: 'DepartmentSummary' },
meta: {
+ moduleName: 'Department',
menu: ['DepartmentBasicData'],
},
children: [
@@ -214,7 +215,8 @@ const departmentCard = {
title: 'summary',
icon: 'launch',
},
- component: () => import('src/pages/Department/Card/DepartmentSummary.vue'),
+ component: () =>
+ import('src/pages/Worker/Department/Card/DepartmentSummary.vue'),
},
{
path: 'basic-data',
@@ -223,7 +225,8 @@ const departmentCard = {
title: 'basicData',
icon: 'vn:settings',
},
- component: () => import('src/pages/Department/Card/DepartmentBasicData.vue'),
+ component: () =>
+ import('src/pages/Worker/Department/Card/DepartmentBasicData.vue'),
},
],
};
diff --git a/src/stores/__tests__/useNavigationStore.spec.js b/src/stores/__tests__/useNavigationStore.spec.js
new file mode 100644
index 000000000..c5df6157e
--- /dev/null
+++ b/src/stores/__tests__/useNavigationStore.spec.js
@@ -0,0 +1,153 @@
+import { setActivePinia, createPinia } from 'pinia';
+import { describe, beforeEach, afterEach, it, expect, vi, beforeAll } from 'vitest';
+import { useNavigationStore } from '../useNavigationStore';
+import axios from 'axios';
+
+let store;
+
+vi.mock('src/router/modules', () => [
+ { name: 'Item', meta: {} },
+ { name: 'Shelving', meta: {} },
+ { name: 'Order', meta: {} },
+]);
+
+vi.mock('src/filters', () => ({
+ toLowerCamel: vi.fn((name) => name.toLowerCase()),
+}));
+
+const modulesMock = [
+ {
+ name: 'Item',
+ children: null,
+ title: 'globals.pageTitles.undefined',
+ icon: undefined,
+ module: 'item',
+ isPinned: true,
+ },
+ {
+ name: 'Shelving',
+ children: null,
+ title: 'globals.pageTitles.undefined',
+ icon: undefined,
+ module: 'shelving',
+ isPinned: false,
+ },
+ {
+ name: 'Order',
+ children: null,
+ title: 'globals.pageTitles.undefined',
+ icon: undefined,
+ module: 'order',
+ isPinned: false,
+ },
+];
+
+const pinnedModulesMock = [
+ {
+ name: 'Item',
+ children: null,
+ title: 'globals.pageTitles.undefined',
+ icon: undefined,
+ module: 'item',
+ isPinned: true,
+ },
+];
+
+describe('useNavigationStore', () => {
+ beforeEach(() => {
+ setActivePinia(createPinia());
+ vi.spyOn(axios, 'get').mockResolvedValue({ data: true });
+ store = useNavigationStore();
+ store.getModules = vi.fn().mockReturnValue({
+ value: modulesMock,
+ });
+ store.getPinnedModules = vi.fn().mockReturnValue({
+ value: pinnedModulesMock,
+ });
+ });
+ afterEach(() => {
+ vi.clearAllMocks();
+ });
+
+ it('should return modules with correct structure', () => {
+ const store = useNavigationStore();
+ const modules = store.getModules();
+
+ expect(modules.value).toEqual(modulesMock);
+ });
+
+ it('should return pinned modules', () => {
+ const store = useNavigationStore();
+ const pinnedModules = store.getPinnedModules();
+
+ expect(pinnedModules.value).toEqual(pinnedModulesMock);
+ });
+
+ it('should toggle pinned modules', () => {
+ const store = useNavigationStore();
+
+ store.togglePinned('item');
+ store.togglePinned('shelving');
+ expect(store.pinnedModules).toEqual(['item', 'shelving']);
+
+ store.togglePinned('item');
+ expect(store.pinnedModules).toEqual(['shelving']);
+ });
+
+ it('should fetch pinned modules', async () => {
+ vi.spyOn(axios, 'get').mockResolvedValue({
+ data: [{ id: 1, workerFk: 9, moduleFk: 'order', position: 1 }],
+ });
+ const store = useNavigationStore();
+ await store.fetchPinned();
+
+ expect(store.pinnedModules).toEqual(['order']);
+ });
+
+ it('should add menu item correctly', () => {
+ const store = useNavigationStore();
+ const module = 'customer';
+ const parent = [];
+ const route = {
+ name: 'customer',
+ title: 'Customer',
+ icon: 'customer',
+ meta: {
+ keyBinding: 'ctrl+shift+c',
+ name: 'customer',
+ title: 'Customer',
+ icon: 'customer',
+ menu: 'customer',
+ menuChildren: [{ name: 'customer', title: 'Customer', icon: 'customer' }],
+ },
+ };
+
+ const result = store.addMenuItem(module, route, parent);
+ const expectedItem = {
+ children: [
+ {
+ icon: 'customer',
+ name: 'customer',
+ title: 'globals.pageTitles.Customer',
+ },
+ ],
+ icon: 'customer',
+ keyBinding: 'ctrl+shift+c',
+ name: 'customer',
+ title: 'globals.pageTitles.Customer',
+ };
+ expect(result).toEqual(expectedItem);
+ expect(parent.length).toBe(1);
+ expect(parent).toEqual([expectedItem]);
+ });
+
+ it('should not add menu item if condition is not met', () => {
+ const store = useNavigationStore();
+ const module = 'testModule';
+ const route = { meta: { hidden: true, menuchildren: {} } };
+ const parent = [];
+ const result = store.addMenuItem(module, route, parent);
+ expect(result).toBeUndefined();
+ expect(parent.length).toBe(0);
+ });
+});
diff --git a/src/stores/useArrayDataStore.js b/src/stores/useArrayDataStore.js
index 8d62fdb4a..b3996d1e3 100644
--- a/src/stores/useArrayDataStore.js
+++ b/src/stores/useArrayDataStore.js
@@ -19,6 +19,7 @@ export const useArrayDataStore = defineStore('arrayDataStore', () => {
page: 1,
mapKey: 'id',
keepData: false,
+ oneRecord: false,
};
function get(key) {
diff --git a/src/utils/notifyResults.js b/src/utils/notifyResults.js
new file mode 100644
index 000000000..e87ad6c6f
--- /dev/null
+++ b/src/utils/notifyResults.js
@@ -0,0 +1,19 @@
+import { Notify } from 'quasar';
+
+export default function (results, key) {
+ results.forEach((result, index) => {
+ if (result.status === 'fulfilled') {
+ const data = JSON.parse(result.value.config.data);
+ Notify.create({
+ type: 'positive',
+ message: `Operación (${index + 1}) ${data[key]} completada con éxito.`,
+ });
+ } else {
+ const data = JSON.parse(result.reason.config.data);
+ Notify.create({
+ type: 'negative',
+ message: `Operación (${index + 1}) ${data[key]} fallida: ${result.reason.message}`,
+ });
+ }
+ });
+}
diff --git a/test/cypress/integration/Order/orderCatalog.spec.js b/test/cypress/integration/Order/orderCatalog.spec.js
index cffc47f91..1770a6b56 100644
--- a/test/cypress/integration/Order/orderCatalog.spec.js
+++ b/test/cypress/integration/Order/orderCatalog.spec.js
@@ -45,7 +45,6 @@ describe('OrderCatalog', () => {
).type('{enter}');
cy.get(':nth-child(1) > [data-cy="catalogFilterCategory"]').click();
cy.dataCy('catalogFilterValueDialogBtn').last().click();
- cy.get('[data-cy="catalogFilterValueDialogTagSelect"]').click();
cy.selectOption("[data-cy='catalogFilterValueDialogTagSelect']", 'Tallos');
cy.dataCy('catalogFilterValueDialogValueInput').find('input').focus();
cy.dataCy('catalogFilterValueDialogValueInput').find('input').type('2');
diff --git a/test/cypress/integration/entry/entryList.spec.js b/test/cypress/integration/entry/entryList.spec.js
new file mode 100644
index 000000000..4f99f0cb6
--- /dev/null
+++ b/test/cypress/integration/entry/entryList.spec.js
@@ -0,0 +1,224 @@
+describe('Entry', () => {
+ beforeEach(() => {
+ cy.viewport(1920, 1080);
+ cy.login('buyer');
+ cy.visit(`/#/entry/list`);
+ });
+
+ it('Filter deleted entries and other fields', () => {
+ createEntry();
+ cy.get('.q-notification__message').eq(0).should('have.text', 'Data created');
+ cy.waitForElement('[data-cy="entry-buys"]');
+ deleteEntry();
+ cy.typeSearchbar('{enter}');
+ cy.get('span[title="Date"]').click().click();
+ cy.typeSearchbar('{enter}');
+ cy.url().should('include', 'order');
+ cy.get('td[data-row-index="0"][data-col-field="landed"]').should(
+ 'have.text',
+ '-',
+ );
+ });
+
+ it('Create entry, modify travel and add buys', () => {
+ createEntryAndBuy();
+ cy.get('a[data-cy="EntryBasicData-menu-item"]').click();
+ selectTravel('two');
+ cy.saveCard();
+ cy.get('.q-notification__message').eq(0).should('have.text', 'Data created');
+ deleteEntry();
+ });
+
+ it('Clone entry and recalculate rates', () => {
+ createEntry();
+
+ cy.waitForElement('[data-cy="entry-buys"]');
+
+ cy.url().then((previousUrl) => {
+ cy.get('[data-cy="descriptor-more-opts"]').click();
+ cy.get('div[data-cy="clone-entry"]').should('be.visible').click();
+
+ cy.get('.q-notification__message').eq(1).should('have.text', 'Entry cloned');
+
+ cy.url()
+ .should('not.eq', previousUrl)
+ .then(() => {
+ cy.waitForElement('[data-cy="entry-buys"]');
+
+ cy.get('[data-cy="descriptor-more-opts"]').click();
+ cy.get('div[data-cy="recalculate-rates"]').click();
+
+ cy.get('.q-notification__message')
+ .eq(2)
+ .should('have.text', 'Entry prices recalculated');
+
+ cy.get('[data-cy="descriptor-more-opts"]').click();
+ deleteEntry();
+
+ cy.log(previousUrl);
+
+ cy.visit(previousUrl);
+
+ cy.waitForElement('[data-cy="entry-buys"]');
+ deleteEntry();
+ });
+ });
+ });
+
+ it('Should notify when entry is lock by another user', () => {
+ const checkLockMessage = () => {
+ cy.get('[data-cy="entry-lock-confirm"]').should('be.visible');
+ cy.get('[data-cy="VnConfirm_message"] > span').should(
+ 'contain.text',
+ 'This entry has been locked by buyerNick',
+ );
+ };
+
+ createEntry();
+ goToEntryBuys();
+ cy.get('.q-notification__message')
+ .eq(1)
+ .should('have.text', 'The entry has been locked successfully');
+
+ cy.login('logistic');
+ cy.reload();
+ checkLockMessage();
+ cy.get('[data-cy="VnConfirm_cancel"]').click();
+ cy.url().should('include', 'summary');
+
+ goToEntryBuys();
+ checkLockMessage();
+ cy.get('[data-cy="VnConfirm_confirm"]').click();
+ cy.url().should('include', 'buys');
+
+ deleteEntry();
+ });
+
+ it('Edit buys and use toolbar actions', () => {
+ const COLORS = {
+ negative: 'rgb(251, 82, 82)',
+ positive: 'rgb(200, 228, 132)',
+ enabled: 'rgb(255, 255, 255)',
+ disable: 'rgb(168, 168, 168)',
+ };
+
+ const selectCell = (field, row = 0) =>
+ cy.get(`td[data-col-field="${field}"][data-row-index="${row}"]`);
+ const selectSpan = (field, row = 0) => selectCell(field, row).find('div > span');
+ const selectButton = (cySelector) => cy.get(`button[data-cy="${cySelector}"]`);
+ const clickAndType = (field, value, row = 0) => {
+ selectCell(field, row).click().type(`${value}{esc}`);
+ };
+ const checkText = (field, expectedText, row = 0) =>
+ selectCell(field, row).should('have.text', expectedText);
+ const checkColor = (field, expectedColor, row = 0) =>
+ selectSpan(field, row).should('have.css', 'color', expectedColor);
+
+ createEntryAndBuy();
+
+ selectCell('isIgnored').click().click().type('{esc}');
+ checkText('isIgnored', 'close');
+
+ clickAndType('stickers', '1');
+ checkText('stickers', '0/01');
+ checkText('quantity', '1');
+ checkText('amount', '50.00');
+ clickAndType('packing', '2');
+ checkText('packing', '12');
+ checkText('weight', '12.0');
+ checkText('quantity', '12');
+ checkText('amount', '600.00');
+ checkColor('packing', COLORS.enabled);
+
+ selectCell('groupingMode').click().click().click();
+ checkColor('packing', COLORS.disable);
+ checkColor('grouping', COLORS.enabled);
+
+ selectCell('buyingValue').click().clear().type('{backspace}{backspace}1');
+ checkText('amount', '12.00');
+ checkColor('minPrice', COLORS.disable);
+
+ selectCell('hasMinPrice').click().click();
+ checkColor('minPrice', COLORS.enabled);
+ selectCell('hasMinPrice').click();
+
+ cy.saveCard();
+ cy.get('span[data-cy="footer-stickers"]').should('have.text', '1');
+ cy.get('.q-notification__message').contains('Data saved');
+
+ selectButton('change-quantity-sign').should('be.disabled');
+ selectButton('check-buy-amount').should('be.disabled');
+ cy.get('tr.cursor-pointer > .q-table--col-auto-width > .q-checkbox').click();
+ selectButton('change-quantity-sign').should('be.enabled');
+ selectButton('check-buy-amount').should('be.enabled');
+
+ selectButton('change-quantity-sign').click();
+ selectButton('set-negative-quantity').click();
+ checkText('quantity', '-12');
+ selectButton('set-positive-quantity').click();
+ checkText('quantity', '12');
+ checkColor('amount', COLORS.disable);
+
+ selectButton('check-buy-amount').click();
+ selectButton('uncheck-amount').click();
+ checkColor('amount', COLORS.disable);
+
+ selectButton('check-amount').click();
+ checkColor('amount', COLORS.positive);
+ cy.saveCard();
+
+ cy.get('span[data-cy="footer-amount"]').should(
+ 'have.css',
+ 'color',
+ COLORS.positive,
+ );
+
+ deleteEntry();
+ });
+
+ function goToEntryBuys() {
+ const entryBuySelector = 'a[data-cy="EntryBuys-menu-item"]';
+ cy.get(entryBuySelector).should('be.visible');
+ cy.waitForElement('[data-cy="entry-buys"]');
+ cy.get(entryBuySelector).click();
+ }
+
+ function deleteEntry() {
+ cy.get('[data-cy="descriptor-more-opts"]').click();
+ cy.waitForElement('div[data-cy="delete-entry"]');
+ cy.get('div[data-cy="delete-entry"]').should('be.visible').click();
+ cy.url().should('include', 'list');
+ }
+
+ function createEntryAndBuy() {
+ createEntry();
+ createBuy();
+ }
+
+ function createEntry() {
+ cy.get('button[data-cy="vnTableCreateBtn"]').click();
+ selectTravel('one');
+ cy.get('button[data-cy="FormModelPopup_save"]').click();
+ cy.url().should('include', 'summary');
+ cy.get('.q-notification__message').eq(0).should('have.text', 'Data created');
+ }
+
+ function selectTravel(warehouse) {
+ cy.get('i[data-cy="Travel_icon"]').click();
+ cy.get('input[data-cy="Warehouse Out_select"]').type(warehouse);
+ cy.get('div[role="listbox"] > div > div[role="option"]').eq(0).click();
+ cy.get('button[data-cy="save-filter-travel-form"]').click();
+ cy.get('tr').eq(1).click();
+ }
+
+ function createBuy() {
+ cy.get('a[data-cy="EntryBuys-menu-item"]').click();
+ cy.get('a[data-cy="EntryBuys-menu-item"]').click();
+ cy.get('button[data-cy="vnTableCreateBtn"]').click();
+
+ cy.get('input[data-cy="itemFk-create-popup"]').type('1');
+ cy.get('div[role="listbox"] > div > div[role="option"]').eq(0).click();
+ cy.get('input[data-cy="Grouping mode_select"]').should('have.value', 'packing');
+ cy.get('button[data-cy="FormModelPopup_save"]').click();
+ }
+});
diff --git a/test/cypress/integration/entry/stockBought.spec.js b/test/cypress/integration/entry/stockBought.spec.js
index 078ad19cc..bc36156b4 100644
--- a/test/cypress/integration/entry/stockBought.spec.js
+++ b/test/cypress/integration/entry/stockBought.spec.js
@@ -6,6 +6,7 @@ describe('EntryStockBought', () => {
});
it('Should edit the reserved space', () => {
cy.get('.q-field__native.q-placeholder').should('have.value', '01/01/2001');
+ cy.get('[data-col-field="reserve"][data-row-index="0"]').click();
cy.get('input[name="reserve"]').type('10{enter}');
cy.get('button[title="Save"]').click();
cy.get('.q-notification__message').should('have.text', 'Data saved');
@@ -15,25 +16,35 @@ describe('EntryStockBought', () => {
cy.get('input[aria-label="Reserve"]').type('1');
cy.get('input[aria-label="Date"]').eq(1).clear();
cy.get('input[aria-label="Date"]').eq(1).type('01-01');
- cy.get('input[aria-label="Buyer"]').type('buyerboss{downarrow}{enter}');
+ cy.get('input[aria-label="Buyer"]').type('buyerBossNick');
+ cy.get('div[role="listbox"] > div > div[role="option"]')
+ .eq(0)
+ .should('be.visible')
+ .click();
+
+ cy.get('[data-cy="FormModelPopup_save"]').click();
cy.get('.q-notification__message').should('have.text', 'Data created');
+
+ cy.get('[data-col-field="reserve"][data-row-index="1"]').click().clear();
+ cy.get('[data-cy="searchBtn"]').eq(1).click();
+ cy.get('.q-table__bottom.row.items-center.q-table__bottom--nodata')
+ .should('have.text', 'warningNo data available')
+ .type('{esc}');
+ cy.get('[data-col-field="reserve"][data-row-index="1"]')
+ .click()
+ .type('{backspace}{enter}');
+ cy.get('[data-cy="crudModelDefaultSaveBtn"]').should('be.enabled').click();
+ cy.get('.q-notification__message').eq(1).should('have.text', 'Data saved');
});
it('Should check detail for the buyer', () => {
- cy.get(':nth-child(1) > .sticky > .q-btn > .q-btn__content > .q-icon').click();
+ cy.get('[data-cy="searchBtn"]').eq(0).click();
cy.get('tBody > tr').eq(1).its('length').should('eq', 1);
});
- it('Should check detail for the buyerBoss and had no content', () => {
- cy.get(':nth-child(2) > .sticky > .q-btn > .q-btn__content > .q-icon').click();
- cy.get('.q-table__bottom.row.items-center.q-table__bottom--nodata').should(
- 'have.text',
- 'warningNo data available'
- );
- });
+
it('Should edit travel m3 and refresh', () => {
- cy.get('.vn-row > div > .q-btn > .q-btn__content > .q-icon').click();
- cy.get('input[aria-label="m3"]').clear();
- cy.get('input[aria-label="m3"]').type('60');
- cy.get('.q-mt-lg > .q-btn--standard > .q-btn__content > .block').click();
+ cy.get('[data-cy="edit-travel"]').should('be.visible').click();
+ cy.get('input[aria-label="m3"]').clear().type('60');
+ cy.get('[data-cy="FormModelPopup_save"]').click();
cy.get('.vn-row > div > :nth-child(2)').should('have.text', '60');
});
});
diff --git a/test/cypress/integration/invoiceIn/invoiceInBasicData.spec.js b/test/cypress/integration/invoiceIn/invoiceInBasicData.spec.js
index 2016fca6d..11ca1bb59 100644
--- a/test/cypress/integration/invoiceIn/invoiceInBasicData.spec.js
+++ b/test/cypress/integration/invoiceIn/invoiceInBasicData.spec.js
@@ -1,9 +1,9 @@
///
describe('InvoiceInBasicData', () => {
- const formInputs = '.q-form > .q-card input';
const firstFormSelect = '.q-card > .vn-row:nth-child(1) > .q-select';
- const documentBtns = '[data-cy="dms-buttons"] button';
const dialogInputs = '.q-dialog input';
+ const resetBtn = '.q-btn-group--push > .q-btn--flat';
+ const getDocumentBtns = (opt) => `[data-cy="dms-buttons"] > :nth-child(${opt})`;
beforeEach(() => {
cy.login('developer');
@@ -11,13 +11,16 @@ describe('InvoiceInBasicData', () => {
});
it('should edit the provideer and supplier ref', () => {
- cy.selectOption(firstFormSelect, 'Bros');
- cy.get('[title="Reset"]').click();
- cy.get(formInputs).eq(1).type('{selectall}4739');
- cy.saveCard();
+ cy.dataCy('UnDeductibleVatSelect').type('4751000000');
+ cy.get('.q-menu .q-item').contains('4751000000').click();
+ cy.get(resetBtn).click();
- cy.get(`${firstFormSelect} input`).invoke('val').should('eq', 'Plants nick');
- cy.get(formInputs).eq(1).invoke('val').should('eq', '4739');
+ cy.waitForElement('#formModel').within(() => {
+ cy.dataCy('vnSupplierSelect').type('Bros nick');
+ })
+ cy.get('.q-menu .q-item').contains('Bros nick').click();
+ cy.saveCard();
+ cy.get(`${firstFormSelect} input`).invoke('val').should('eq', 'Bros nick');
});
it('should edit, remove and create the dms data', () => {
@@ -25,18 +28,18 @@ describe('InvoiceInBasicData', () => {
const secondInput = "I don't know what posting here!";
//edit
- cy.get(documentBtns).eq(1).click();
+ cy.get(getDocumentBtns(2)).click();
cy.get(dialogInputs).eq(0).type(`{selectall}${firtsInput}`);
cy.get('textarea').type(`{selectall}${secondInput}`);
cy.get('[data-cy="FormModelPopup_save"]').click();
- cy.get(documentBtns).eq(1).click();
+ cy.get(getDocumentBtns(2)).click();
cy.get(dialogInputs).eq(0).invoke('val').should('eq', firtsInput);
cy.get('textarea').invoke('val').should('eq', secondInput);
cy.get('[data-cy="FormModelPopup_save"]').click();
cy.checkNotification('Data saved');
//remove
- cy.get(documentBtns).eq(2).click();
+ cy.get(getDocumentBtns(3)).click();
cy.get('[data-cy="VnConfirm_confirm"]').click();
cy.checkNotification('Data saved');
@@ -46,7 +49,7 @@ describe('InvoiceInBasicData', () => {
'test/cypress/fixtures/image.jpg',
{
force: true,
- }
+ },
);
cy.get('[data-cy="FormModelPopup_save"]').click();
cy.checkNotification('Data saved');
diff --git a/test/cypress/integration/invoiceIn/invoiceInVat.spec.js b/test/cypress/integration/invoiceIn/invoiceInVat.spec.js
index f8b403a45..1e7ce1003 100644
--- a/test/cypress/integration/invoiceIn/invoiceInVat.spec.js
+++ b/test/cypress/integration/invoiceIn/invoiceInVat.spec.js
@@ -36,7 +36,7 @@ describe('InvoiceInVat', () => {
cy.get(dialogInputs).eq(0).type(randomInt);
cy.get(dialogInputs).eq(1).type('This is a dummy expense');
- cy.get('button[type="submit"]').click();
+ cy.get('[data-cy="FormModelPopup_save"]').click();
cy.get('.q-notification__message').should('have.text', 'Data created');
});
});
diff --git a/test/cypress/integration/invoiceOut/invoiceOutNegativeBases.spec.js b/test/cypress/integration/invoiceOut/invoiceOutNegativeBases.spec.js
index 5f629df0b..02b7fbb43 100644
--- a/test/cypress/integration/invoiceOut/invoiceOutNegativeBases.spec.js
+++ b/test/cypress/integration/invoiceOut/invoiceOutNegativeBases.spec.js
@@ -7,9 +7,7 @@ describe('InvoiceOut negative bases', () => {
});
it('should filter and download as CSV', () => {
- cy.get(
- ':nth-child(7) > .full-width > :nth-child(1) > .column > div.q-px-xs > .q-field > .q-field__inner > .q-field__control'
- ).type('23{enter}');
+ cy.get('input[name="ticketFk"]').type('23{enter}');
cy.get('#subToolbar > .q-btn').click();
cy.checkNotification('CSV downloaded successfully');
});
diff --git a/test/cypress/integration/item/ItemProposal.spec.js b/test/cypress/integration/item/ItemProposal.spec.js
new file mode 100644
index 000000000..b3ba9f676
--- /dev/null
+++ b/test/cypress/integration/item/ItemProposal.spec.js
@@ -0,0 +1,11 @@
+///
+describe('ItemProposal', () => {
+ beforeEach(() => {
+ const ticketId = 1;
+
+ cy.login('developer');
+ cy.visit(`/#/ticket/${ticketId}/summary`);
+ });
+
+ describe('Handle item proposal selected', () => {});
+});
diff --git a/test/cypress/integration/item/itemTag.spec.js b/test/cypress/integration/item/itemTag.spec.js
index 10d68d08a..d1596f693 100644
--- a/test/cypress/integration/item/itemTag.spec.js
+++ b/test/cypress/integration/item/itemTag.spec.js
@@ -13,7 +13,7 @@ describe('Item tag', () => {
cy.dataCy('Tag_select').eq(7).type('Tallos');
cy.get('.q-menu .q-item').contains('Tallos').click();
cy.get(':nth-child(8) > [label="Value"]').type('1');
- +cy.dataCy('crudModelDefaultSaveBtn').click();
+ cy.dataCy('crudModelDefaultSaveBtn').click();
cy.checkNotification("The tag or priority can't be repeated for an item");
});
@@ -26,8 +26,11 @@ describe('Item tag', () => {
cy.get(':nth-child(8) > [label="Value"]').type('50');
cy.dataCy('crudModelDefaultSaveBtn').click();
cy.checkNotification('Data saved');
- cy.dataCy('itemTags').children(':nth-child(8)').find('.justify-center > .q-icon').click();
+ cy.dataCy('itemTags')
+ .children(':nth-child(8)')
+ .find('.justify-center > .q-icon')
+ .click();
cy.dataCy('VnConfirm_confirm').click();
cy.checkNotification('Data saved');
});
-});
\ No newline at end of file
+});
diff --git a/test/cypress/integration/parking/parkingBasicData.spec.js b/test/cypress/integration/parking/parkingBasicData.spec.js
index 0d130d335..f64f23ec8 100644
--- a/test/cypress/integration/parking/parkingBasicData.spec.js
+++ b/test/cypress/integration/parking/parkingBasicData.spec.js
@@ -13,11 +13,11 @@ describe('ParkingBasicData', () => {
cy.get(sectorOpt).click();
cy.get(codeInput).eq(0).clear();
- cy.get(codeInput).eq(0).type(123);
+ cy.get(codeInput).eq(0).type('900-001');
cy.saveCard();
cy.get(sectorSelect).should('have.value', 'Second sector');
- cy.get(codeInput).should('have.value', 123);
+ cy.get(codeInput).should('have.value', '900-001');
});
});
diff --git a/test/cypress/integration/route/agency/agencyWorkCenter.spec.js b/test/cypress/integration/route/agency/agencyWorkCenter.spec.js
index e28caea7c..82ec6626d 100644
--- a/test/cypress/integration/route/agency/agencyWorkCenter.spec.js
+++ b/test/cypress/integration/route/agency/agencyWorkCenter.spec.js
@@ -15,6 +15,7 @@ describe('AgencyWorkCenter', () => {
// expect error when duplicate
cy.get(createButton).click();
+ cy.selectOption(workCenterCombobox, 'workCenterOne');
cy.get('[data-cy="FormModelPopup_save"]').click();
cy.checkNotification('This workCenter is already assigned to this agency');
cy.get('[data-cy="FormModelPopup_cancel"]').click();
diff --git a/test/cypress/integration/route/routeList.spec.js b/test/cypress/integration/route/routeList.spec.js
index 4da43ce8e..976ce7352 100644
--- a/test/cypress/integration/route/routeList.spec.js
+++ b/test/cypress/integration/route/routeList.spec.js
@@ -4,9 +4,6 @@ describe('Route', () => {
cy.login('developer');
cy.visit(`/#/route/extended-list`);
});
- const getVnSelect =
- '> :nth-child(1) > .column > .q-field > .q-field__inner > .q-field__control > .q-field__control-container';
- const getRowColumn = (row, column) => `:nth-child(${row}) > :nth-child(${column})`;
it('Route list create route', () => {
cy.addBtnClick();
@@ -17,15 +14,23 @@ describe('Route', () => {
it('Route list search and edit', () => {
cy.get('#searchbar input').type('{enter}');
- cy.get('input[name="description"]').type('routeTestOne{enter}');
+ cy.get('[data-col-field="description"][data-row-index="0"]')
+ .click()
+ .type('routeTestOne{enter}');
cy.get('.q-table tr')
.its('length')
.then((rowCount) => {
expect(rowCount).to.be.greaterThan(0);
});
- cy.get(getRowColumn(1, 3) + getVnSelect).type('{downArrow}{enter}');
- cy.get(getRowColumn(1, 4) + getVnSelect).type('{downArrow}{enter}');
- cy.get(getRowColumn(1, 5) + getVnSelect).type('{downArrow}{enter}');
+ cy.get('[data-col-field="workerFk"][data-row-index="0"]')
+ .click()
+ .type('{downArrow}{enter}');
+ cy.get('[data-col-field="agencyModeFk"][data-row-index="0"]')
+ .click()
+ .type('{downArrow}{enter}');
+ cy.get('[data-col-field="vehicleFk"][data-row-index="0"]')
+ .click()
+ .type('{downArrow}{enter}');
cy.get('button[title="Save"]').click();
cy.get('.q-notification__message').should('have.text', 'Data saved');
});
diff --git a/test/cypress/integration/route/vehicle/vehicleDescriptor.spec.js b/test/cypress/integration/route/vehicle/vehicleDescriptor.spec.js
new file mode 100644
index 000000000..64b9ca0a0
--- /dev/null
+++ b/test/cypress/integration/route/vehicle/vehicleDescriptor.spec.js
@@ -0,0 +1,13 @@
+describe('Vehicle', () => {
+ beforeEach(() => {
+ cy.viewport(1920, 1080);
+ cy.login('deliveryAssistant');
+ cy.visit(`/#/route/vehicle/7`);
+ });
+
+ it('should delete a vehicle', () => {
+ cy.openActionsDescriptor();
+ cy.get('[data-cy="delete"]').click();
+ cy.checkNotification('Vehicle removed');
+ });
+});
diff --git a/test/cypress/integration/ticket/negative/TicketLackDetail.spec.js b/test/cypress/integration/ticket/negative/TicketLackDetail.spec.js
new file mode 100644
index 000000000..9ea1cff63
--- /dev/null
+++ b/test/cypress/integration/ticket/negative/TicketLackDetail.spec.js
@@ -0,0 +1,147 @@
+///
+describe('Ticket Lack detail', () => {
+ beforeEach(() => {
+ cy.login('developer');
+ cy.intercept('GET', /\/api\/Tickets\/itemLack\/5.*$/, {
+ statusCode: 200,
+ body: [
+ {
+ saleFk: 33,
+ code: 'OK',
+ ticketFk: 142,
+ nickname: 'Malibu Point',
+ shipped: '2000-12-31T23:00:00.000Z',
+ hour: 0,
+ quantity: 50,
+ agName: 'Super-Man delivery',
+ alertLevel: 0,
+ stateName: 'OK',
+ stateId: 3,
+ itemFk: 5,
+ price: 1.79,
+ alertLevelCode: 'FREE',
+ zoneFk: 9,
+ zoneName: 'Zone superMan',
+ theoreticalhour: '2011-11-01T22:59:00.000Z',
+ isRookie: 1,
+ turno: 1,
+ peticionCompra: 1,
+ hasObservation: 1,
+ hasToIgnore: 1,
+ isBasket: 1,
+ minTimed: 0,
+ customerId: 1104,
+ customerName: 'Tony Stark',
+ observationTypeCode: 'administrative',
+ },
+ ],
+ }).as('getItemLack');
+
+ cy.visit('/#/ticket/negative/5');
+ cy.wait('@getItemLack');
+ });
+ describe('Table actions', () => {
+ it.skip('should display only one row in the lack list', () => {
+ cy.location('href').should('contain', '#/ticket/negative/5');
+
+ cy.get('[data-cy="changeItem"]').should('be.disabled');
+ cy.get('[data-cy="changeState"]').should('be.disabled');
+ cy.get('[data-cy="changeQuantity"]').should('be.disabled');
+ cy.get('[data-cy="itemProposal"]').should('be.disabled');
+ cy.get('[data-cy="transferLines"]').should('be.disabled');
+ cy.get('tr.cursor-pointer > :nth-child(1)').click();
+ cy.get('[data-cy="changeItem"]').should('be.enabled');
+ cy.get('[data-cy="changeState"]').should('be.enabled');
+ cy.get('[data-cy="changeQuantity"]').should('be.enabled');
+ cy.get('[data-cy="itemProposal"]').should('be.enabled');
+ cy.get('[data-cy="transferLines"]').should('be.enabled');
+ });
+ });
+ describe('Item proposal', () => {
+ beforeEach(() => {
+ cy.get('tr.cursor-pointer > :nth-child(1)').click();
+
+ cy.intercept('GET', /\/api\/Items\/getSimilar\?.*$/, {
+ statusCode: 200,
+ body: [
+ {
+ id: 1,
+ longName: 'Ranged weapon longbow 50cm',
+ subName: 'Stark Industries',
+ tag5: 'Color',
+ value5: 'Brown',
+ match5: 0,
+ match6: 0,
+ match7: 0,
+ match8: 1,
+ tag6: 'Categoria',
+ value6: '+1 precission',
+ tag7: 'Tallos',
+ value7: '1',
+ tag8: null,
+ value8: null,
+ available: 20,
+ calc_id: 6,
+ counter: 0,
+ minQuantity: 1,
+ visible: null,
+ price2: 1,
+ },
+ {
+ id: 2,
+ longName: 'Ranged weapon longbow 100cm',
+ subName: 'Stark Industries',
+ tag5: 'Color',
+ value5: 'Brown',
+ match5: 0,
+ match6: 1,
+ match7: 0,
+ match8: 1,
+ tag6: 'Categoria',
+ value6: '+1 precission',
+ tag7: 'Tallos',
+ value7: '1',
+ tag8: null,
+ value8: null,
+ available: 50,
+ calc_id: 6,
+ counter: 1,
+ minQuantity: 5,
+ visible: null,
+ price2: 10,
+ },
+ {
+ id: 3,
+ longName: 'Ranged weapon longbow 200cm',
+ subName: 'Stark Industries',
+ tag5: 'Color',
+ value5: 'Brown',
+ match5: 1,
+ match6: 1,
+ match7: 1,
+ match8: 1,
+ tag6: 'Categoria',
+ value6: '+1 precission',
+ tag7: 'Tallos',
+ value7: '1',
+ tag8: null,
+ value8: null,
+ available: 185,
+ calc_id: 6,
+ counter: 10,
+ minQuantity: 10,
+ visible: null,
+ price2: 100,
+ },
+ ],
+ }).as('getItemGetSimilar');
+ cy.get('[data-cy="itemProposal"]').click();
+ cy.wait('@getItemGetSimilar');
+ });
+ describe('Replace item if', () => {
+ it.only('Quantity is less than available', () => {
+ cy.get(':nth-child(1) > .text-right > .q-btn').click();
+ });
+ });
+ });
+});
diff --git a/test/cypress/integration/ticket/negative/TicketLackList.spec.js b/test/cypress/integration/ticket/negative/TicketLackList.spec.js
new file mode 100644
index 000000000..01ab4f621
--- /dev/null
+++ b/test/cypress/integration/ticket/negative/TicketLackList.spec.js
@@ -0,0 +1,36 @@
+///
+describe('Ticket Lack list', () => {
+ beforeEach(() => {
+ cy.login('developer');
+ cy.intercept('GET', /Tickets\/itemLack\?.*$/, {
+ statusCode: 200,
+ body: [
+ {
+ itemFk: 5,
+ longName: 'Ranged weapon pistol 9mm',
+ warehouseFk: 1,
+ producer: null,
+ size: 15,
+ category: null,
+ warehouse: 'Warehouse One',
+ lack: -50,
+ inkFk: 'SLV',
+ timed: '2025-01-25T22:59:00.000Z',
+ minTimed: '23:59',
+ originFk: 'Holand',
+ },
+ ],
+ }).as('getLack');
+
+ cy.visit('/#/ticket/negative');
+ });
+
+ describe('Table actions', () => {
+ it('should display only one row in the lack list', () => {
+ cy.wait('@getLack', { timeout: 10000 });
+
+ cy.get('.q-virtual-scroll__content > :nth-child(1) > .sticky').click();
+ cy.location('href').should('contain', '#/ticket/negative/5');
+ });
+ });
+});
diff --git a/test/cypress/integration/ticket/ticketList.spec.js b/test/cypress/integration/ticket/ticketList.spec.js
index 2984a4ee4..593021e6e 100644
--- a/test/cypress/integration/ticket/ticketList.spec.js
+++ b/test/cypress/integration/ticket/ticketList.spec.js
@@ -53,4 +53,29 @@ describe('TicketList', () => {
cy.checkNotification('Data created');
cy.url().should('match', /\/ticket\/\d+\/summary/);
});
+
+ it('should show the corerct problems', () => {
+ cy.intercept('GET', '**/api/Tickets/filter*', (req) => {
+ req.headers['cache-control'] = 'no-cache';
+ req.headers['pragma'] = 'no-cache';
+ req.headers['expires'] = '0';
+
+ req.on('response', (res) => {
+ delete res.headers['if-none-match'];
+ delete res.headers['if-modified-since'];
+ });
+ }).as('ticket');
+
+ cy.get('[data-cy="Warehouse_select"]').type('Warehouse Five');
+ cy.get('.q-menu .q-item').contains('Warehouse Five').click();
+ cy.wait('@ticket').then((interception) => {
+ const data = interception.response.body[1];
+ expect(data.hasComponentLack).to.equal(1);
+ expect(data.isTooLittle).to.equal(1);
+ expect(data.hasItemShortage).to.equal(1);
+ });
+ cy.get('.icon-components').should('exist');
+ cy.get('.icon-unavailable').should('exist');
+ cy.get('.icon-isTooLittle').should('exist');
+ });
});
diff --git a/test/cypress/integration/vnComponent/VnShortcut.spec.js b/test/cypress/integration/vnComponent/VnShortcut.spec.js
index b49b4e964..e08c44635 100644
--- a/test/cypress/integration/vnComponent/VnShortcut.spec.js
+++ b/test/cypress/integration/vnComponent/VnShortcut.spec.js
@@ -28,6 +28,17 @@ describe('VnShortcuts', () => {
});
cy.url().should('include', module);
+ if (['monitor', 'claim'].includes(module)) {
+ return;
+ }
+ cy.waitForElement('.q-page').should('exist');
+ cy.dataCy('vnTableCreateBtn').should('exist');
+ cy.get('.q-page').trigger('keydown', {
+ ctrlKey: true,
+ altKey: true,
+ key: '+',
+ });
+ cy.get('#formModel').should('exist');
});
}
});
diff --git a/test/cypress/integration/wagon/wagonType/wagonTypeCreate.spec.js b/test/cypress/integration/wagon/wagonType/wagonTypeCreate.spec.js
index 343c1c127..2cd43984a 100644
--- a/test/cypress/integration/wagon/wagonType/wagonTypeCreate.spec.js
+++ b/test/cypress/integration/wagon/wagonType/wagonTypeCreate.spec.js
@@ -9,7 +9,7 @@ describe('WagonTypeCreate', () => {
it('should create a new wagon type and then delete it', () => {
cy.get('.q-page-sticky > div > .q-btn').click();
cy.get('input').first().type('Example for testing');
- cy.get('button[type="submit"]').click();
+ cy.get('[data-cy="FormModelPopup_save"]').click();
cy.get('[title="Remove"] > .q-btn__content > .q-icon').first().click();
});
});
diff --git a/test/cypress/integration/zone/zoneBasicData.spec.js b/test/cypress/integration/zone/zoneBasicData.spec.js
index 95a075fb3..70ded3f79 100644
--- a/test/cypress/integration/zone/zoneBasicData.spec.js
+++ b/test/cypress/integration/zone/zoneBasicData.spec.js
@@ -1,5 +1,6 @@
describe('ZoneBasicData', () => {
const priceBasicData = '[data-cy="Price_input"]';
+ const saveBtn = '.q-btn-group > .q-btn--standard';
beforeEach(() => {
cy.viewport(1280, 720);
@@ -8,20 +9,27 @@ describe('ZoneBasicData', () => {
});
it('should throw an error if the name is empty', () => {
- cy.get('[data-cy="zone-basic-data-name"] input').type('{selectall}{backspace}');
- cy.get('.q-btn-group > .q-btn--standard').click();
+ cy.intercept('GET', /\/api\/Zones\/4./).as('zone');
+
+ cy.wait('@zone').then(() => {
+ cy.get('[data-cy="zone-basic-data-name"] input').type(
+ '{selectall}{backspace}',
+ );
+ });
+
+ cy.get(saveBtn).click();
cy.checkNotification("can't be blank");
});
it('should throw an error if the price is empty', () => {
cy.get(priceBasicData).clear();
- cy.get('.q-btn-group > .q-btn--standard').click();
+ cy.get(saveBtn).click();
cy.checkNotification('cannot be blank');
});
it("should edit the basicData's zone", () => {
cy.get('.q-card > :nth-child(1)').type(' modified');
- cy.get('.q-btn-group > .q-btn--standard').click();
+ cy.get(saveBtn).click();
cy.checkNotification('Data saved');
});
});
diff --git a/test/cypress/support/commands.js b/test/cypress/support/commands.js
index 2c93fbf84..aa4a1219e 100755
--- a/test/cypress/support/commands.js
+++ b/test/cypress/support/commands.js
@@ -87,36 +87,55 @@ Cypress.Commands.add('getValue', (selector) => {
});
// Fill Inputs
-Cypress.Commands.add('selectOption', (selector, option, timeout = 5000) => {
+Cypress.Commands.add('selectOption', (selector, option, timeout = 2500) => {
cy.waitForElement(selector, timeout);
- cy.get(selector).click();
- cy.get(selector).invoke('data', 'url').as('dataUrl');
- cy.get(selector)
- .clear()
- .type(option)
- .then(() => {
- cy.get('.q-menu', { timeout })
- .should('be.visible') // Asegurarse de que el menú está visible
- .and('exist') // Verificar que el menú existe
- .then(() => {
- cy.get('@dataUrl').then((url) => {
- if (url) {
- // Esperar a que el menú no esté visible (desaparezca)
- cy.get('.q-menu').should('not.be.visible');
- // Ahora esperar a que el menú vuelva a aparecer
- cy.get('.q-menu').should('be.visible').and('exist');
- }
- });
- });
- });
- // Finalmente, seleccionar la opción deseada
- cy.get('.q-menu:visible') // Asegurarse de que estamos dentro del menú visible
- .find('.q-item') // Encontrar los elementos de las opciones
- .contains(option) // Verificar que existe una opción que contenga el texto deseado
- .click(); // Hacer clic en la opción
+ cy.get(selector, { timeout })
+ .should('exist')
+ .should('be.visible')
+ .click()
+ .then(($el) => {
+ cy.wrap($el.is('input') ? $el : $el.find('input'))
+ .invoke('attr', 'aria-controls')
+ .then((ariaControl) => selectItem(selector, option, ariaControl));
+ });
});
+function selectItem(selector, option, ariaControl, hasWrite = true) {
+ if (!hasWrite) cy.wait(100);
+
+ getItems(ariaControl).then((items) => {
+ const matchingItem = items
+ .toArray()
+ .find((item) => item.innerText.includes(option));
+ if (matchingItem) return cy.wrap(matchingItem).click();
+
+ if (hasWrite) cy.get(selector).clear().type(option, { delay: 0 });
+ return selectItem(selector, option, ariaControl, false);
+ });
+}
+
+function getItems(ariaControl, startTime = Cypress._.now(), timeout = 2500) {
+ // Se intenta obtener la lista de opciones del desplegable de manera recursiva
+ return cy
+ .get('#' + ariaControl, { timeout })
+ .should('exist')
+ .find('.q-item')
+ .should('exist')
+ .then(($items) => {
+ if (!$items?.length || $items.first().text().trim() === '') {
+ if (Cypress._.now() - startTime > timeout) {
+ throw new Error(
+ `getItems: Tiempo de espera (${timeout}ms) excedido.`,
+ );
+ }
+ return getItems(ariaControl, startTime, timeout);
+ }
+
+ return cy.wrap($items);
+ });
+}
+
Cypress.Commands.add('countSelectOptions', (selector, option) => {
cy.waitForElement(selector);
cy.get(selector).click({ force: true });
diff --git a/test/cypress/support/waitUntil.js b/test/cypress/support/waitUntil.js
index 5fb47a2d8..359f8643f 100644
--- a/test/cypress/support/waitUntil.js
+++ b/test/cypress/support/waitUntil.js
@@ -1,7 +1,7 @@
const waitUntil = (subject, checkFunction, originalOptions = {}) => {
if (!(checkFunction instanceof Function)) {
throw new Error(
- '`checkFunction` parameter should be a function. Found: ' + checkFunction
+ '`checkFunction` parameter should be a function. Found: ' + checkFunction,
);
}