#6919 syncData #941
144
package.json
144
package.json
|
@ -1,74 +1,74 @@
|
||||||
{
|
{
|
||||||
"name": "salix-front",
|
"name": "salix-front",
|
||||||
"version": "25.06.0",
|
"version": "25.08.0",
|
||||||
"description": "Salix frontend",
|
"description": "Salix frontend",
|
||||||
"productName": "Salix",
|
"productName": "Salix",
|
||||||
"author": "Verdnatura",
|
"author": "Verdnatura",
|
||||||
"private": true,
|
"private": true,
|
||||||
"packageManager": "pnpm@8.15.1",
|
"packageManager": "pnpm@8.15.1",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"resetDatabase": "cd ../salix && gulp docker",
|
"resetDatabase": "cd ../salix && gulp docker",
|
||||||
"lint": "eslint --ext .js,.vue ./",
|
"lint": "eslint --ext .js,.vue ./",
|
||||||
"format": "prettier --write \"**/*.{js,vue,scss,html,md,json}\" --ignore-path .gitignore",
|
"format": "prettier --write \"**/*.{js,vue,scss,html,md,json}\" --ignore-path .gitignore",
|
||||||
"test:e2e": "cypress open",
|
"test:e2e": "cypress open",
|
||||||
"test:e2e:ci": "npm run resetDatabase && cd ../salix-front && cypress run",
|
"test:e2e:ci": "npm run resetDatabase && cd ../salix-front && cypress run",
|
||||||
"test": "echo \"See package.json => scripts for available tests.\" && exit 0",
|
"test": "echo \"See package.json => scripts for available tests.\" && exit 0",
|
||||||
"test:unit": "vitest",
|
"test:unit": "vitest",
|
||||||
"test:unit:ci": "vitest run",
|
"test:unit:ci": "vitest run",
|
||||||
"commitlint": "commitlint --edit",
|
"commitlint": "commitlint --edit",
|
||||||
"prepare": "npx husky install",
|
"prepare": "npx husky install",
|
||||||
"addReferenceTag": "node .husky/addReferenceTag.js",
|
"addReferenceTag": "node .husky/addReferenceTag.js",
|
||||||
"docs:dev": "vitepress dev docs",
|
"docs:dev": "vitepress dev docs",
|
||||||
"docs:build": "vitepress build docs",
|
"docs:build": "vitepress build docs",
|
||||||
"docs:preview": "vitepress preview docs"
|
"docs:preview": "vitepress preview docs"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@quasar/cli": "^2.4.1",
|
"@quasar/cli": "^2.4.1",
|
||||||
"@quasar/extras": "^1.16.16",
|
"@quasar/extras": "^1.16.16",
|
||||||
"axios": "^1.4.0",
|
"axios": "^1.4.0",
|
||||||
"chromium": "^3.0.3",
|
"chromium": "^3.0.3",
|
||||||
"croppie": "^2.6.5",
|
"croppie": "^2.6.5",
|
||||||
"moment": "^2.30.1",
|
"moment": "^2.30.1",
|
||||||
"pinia": "^2.1.3",
|
"pinia": "^2.1.3",
|
||||||
"quasar": "^2.17.7",
|
"quasar": "^2.17.7",
|
||||||
"validator": "^13.9.0",
|
"validator": "^13.9.0",
|
||||||
"vue": "^3.5.13",
|
"vue": "^3.5.13",
|
||||||
"vue-i18n": "^9.3.0",
|
"vue-i18n": "^9.3.0",
|
||||||
"vue-router": "^4.2.5"
|
"vue-router": "^4.2.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@commitlint/cli": "^19.2.1",
|
"@commitlint/cli": "^19.2.1",
|
||||||
"@commitlint/config-conventional": "^19.1.0",
|
"@commitlint/config-conventional": "^19.1.0",
|
||||||
"@intlify/unplugin-vue-i18n": "^0.8.2",
|
"@intlify/unplugin-vue-i18n": "^0.8.2",
|
||||||
"@pinia/testing": "^0.1.2",
|
"@pinia/testing": "^0.1.2",
|
||||||
"@quasar/app-vite": "^2.0.8",
|
"@quasar/app-vite": "^2.0.8",
|
||||||
"@quasar/quasar-app-extension-qcalendar": "^4.0.2",
|
"@quasar/quasar-app-extension-qcalendar": "^4.0.2",
|
||||||
"@quasar/quasar-app-extension-testing-unit-vitest": "^0.4.0",
|
"@quasar/quasar-app-extension-testing-unit-vitest": "^0.4.0",
|
||||||
"@vue/test-utils": "^2.4.4",
|
"@vue/test-utils": "^2.4.4",
|
||||||
"autoprefixer": "^10.4.14",
|
"autoprefixer": "^10.4.14",
|
||||||
"cypress": "^13.6.6",
|
"cypress": "^13.6.6",
|
||||||
"cypress-mochawesome-reporter": "^3.8.2",
|
"cypress-mochawesome-reporter": "^3.8.2",
|
||||||
"eslint": "^9.18.0",
|
"eslint": "^9.18.0",
|
||||||
"eslint-config-prettier": "^10.0.1",
|
"eslint-config-prettier": "^10.0.1",
|
||||||
"eslint-plugin-cypress": "^4.1.0",
|
"eslint-plugin-cypress": "^4.1.0",
|
||||||
"eslint-plugin-vue": "^9.32.0",
|
"eslint-plugin-vue": "^9.32.0",
|
||||||
"husky": "^8.0.0",
|
"husky": "^8.0.0",
|
||||||
"postcss": "^8.4.23",
|
"postcss": "^8.4.23",
|
||||||
"prettier": "^3.4.2",
|
"prettier": "^3.4.2",
|
||||||
"sass": "^1.83.4",
|
"sass": "^1.83.4",
|
||||||
"vitepress": "^1.6.3",
|
"vitepress": "^1.6.3",
|
||||||
"vitest": "^0.34.0"
|
"vitest": "^0.34.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^20 || ^18 || ^16",
|
"node": "^20 || ^18 || ^16",
|
||||||
"npm": ">= 8.1.2",
|
"npm": ">= 8.1.2",
|
||||||
"yarn": ">= 1.21.1",
|
"yarn": ">= 1.21.1",
|
||||||
"bun": ">= 1.0.25"
|
"bun": ">= 1.0.25"
|
||||||
},
|
},
|
||||||
"overrides": {
|
"overrides": {
|
||||||
"@vitejs/plugin-vue": "^5.2.1",
|
"@vitejs/plugin-vue": "^5.2.1",
|
||||||
"vite": "^6.0.11",
|
"vite": "^6.0.11",
|
||||||
"vitest": "^0.31.1"
|
"vitest": "^0.31.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -10,12 +10,13 @@ import routes from 'src/router/modules';
|
||||||
import LeftMenuItem from './LeftMenuItem.vue';
|
import LeftMenuItem from './LeftMenuItem.vue';
|
||||||
import LeftMenuItemGroup from './LeftMenuItemGroup.vue';
|
import LeftMenuItemGroup from './LeftMenuItemGroup.vue';
|
||||||
import VnInput from './common/VnInput.vue';
|
import VnInput from './common/VnInput.vue';
|
||||||
|
import { useRouter } from 'vue-router';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const quasar = useQuasar();
|
const quasar = useQuasar();
|
||||||
const navigation = useNavigationStore();
|
const navigation = useNavigationStore();
|
||||||
|
const router = useRouter();
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
source: {
|
source: {
|
||||||
type: String,
|
type: String,
|
||||||
|
@ -174,6 +175,10 @@ function normalize(text) {
|
||||||
.replace(/[\u0300-\u036f]/g, '')
|
.replace(/[\u0300-\u036f]/g, '')
|
||||||
.toLowerCase();
|
.toLowerCase();
|
||||||
}
|
}
|
||||||
|
const searchModule = () => {
|
||||||
|
const [item] = filteredItems.value;
|
||||||
|
if (item) router.push({ name: item.name });
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -188,10 +193,11 @@ function normalize(text) {
|
||||||
filled
|
filled
|
||||||
dense
|
dense
|
||||||
autofocus
|
autofocus
|
||||||
|
@keyup.enter.stop="searchModule()"
|
||||||
/>
|
/>
|
||||||
</QItem>
|
</QItem>
|
||||||
<QSeparator />
|
<QSeparator />
|
||||||
<template v-if="filteredPinnedModules.size">
|
<template v-if="filteredPinnedModules.size && !search">
|
||||||
<LeftMenuItem
|
<LeftMenuItem
|
||||||
v-for="[key, pinnedModule] of filteredPinnedModules"
|
v-for="[key, pinnedModule] of filteredPinnedModules"
|
||||||
:key="key"
|
:key="key"
|
||||||
|
@ -215,11 +221,11 @@ function normalize(text) {
|
||||||
</LeftMenuItem>
|
</LeftMenuItem>
|
||||||
<QSeparator />
|
<QSeparator />
|
||||||
</template>
|
</template>
|
||||||
<template v-for="item in filteredItems" :key="item.name">
|
<template v-for="(item, index) in filteredItems" :key="item.name">
|
||||||
<template
|
<template
|
||||||
v-if="item.children && !filteredPinnedModules.has(item.name)"
|
v-if="search ||item.children && !filteredPinnedModules.has(item.name)"
|
||||||
>
|
>
|
||||||
<LeftMenuItem :item="item" group="modules">
|
<LeftMenuItem :item="item" group="modules" :class="search && index === 0 ? 'searched' : ''">
|
||||||
<template #side>
|
<template #side>
|
||||||
<QBtn
|
<QBtn
|
||||||
v-if="item.isPinned === true"
|
v-if="item.isPinned === true"
|
||||||
|
@ -336,6 +342,9 @@ function normalize(text) {
|
||||||
.header {
|
.header {
|
||||||
color: var(--vn-label-color);
|
color: var(--vn-label-color);
|
||||||
}
|
}
|
||||||
|
.searched{
|
||||||
|
background-color: var(--vn-section-hover-color);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
<i18n>
|
<i18n>
|
||||||
es:
|
es:
|
||||||
|
|
|
@ -2,26 +2,9 @@
|
||||||
defineProps({ row: { type: Object, required: true } });
|
defineProps({ row: { type: Object, required: true } });
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<span>
|
<span class="q-gutter-x-xs">
|
||||||
<QIcon
|
<QIcon
|
||||||
v-if="row.isTaxDataChecked === 0"
|
v-if="row?.risk"
|
||||||
name="vn:no036"
|
|
||||||
color="primary"
|
|
||||||
size="xs"
|
|
||||||
>
|
|
||||||
<QTooltip>{{ $t('salesTicketsTable.noVerifiedData') }}</QTooltip>
|
|
||||||
</QIcon>
|
|
||||||
<QIcon v-if="row.hasTicketRequest" name="vn:buyrequest" color="primary" size="xs">
|
|
||||||
<QTooltip>{{ $t('salesTicketsTable.purchaseRequest') }}</QTooltip>
|
|
||||||
</QIcon>
|
|
||||||
<QIcon v-if="row.itemShortage" name="vn:unavailable" color="primary" size="xs">
|
|
||||||
<QTooltip>{{ $t('salesTicketsTable.notVisible') }}</QTooltip>
|
|
||||||
</QIcon>
|
|
||||||
<QIcon v-if="row.isFreezed" name="vn:frozen" color="primary" size="xs">
|
|
||||||
<QTooltip>{{ $t('salesTicketsTable.clientFrozen') }}</QTooltip>
|
|
||||||
</QIcon>
|
|
||||||
<QIcon
|
|
||||||
v-if="row.risk"
|
|
||||||
name="vn:risk"
|
name="vn:risk"
|
||||||
:color="row.hasHighRisk ? 'negative' : 'primary'"
|
:color="row.hasHighRisk ? 'negative' : 'primary'"
|
||||||
size="xs"
|
size="xs"
|
||||||
|
@ -30,10 +13,57 @@ defineProps({ row: { type: Object, required: true } });
|
||||||
{{ $t('salesTicketsTable.risk') }}: {{ row.risk - row.credit }}
|
{{ $t('salesTicketsTable.risk') }}: {{ row.risk - row.credit }}
|
||||||
</QTooltip>
|
</QTooltip>
|
||||||
</QIcon>
|
</QIcon>
|
||||||
<QIcon v-if="row.hasComponentLack" name="vn:components" color="primary" size="xs">
|
<QIcon
|
||||||
|
v-if="row?.hasComponentLack"
|
||||||
|
name="vn:components"
|
||||||
|
color="primary"
|
||||||
|
size="xs"
|
||||||
|
>
|
||||||
<QTooltip>{{ $t('salesTicketsTable.componentLack') }}</QTooltip>
|
<QTooltip>{{ $t('salesTicketsTable.componentLack') }}</QTooltip>
|
||||||
</QIcon>
|
</QIcon>
|
||||||
<QIcon v-if="row.isTooLittle" name="vn:isTooLittle" color="primary" size="xs">
|
<QIcon v-if="row?.hasItemDelay" color="primary" size="xs" name="vn:hasItemDelay">
|
||||||
|
<QTooltip>
|
||||||
|
{{ $t('ticket.summary.hasItemDelay') }}
|
||||||
|
</QTooltip>
|
||||||
|
</QIcon>
|
||||||
|
<QIcon v-if="row?.hasItemLost" color="primary" size="xs" name="vn:hasItemLost">
|
||||||
|
<QTooltip>
|
||||||
|
{{ $t('salesTicketsTable.hasItemLost') }}
|
||||||
|
</QTooltip>
|
||||||
|
</QIcon>
|
||||||
|
<QIcon
|
||||||
|
v-if="row?.hasItemShortage"
|
||||||
|
name="vn:unavailable"
|
||||||
|
color="primary"
|
||||||
|
size="xs"
|
||||||
|
>
|
||||||
|
<QTooltip>{{ $t('salesTicketsTable.notVisible') }}</QTooltip>
|
||||||
|
</QIcon>
|
||||||
|
<QIcon v-if="row?.hasRounding" color="primary" name="sync_problem" size="xs">
|
||||||
|
<QTooltip>
|
||||||
|
{{ $t('ticketList.rounding') }}
|
||||||
|
</QTooltip>
|
||||||
|
</QIcon>
|
||||||
|
<QIcon
|
||||||
|
v-if="row?.hasTicketRequest"
|
||||||
|
name="vn:buyrequest"
|
||||||
|
color="primary"
|
||||||
|
size="xs"
|
||||||
|
>
|
||||||
|
<QTooltip>{{ $t('salesTicketsTable.purchaseRequest') }}</QTooltip>
|
||||||
|
</QIcon>
|
||||||
|
<QIcon
|
||||||
|
v-if="!row?.isTaxDataChecked === 0"
|
||||||
|
name="vn:no036"
|
||||||
|
color="primary"
|
||||||
|
size="xs"
|
||||||
|
>
|
||||||
|
<QTooltip>{{ $t('salesTicketsTable.noVerifiedData') }}</QTooltip>
|
||||||
|
</QIcon>
|
||||||
|
<QIcon v-if="row?.isFreezed" name="vn:frozen" color="primary" size="xs">
|
||||||
|
<QTooltip>{{ $t('salesTicketsTable.clientFrozen') }}</QTooltip>
|
||||||
|
</QIcon>
|
||||||
|
<QIcon v-if="row?.isTooLittle" name="vn:isTooLittle" color="primary" size="xs">
|
||||||
<QTooltip>{{ $t('salesTicketsTable.tooLittle') }}</QTooltip>
|
<QTooltip>{{ $t('salesTicketsTable.tooLittle') }}</QTooltip>
|
||||||
</QIcon>
|
</QIcon>
|
||||||
</span>
|
</span>
|
||||||
|
|
|
@ -500,7 +500,7 @@ function handleSelection({ evt, added, rows: selectedRows }, rows) {
|
||||||
<QCard
|
<QCard
|
||||||
bordered
|
bordered
|
||||||
flat
|
flat
|
||||||
class="row no-wrap justify-between cursor-pointer"
|
class="row no-wrap justify-between cursor-pointer q-pa-sm"
|
||||||
@click="
|
@click="
|
||||||
(_, row) => {
|
(_, row) => {
|
||||||
$props.rowClick && $props.rowClick(row);
|
$props.rowClick && $props.rowClick(row);
|
||||||
|
@ -581,7 +581,6 @@ function handleSelection({ evt, added, rows: selectedRows }, rows) {
|
||||||
<!-- Actions -->
|
<!-- Actions -->
|
||||||
<QCardSection
|
<QCardSection
|
||||||
v-if="colsMap.tableActions"
|
v-if="colsMap.tableActions"
|
||||||
class="column flex-center w-10 no-margin q-pa-xs q-gutter-y-xs"
|
|
||||||
@click="stopEventPropagation($event)"
|
@click="stopEventPropagation($event)"
|
||||||
>
|
>
|
||||||
<QBtn
|
<QBtn
|
||||||
|
@ -807,12 +806,15 @@ es:
|
||||||
|
|
||||||
.grid-two {
|
.grid-two {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(auto-fit, minmax(150px, max-content));
|
grid-template-columns: 2fr 2fr;
|
||||||
max-width: 100%;
|
.vn-label-value {
|
||||||
margin: 0 auto;
|
flex-direction: column;
|
||||||
overflow: scroll;
|
white-space: nowrap;
|
||||||
white-space: wrap;
|
.fields {
|
||||||
width: 100%;
|
display: flex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.w-80 {
|
.w-80 {
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
import { vi, describe, expect, it, beforeEach, beforeAll, 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';
|
||||||
|
|
||||||
|
describe('UserPanel', () => {
|
||||||
|
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;
|
||||||
|
});
|
||||||
|
|
||||||
|
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 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 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 update user data', async () => {
|
||||||
|
const key = 'name';
|
||||||
|
const value = 'itboss';
|
||||||
|
await vm.saveUserData(key, value);
|
||||||
|
expect(axios.post).toHaveBeenCalledWith('UserConfigs/setUserConfig', { [key]: value });
|
||||||
|
});
|
||||||
|
});
|
|
@ -53,6 +53,7 @@ const url = computed(() => {
|
||||||
:fields="['id', 'name', 'nickname', 'code']"
|
:fields="['id', 'name', 'nickname', 'code']"
|
||||||
:filter-options="['id', 'name', 'nickname', 'code']"
|
:filter-options="['id', 'name', 'nickname', 'code']"
|
||||||
sort-by="nickname ASC"
|
sort-by="nickname ASC"
|
||||||
|
data-cy="vnWorkerSelect"
|
||||||
>
|
>
|
||||||
<template #prepend v-if="$props.hasAvatar">
|
<template #prepend v-if="$props.hasAvatar">
|
||||||
<VnAvatar :worker-id="value" color="primary" v-bind="$attrs" />
|
<VnAvatar :worker-id="value" color="primary" v-bind="$attrs" />
|
||||||
|
|
|
@ -15,6 +15,10 @@ const props = defineProps({
|
||||||
type: Object,
|
type: Object,
|
||||||
default: null,
|
default: null,
|
||||||
},
|
},
|
||||||
|
userFilter: {
|
||||||
|
type: Object,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
entityId: {
|
entityId: {
|
||||||
type: [Number, String],
|
type: [Number, String],
|
||||||
default: null,
|
default: null,
|
||||||
|
@ -34,6 +38,7 @@ const isSummary = ref();
|
||||||
const arrayData = useArrayData(props.dataKey, {
|
const arrayData = useArrayData(props.dataKey, {
|
||||||
url: props.url,
|
url: props.url,
|
||||||
filter: props.filter,
|
filter: props.filter,
|
||||||
|
userFilter: props.userFilter,
|
||||||
skip: 0,
|
skip: 0,
|
||||||
oneRecord: true,
|
oneRecord: true,
|
||||||
});
|
});
|
||||||
|
|
|
@ -123,7 +123,7 @@ watch(
|
||||||
() => props.data,
|
() => props.data,
|
||||||
() => {
|
() => {
|
||||||
store.data = props.data;
|
store.data = props.data;
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
|
@ -132,12 +132,12 @@ watch(
|
||||||
if (!mounted.value) return;
|
if (!mounted.value) return;
|
||||||
emit('onChange', data);
|
emit('onChange', data);
|
||||||
},
|
},
|
||||||
{ immediate: true }
|
{ immediate: true },
|
||||||
);
|
);
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => [props.url, props.filter],
|
() => [props.url, props.filter],
|
||||||
([url, filter]) => mounted.value && fetch({ url, filter })
|
([url, filter]) => mounted.value && fetch({ url, filter }),
|
||||||
);
|
);
|
||||||
const addFilter = async (filter, params) => {
|
const addFilter = async (filter, params) => {
|
||||||
await arrayData.addFilter({ filter, params });
|
await arrayData.addFilter({ filter, params });
|
||||||
|
@ -198,7 +198,7 @@ function endPagination() {
|
||||||
async function onLoad(index, done) {
|
async function onLoad(index, done) {
|
||||||
if (!store.data || !mounted.value) return done();
|
if (!store.data || !mounted.value) return done();
|
||||||
|
|
||||||
if (store.data.length === 0 || !props.url) return done(false);
|
if (store.data.length === 0 || !arrayData.store.url) return done(false);
|
||||||
|
|
||||||
pagination.value.page = pagination.value.page + 1;
|
pagination.value.page = pagination.value.page + 1;
|
||||||
|
|
||||||
|
|
|
@ -378,7 +378,7 @@ login:
|
||||||
loginError: Invalid username or password
|
loginError: Invalid username or password
|
||||||
fieldRequired: This field is required
|
fieldRequired: This field is required
|
||||||
twoFactorRequired: Two-factor verification required
|
twoFactorRequired: Two-factor verification required
|
||||||
twoFactorRequired:
|
twoFactor:
|
||||||
validate: Validate
|
validate: Validate
|
||||||
insert: Enter the verification code
|
insert: Enter the verification code
|
||||||
explanation: >-
|
explanation: >-
|
||||||
|
@ -457,48 +457,6 @@ ticket:
|
||||||
consigneeStreet: Street
|
consigneeStreet: Street
|
||||||
create:
|
create:
|
||||||
address: Address
|
address: Address
|
||||||
invoiceOut:
|
|
||||||
card:
|
|
||||||
issued: Issued
|
|
||||||
customerCard: Customer card
|
|
||||||
ticketList: Ticket List
|
|
||||||
summary:
|
|
||||||
issued: Issued
|
|
||||||
dued: Due
|
|
||||||
booked: Booked
|
|
||||||
taxBreakdown: Tax breakdown
|
|
||||||
taxableBase: Taxable base
|
|
||||||
rate: Rate
|
|
||||||
fee: Fee
|
|
||||||
tickets: Tickets
|
|
||||||
totalWithVat: Amount
|
|
||||||
globalInvoices:
|
|
||||||
errors:
|
|
||||||
chooseValidClient: Choose a valid client
|
|
||||||
chooseValidCompany: Choose a valid company
|
|
||||||
chooseValidPrinter: Choose a valid printer
|
|
||||||
chooseValidSerialType: Choose a serial type
|
|
||||||
fillDates: Invoice date and the max date should be filled
|
|
||||||
invoiceDateLessThanMaxDate: Invoice date can not be less than max date
|
|
||||||
invoiceWithFutureDate: Exists an invoice with a future date
|
|
||||||
noTicketsToInvoice: There are not tickets to invoice
|
|
||||||
criticalInvoiceError: 'Critical invoicing error, process stopped'
|
|
||||||
invalidSerialTypeForAll: The serial type must be global when invoicing all clients
|
|
||||||
table:
|
|
||||||
addressId: Address id
|
|
||||||
streetAddress: Street
|
|
||||||
statusCard:
|
|
||||||
percentageText: '{getPercentage}% {getAddressNumber} of {getNAddresses}'
|
|
||||||
pdfsNumberText: '{nPdfs} of {totalPdfs} PDFs'
|
|
||||||
negativeBases:
|
|
||||||
clientId: Client Id
|
|
||||||
base: Base
|
|
||||||
active: Active
|
|
||||||
hasToInvoice: Has to Invoice
|
|
||||||
verifiedData: Verified Data
|
|
||||||
comercial: Comercial
|
|
||||||
errors:
|
|
||||||
downloadCsvFailed: CSV download failed
|
|
||||||
department:
|
department:
|
||||||
chat: Chat
|
chat: Chat
|
||||||
bossDepartment: Boss Department
|
bossDepartment: Boss Department
|
||||||
|
|
|
@ -199,6 +199,7 @@ const debtWarning = computed(() => {
|
||||||
query: {
|
query: {
|
||||||
createForm: JSON.stringify({
|
createForm: JSON.stringify({
|
||||||
clientFk: entity.id,
|
clientFk: entity.id,
|
||||||
|
addressId: entity.defaultAddressFk,
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
}"
|
}"
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
|
||||||
export async function getAddresses(clientId) {
|
export async function getAddresses(clientId, _filter = {}) {
|
||||||
if (!clientId) return;
|
if (!clientId) return;
|
||||||
const filter = {
|
const filter = {
|
||||||
|
..._filter,
|
||||||
fields: ['nickname', 'street', 'city', 'id'],
|
fields: ['nickname', 'street', 'city', 'id'],
|
||||||
where: { isActive: true },
|
where: { isActive: true },
|
||||||
order: 'nickname ASC',
|
order: 'nickname ASC',
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
|
||||||
export async function getClient(clientId) {
|
export async function getClient(clientId, _filter = {}) {
|
||||||
const filter = {
|
const filter = {
|
||||||
|
..._filter,
|
||||||
include: {
|
include: {
|
||||||
relation: 'defaultAddress',
|
relation: 'defaultAddress',
|
||||||
scope: {
|
scope: {
|
||||||
|
|
|
@ -134,6 +134,7 @@ function downloadCSV(rows) {
|
||||||
@click="
|
@click="
|
||||||
openReport(`Entries/${entityId}/labelSupplier`)
|
openReport(`Entries/${entityId}/labelSupplier`)
|
||||||
"
|
"
|
||||||
|
data-cy="printLabelsBtn"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template #body="props">
|
<template #body="props">
|
||||||
|
|
|
@ -177,7 +177,7 @@ const cols = computed(() => [
|
||||||
:required="true"
|
:required="true"
|
||||||
/>
|
/>
|
||||||
<VnInput
|
<VnInput
|
||||||
:label="t('invoicein.list.supplierRef')"
|
:label="t('invoiceIn.list.supplierRef')"
|
||||||
v-model="data.supplierRef"
|
v-model="data.supplierRef"
|
||||||
/>
|
/>
|
||||||
<VnSelect
|
<VnSelect
|
||||||
|
@ -190,7 +190,7 @@ const cols = computed(() => [
|
||||||
:required="true"
|
:required="true"
|
||||||
/>
|
/>
|
||||||
<VnInputDate
|
<VnInputDate
|
||||||
:label="t('invoicein.summary.issued')"
|
:label="t('invoiceIn.summary.issued')"
|
||||||
v-model="data.issued"
|
v-model="data.issued"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -125,7 +125,7 @@ onMounted(async () => {
|
||||||
inventoriedDate.value =
|
inventoriedDate.value =
|
||||||
(await axios.get('Configs/findOne')).data?.inventoried || today;
|
(await axios.get('Configs/findOne')).data?.inventoried || today;
|
||||||
|
|
||||||
if (query.warehouseFk) ref.warehouseFk = query.warehouseFk;
|
if (query.warehouseFk) ref.warehouseFk = +query.warehouseFk;
|
||||||
else if (!ref.warehouseFk && user.value) ref.warehouseFk = user.value.warehouseFk;
|
else if (!ref.warehouseFk && user.value) ref.warehouseFk = user.value.warehouseFk;
|
||||||
if (ref.date) showWhatsBeforeInventory.value = true;
|
if (ref.date) showWhatsBeforeInventory.value = true;
|
||||||
ref.itemFk = route.params.id;
|
ref.itemFk = route.params.id;
|
||||||
|
@ -143,7 +143,7 @@ onMounted(async () => {
|
||||||
const fetchItemBalances = async () => await arrayDataItemBalances.fetch({});
|
const fetchItemBalances = async () => await arrayDataItemBalances.fetch({});
|
||||||
|
|
||||||
const getBadgeAttrs = (_date) => {
|
const getBadgeAttrs = (_date) => {
|
||||||
const isSameDate = date.isSameDate(today.value, _date);
|
const isSameDate = date.isSameDate(today, _date);
|
||||||
const attrs = {
|
const attrs = {
|
||||||
'text-color': isSameDate ? 'black' : 'white',
|
'text-color': isSameDate ? 'black' : 'white',
|
||||||
color: isSameDate ? 'warning' : 'transparent',
|
color: isSameDate ? 'warning' : 'transparent',
|
||||||
|
@ -153,8 +153,6 @@ const getBadgeAttrs = (_date) => {
|
||||||
|
|
||||||
const scrollToToday = async () => {
|
const scrollToToday = async () => {
|
||||||
await nextTick();
|
await nextTick();
|
||||||
const today = Date.vnNew();
|
|
||||||
today.setHours(0, 0, 0, 0);
|
|
||||||
const todayCell = document.querySelector(`td[data-date="${today.toISOString()}"]`);
|
const todayCell = document.querySelector(`td[data-date="${today.toISOString()}"]`);
|
||||||
if (todayCell) {
|
if (todayCell) {
|
||||||
todayCell.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
todayCell.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||||
|
|
|
@ -5,6 +5,9 @@ import VnTable from 'components/VnTable/VnTable.vue';
|
||||||
import FetchData from 'components/FetchData.vue';
|
import FetchData from 'components/FetchData.vue';
|
||||||
import WorkerDescriptorProxy from '../Worker/Card/WorkerDescriptorProxy.vue';
|
import WorkerDescriptorProxy from '../Worker/Card/WorkerDescriptorProxy.vue';
|
||||||
import VnSection from 'src/components/common/VnSection.vue';
|
import VnSection from 'src/components/common/VnSection.vue';
|
||||||
|
import VnInput from 'src/components/common/VnInput.vue';
|
||||||
|
import VnSelectWorker from 'src/components/common/VnSelectWorker.vue';
|
||||||
|
import VnSelect from 'src/components/common/VnSelect.vue';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const tableRef = ref();
|
const tableRef = ref();
|
||||||
|
@ -60,20 +63,17 @@ const columns = computed(() => [
|
||||||
label: t('code'),
|
label: t('code'),
|
||||||
isTitle: true,
|
isTitle: true,
|
||||||
cardVisible: true,
|
cardVisible: true,
|
||||||
create: true,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
name: 'name',
|
name: 'name',
|
||||||
label: t('globals.name'),
|
label: t('globals.name'),
|
||||||
cardVisible: true,
|
cardVisible: true,
|
||||||
create: true,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
label: t('worker'),
|
label: t('worker'),
|
||||||
name: 'workerFk',
|
name: 'workerFk',
|
||||||
create: true,
|
|
||||||
component: 'select',
|
component: 'select',
|
||||||
attrs: {
|
attrs: {
|
||||||
url: 'Workers/search',
|
url: 'Workers/search',
|
||||||
|
@ -100,7 +100,6 @@ const columns = computed(() => [
|
||||||
align: 'left',
|
align: 'left',
|
||||||
name: 'categoryFk',
|
name: 'categoryFk',
|
||||||
label: t('ItemCategory'),
|
label: t('ItemCategory'),
|
||||||
create: true,
|
|
||||||
component: 'select',
|
component: 'select',
|
||||||
attrs: {
|
attrs: {
|
||||||
options: itemCategoriesOptions.value,
|
options: itemCategoriesOptions.value,
|
||||||
|
@ -112,7 +111,6 @@ const columns = computed(() => [
|
||||||
align: 'left',
|
align: 'left',
|
||||||
name: 'Temperature',
|
name: 'Temperature',
|
||||||
label: t('Temperature'),
|
label: t('Temperature'),
|
||||||
create: true,
|
|
||||||
component: 'select',
|
component: 'select',
|
||||||
attrs: {
|
attrs: {
|
||||||
options: temperatureOptions.value,
|
options: temperatureOptions.value,
|
||||||
|
@ -180,6 +178,29 @@ const columns = computed(() => [
|
||||||
<WorkerDescriptorProxy :id="row.workerFk" />
|
<WorkerDescriptorProxy :id="row.workerFk" />
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
|
<template #more-create-dialog="{ data }">
|
||||||
|
<VnInput v-model="data.code" :label="t('code')" data-cy="codeInput" />
|
||||||
|
<VnInput
|
||||||
|
v-model="data.name"
|
||||||
|
:label="t('globals.name')"
|
||||||
|
data-cy="nameInput"
|
||||||
|
/>
|
||||||
|
<VnSelectWorker v-model="data.workerFk" />
|
||||||
|
<VnSelect
|
||||||
|
:label="t('ItemCategory')"
|
||||||
|
v-model="data.categoryFk"
|
||||||
|
:options="itemCategoriesOptions"
|
||||||
|
hide-selected
|
||||||
|
data-cy="itemCategorySelect"
|
||||||
|
/>
|
||||||
|
<VnSelect
|
||||||
|
:label="t('Temperature')"
|
||||||
|
v-model="data.temperatureFk"
|
||||||
|
:options="temperatureOptions"
|
||||||
|
hide-selected
|
||||||
|
data-cy="temperatureSelect"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
</VnTable>
|
</VnTable>
|
||||||
</template>
|
</template>
|
||||||
</VnSection>
|
</VnSection>
|
||||||
|
|
|
@ -38,6 +38,7 @@ salesTicketsTable:
|
||||||
payMethod: Pay method
|
payMethod: Pay method
|
||||||
department: Department
|
department: Department
|
||||||
packing: ITP
|
packing: ITP
|
||||||
|
hasItemLost: Item lost
|
||||||
searchBar:
|
searchBar:
|
||||||
label: Search tickets
|
label: Search tickets
|
||||||
info: Search tickets by id or alias
|
info: Search tickets by id or alias
|
||||||
|
|
|
@ -39,6 +39,7 @@ salesTicketsTable:
|
||||||
payMethod: Método de pago
|
payMethod: Método de pago
|
||||||
department: Departamento
|
department: Departamento
|
||||||
packing: ITP
|
packing: ITP
|
||||||
|
hasItemLost: Artículo perdido
|
||||||
searchBar:
|
searchBar:
|
||||||
label: Buscar tickets
|
label: Buscar tickets
|
||||||
info: Buscar tickets por identificador o alias
|
info: Buscar tickets por identificador o alias
|
||||||
|
|
|
@ -22,7 +22,6 @@ const catalogParams = {
|
||||||
};
|
};
|
||||||
const arrayData = useArrayData(dataKey, {
|
const arrayData = useArrayData(dataKey, {
|
||||||
url: 'Orders/CatalogFilter',
|
url: 'Orders/CatalogFilter',
|
||||||
limit: 50,
|
|
||||||
userParams: catalogParams,
|
userParams: catalogParams,
|
||||||
});
|
});
|
||||||
const store = arrayData.store;
|
const store = arrayData.store;
|
||||||
|
@ -66,7 +65,7 @@ function extractValueTags(items) {
|
||||||
.filter((k) => /^value\d+$/.test(k))
|
.filter((k) => /^value\d+$/.test(k))
|
||||||
.map((v) => x[v])
|
.map((v) => x[v])
|
||||||
.filter((v) => v)
|
.filter((v) => v)
|
||||||
.sort()
|
.sort(),
|
||||||
);
|
);
|
||||||
tagValue.value = resultValueTags;
|
tagValue.value = resultValueTags;
|
||||||
}
|
}
|
||||||
|
@ -76,7 +75,7 @@ watch(
|
||||||
(val) => {
|
(val) => {
|
||||||
extractTags(val);
|
extractTags(val);
|
||||||
},
|
},
|
||||||
{ immediate: true }
|
{ immediate: true },
|
||||||
);
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -81,7 +81,7 @@ const columns = computed(() => [
|
||||||
label: t('module.created'),
|
label: t('module.created'),
|
||||||
component: 'date',
|
component: 'date',
|
||||||
cardVisible: true,
|
cardVisible: true,
|
||||||
format: (row) => toDateTimeFormat(row?.landed),
|
format: (row) => toDateTimeFormat(row?.created),
|
||||||
columnField: {
|
columnField: {
|
||||||
component: null,
|
component: null,
|
||||||
},
|
},
|
||||||
|
|
|
@ -3,14 +3,17 @@ import axios from 'axios';
|
||||||
import { getAgencies } from 'src/pages/Route/Agency/composables/getAgencies';
|
import { getAgencies } from 'src/pages/Route/Agency/composables/getAgencies';
|
||||||
|
|
||||||
vi.mock('axios');
|
vi.mock('axios');
|
||||||
|
const response = { data: [{ agencyModeFk: 'Agency1' }, { agencyModeFk: 'Agency2' }] };
|
||||||
|
axios.get.mockResolvedValue(response);
|
||||||
|
|
||||||
describe('getAgencies', () => {
|
describe('getAgencies', () => {
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
vi.clearAllMocks();
|
vi.clearAllMocks();
|
||||||
});
|
});
|
||||||
|
|
||||||
const generateParams = (formData) => ({
|
const generateParams = (formData, filter = {}) => ({
|
||||||
params: {
|
params: {
|
||||||
|
filter: JSON.stringify(filter),
|
||||||
warehouseFk: formData.warehouseId,
|
warehouseFk: formData.warehouseId,
|
||||||
addressFk: formData.addressId,
|
addressFk: formData.addressId,
|
||||||
landed: formData.landed,
|
landed: formData.landed,
|
||||||
|
@ -23,10 +26,15 @@ describe('getAgencies', () => {
|
||||||
addressId: '456',
|
addressId: '456',
|
||||||
landed: 'true',
|
landed: 'true',
|
||||||
};
|
};
|
||||||
|
const filter = {
|
||||||
|
fields: ['nickname', 'street', 'city', 'id'],
|
||||||
|
where: { isActive: true },
|
||||||
|
order: 'nickname ASC',
|
||||||
|
};
|
||||||
|
|
||||||
await getAgencies(formData);
|
await getAgencies(formData, null, filter);
|
||||||
|
|
||||||
expect(axios.get).toHaveBeenCalledWith('Agencies/getAgenciesWithWarehouse', generateParams(formData));
|
expect(axios.get).toHaveBeenCalledWith('Agencies/getAgenciesWithWarehouse', generateParams(formData, filter));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not call API when formData is missing required landed field', async () => {
|
it('should not call API when formData is missing required landed field', async () => {
|
||||||
|
@ -52,4 +60,23 @@ describe('getAgencies', () => {
|
||||||
|
|
||||||
expect(axios.get).not.toHaveBeenCalled();
|
expect(axios.get).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should return options and agency when default agency is found', async () => {
|
||||||
|
const formData = { warehouseId: '123', addressId: '456', landed: 'true' };
|
||||||
|
const client = { defaultAddress: { agencyModeFk: 'Agency1' } };
|
||||||
|
|
||||||
|
const { options, agency } = await getAgencies(formData, client);
|
||||||
|
|
||||||
|
expect(options).toEqual(response.data);
|
||||||
|
expect(agency).toEqual(response.data[0]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return options and agency when client is not provided', async () => {
|
||||||
|
const formData = { warehouseId: '123', addressId: '456', landed: 'true' };
|
||||||
|
|
||||||
|
const { options, agency } = await getAgencies(formData);
|
||||||
|
|
||||||
|
expect(options).toEqual(response.data);
|
||||||
|
expect(agency).toBeNull();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,12 +1,26 @@
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
import agency from 'src/router/modules/agency';
|
||||||
|
|
||||||
export async function getAgencies(formData) {
|
export async function getAgencies(formData, client, _filter = {}) {
|
||||||
if (!formData.warehouseId || !formData.addressId || !formData.landed) return;
|
if (!formData.warehouseId || !formData.addressId || !formData.landed) return;
|
||||||
|
|
||||||
|
const filter = {
|
||||||
|
..._filter
|
||||||
|
};
|
||||||
|
|
||||||
|
let defaultAgency = null;
|
||||||
let params = {
|
let params = {
|
||||||
|
filter: JSON.stringify(filter),
|
||||||
warehouseFk: formData.warehouseId,
|
warehouseFk: formData.warehouseId,
|
||||||
addressFk: formData.addressId,
|
addressFk: formData.addressId,
|
||||||
landed: formData.landed,
|
landed: formData.landed,
|
||||||
};
|
};
|
||||||
|
|
||||||
return await axios.get('Agencies/getAgenciesWithWarehouse', { params });
|
const { data } = await axios.get('Agencies/getAgenciesWithWarehouse', { params });
|
||||||
|
|
||||||
|
if(data && client) {
|
||||||
|
defaultAgency = data.find((agency) => agency.agencyModeFk === client.defaultAddress.agencyModeFk );
|
||||||
|
};
|
||||||
|
|
||||||
|
return {options: data, agency: defaultAgency}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,9 @@ import VnLv from 'src/components/ui/VnLv.vue';
|
||||||
import VnUserLink from 'src/components/ui/VnUserLink.vue';
|
import VnUserLink from 'src/components/ui/VnUserLink.vue';
|
||||||
import { toDateTimeFormat } from 'src/filters/date';
|
import { toDateTimeFormat } from 'src/filters/date';
|
||||||
import filter from './TicketFilter.js';
|
import filter from './TicketFilter.js';
|
||||||
|
import FetchData from 'src/components/FetchData.vue';
|
||||||
|
import TicketProblems from 'src/components/TicketProblems.vue';
|
||||||
|
|
||||||
const $props = defineProps({
|
const $props = defineProps({
|
||||||
id: {
|
id: {
|
||||||
type: Number,
|
type: Number,
|
||||||
|
@ -27,6 +30,7 @@ const { t } = useI18n();
|
||||||
const entityId = computed(() => {
|
const entityId = computed(() => {
|
||||||
return $props.id || route.params.id;
|
return $props.id || route.params.id;
|
||||||
});
|
});
|
||||||
|
const problems = ref({});
|
||||||
|
|
||||||
function ticketFilter(ticket) {
|
function ticketFilter(ticket) {
|
||||||
return JSON.stringify({ clientFk: ticket.clientFk });
|
return JSON.stringify({ clientFk: ticket.clientFk });
|
||||||
|
@ -34,6 +38,11 @@ function ticketFilter(ticket) {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
<FetchData
|
||||||
|
:url="`Tickets/${entityId}/getTicketProblems`"
|
||||||
|
auto-load
|
||||||
|
@on-fetch="(data) => ([problems] = data)"
|
||||||
|
/>
|
||||||
<CardDescriptor
|
<CardDescriptor
|
||||||
module="Ticket"
|
module="Ticket"
|
||||||
:url="`Tickets/${entityId}`"
|
:url="`Tickets/${entityId}`"
|
||||||
|
@ -85,48 +94,9 @@ function ticketFilter(ticket) {
|
||||||
<VnLv :label="t('globals.warehouse')" :value="entity.warehouse?.name" />
|
<VnLv :label="t('globals.warehouse')" :value="entity.warehouse?.name" />
|
||||||
<VnLv :label="t('globals.alias')" :value="entity.nickname" />
|
<VnLv :label="t('globals.alias')" :value="entity.nickname" />
|
||||||
</template>
|
</template>
|
||||||
<template #icons="{ entity }">
|
<template #icons>
|
||||||
<QCardActions class="q-gutter-x-md">
|
<QCardActions class="q-gutter-x-xs">
|
||||||
<QIcon
|
<TicketProblems :row="problems" />
|
||||||
v-if="entity.client?.isActive == false"
|
|
||||||
name="vn:disabled"
|
|
||||||
size="xs"
|
|
||||||
color="primary"
|
|
||||||
>
|
|
||||||
<QTooltip>{{ t('Client inactive') }}</QTooltip>
|
|
||||||
</QIcon>
|
|
||||||
<QIcon
|
|
||||||
v-if="entity.client?.isFreezed == true"
|
|
||||||
name="vn:frozen"
|
|
||||||
size="xs"
|
|
||||||
color="primary"
|
|
||||||
>
|
|
||||||
<QTooltip>{{ t('Client Frozen') }}</QTooltip>
|
|
||||||
</QIcon>
|
|
||||||
<QIcon
|
|
||||||
v-if="entity?.problem?.includes('hasRisk')"
|
|
||||||
name="vn:risk"
|
|
||||||
size="xs"
|
|
||||||
color="primary"
|
|
||||||
>
|
|
||||||
<QTooltip>{{ t('Client has debt') }}</QTooltip>
|
|
||||||
</QIcon>
|
|
||||||
<QIcon
|
|
||||||
v-if="entity.client?.isTaxDataChecked == false"
|
|
||||||
name="vn:no036"
|
|
||||||
size="xs"
|
|
||||||
color="primary"
|
|
||||||
>
|
|
||||||
<QTooltip>{{ t('Client not checked') }}</QTooltip>
|
|
||||||
</QIcon>
|
|
||||||
<QIcon
|
|
||||||
v-if="entity.isDeleted == true"
|
|
||||||
name="vn:deletedTicket"
|
|
||||||
size="xs"
|
|
||||||
color="primary"
|
|
||||||
>
|
|
||||||
<QTooltip>{{ t('This ticket is deleted') }}</QTooltip>
|
|
||||||
</QIcon>
|
|
||||||
</QCardActions>
|
</QCardActions>
|
||||||
</template>
|
</template>
|
||||||
<template #actions="{ entity }">
|
<template #actions="{ entity }">
|
||||||
|
|
|
@ -69,14 +69,16 @@ const onAddressSelected = (addressId) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const fetchClient = async () => {
|
const fetchClient = async () => {
|
||||||
const { data } = await getClient(client.value)
|
const response = await getClient(client.value)
|
||||||
const [retrievedClient] = data;
|
if (!response) return;
|
||||||
|
const [retrievedClient] = response.data;
|
||||||
selectedClient.value = retrievedClient;
|
selectedClient.value = retrievedClient;
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchAddresses = async () => {
|
const fetchAddresses = async () => {
|
||||||
const { data } = await getAddresses(client.value);
|
const response = await getAddresses(client.value);
|
||||||
addressesOptions.value = data;
|
if (!response) return;
|
||||||
|
addressesOptions.value = response.data;
|
||||||
|
|
||||||
const { defaultAddress } = selectedClient.value;
|
const { defaultAddress } = selectedClient.value;
|
||||||
address.value = defaultAddress.id;
|
address.value = defaultAddress.id;
|
||||||
|
|
|
@ -24,6 +24,7 @@ import axios from 'axios';
|
||||||
import VnTable from 'src/components/VnTable/VnTable.vue';
|
import VnTable from 'src/components/VnTable/VnTable.vue';
|
||||||
import VnUsesMana from 'src/components/ui/VnUsesMana.vue';
|
import VnUsesMana from 'src/components/ui/VnUsesMana.vue';
|
||||||
import VnConfirm from 'src/components/ui/VnConfirm.vue';
|
import VnConfirm from 'src/components/ui/VnConfirm.vue';
|
||||||
|
import TicketProblems from 'src/components/TicketProblems.vue';
|
||||||
import RightMenu from 'src/components/common/RightMenu.vue';
|
import RightMenu from 'src/components/common/RightMenu.vue';
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
@ -56,7 +57,7 @@ const canProceed = ref();
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => route.params.id,
|
() => route.params.id,
|
||||||
() => tableRef.value.reload()
|
() => tableRef.value.reload(),
|
||||||
);
|
);
|
||||||
|
|
||||||
const columns = computed(() => [
|
const columns = computed(() => [
|
||||||
|
@ -199,7 +200,7 @@ const changeQuantity = async (sale) => {
|
||||||
await updateQuantity(sale);
|
await updateQuantity(sale);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const { quantity } = tableRef.value.CrudModelRef.originalData.find(
|
const { quantity } = tableRef.value.CrudModelRef.originalData.find(
|
||||||
(s) => s.id === sale.id
|
(s) => s.id === sale.id,
|
||||||
);
|
);
|
||||||
sale.quantity = quantity;
|
sale.quantity = quantity;
|
||||||
throw e;
|
throw e;
|
||||||
|
@ -503,7 +504,7 @@ async function isSalePrepared(item) {
|
||||||
componentProps: {
|
componentProps: {
|
||||||
title: t('Item prepared'),
|
title: t('Item prepared'),
|
||||||
message: t(
|
message: t(
|
||||||
'This item is already prepared. Do you want to continue?'
|
'This item is already prepared. Do you want to continue?',
|
||||||
),
|
),
|
||||||
data: item,
|
data: item,
|
||||||
},
|
},
|
||||||
|
@ -525,7 +526,7 @@ watch(
|
||||||
if (newItemFk) {
|
if (newItemFk) {
|
||||||
updateItem(newRow.value);
|
updateItem(newRow.value);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -595,7 +596,7 @@ watch(
|
||||||
openConfirmationModal(
|
openConfirmationModal(
|
||||||
t('Continue anyway?'),
|
t('Continue anyway?'),
|
||||||
t('You are going to delete lines of the ticket'),
|
t('You are going to delete lines of the ticket'),
|
||||||
removeSales
|
removeSales,
|
||||||
)
|
)
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
|
@ -679,53 +680,7 @@ watch(
|
||||||
:disabled-attr="isTicketEditable"
|
:disabled-attr="isTicketEditable"
|
||||||
>
|
>
|
||||||
<template #column-statusIcons="{ row }">
|
<template #column-statusIcons="{ row }">
|
||||||
<router-link
|
<TicketProblems :row="row" />
|
||||||
v-if="row.claim?.claimFk"
|
|
||||||
:to="{ name: 'ClaimBasicData', params: { id: row.claim?.claimFk } }"
|
|
||||||
>
|
|
||||||
<QIcon color="primary" name="vn:claims" size="xs">
|
|
||||||
<QTooltip>
|
|
||||||
{{ t('ticketSale.claim') }}:
|
|
||||||
{{ row.claim?.claimFk }}
|
|
||||||
</QTooltip>
|
|
||||||
</QIcon>
|
|
||||||
</router-link>
|
|
||||||
<QIcon v-if="row.visible < 0" color="primary" name="warning" size="xs">
|
|
||||||
<QTooltip>
|
|
||||||
{{ t('ticketSale.visible') }}: {{ row.visible || 0 }}
|
|
||||||
</QTooltip>
|
|
||||||
</QIcon>
|
|
||||||
<QIcon
|
|
||||||
v-if="row.reserved"
|
|
||||||
color="primary"
|
|
||||||
name="vn:reserva"
|
|
||||||
size="xs"
|
|
||||||
data-cy="ticketSaleReservedIcon"
|
|
||||||
>
|
|
||||||
<QTooltip>
|
|
||||||
{{ t('ticketSale.reserved') }}
|
|
||||||
</QTooltip>
|
|
||||||
</QIcon>
|
|
||||||
<QIcon
|
|
||||||
v-if="row.itemShortage"
|
|
||||||
color="primary"
|
|
||||||
name="vn:unavailable"
|
|
||||||
size="xs"
|
|
||||||
>
|
|
||||||
<QTooltip>
|
|
||||||
{{ t('ticketSale.noVisible') }}
|
|
||||||
</QTooltip>
|
|
||||||
</QIcon>
|
|
||||||
<QIcon
|
|
||||||
v-if="row.hasComponentLack"
|
|
||||||
color="primary"
|
|
||||||
name="vn:components"
|
|
||||||
size="xs"
|
|
||||||
>
|
|
||||||
<QTooltip>
|
|
||||||
{{ t('ticketSale.hasComponentLack') }}
|
|
||||||
</QTooltip>
|
|
||||||
</QIcon>
|
|
||||||
</template>
|
</template>
|
||||||
<template #body-cell-picture="{ row }">
|
<template #body-cell-picture="{ row }">
|
||||||
<QTd>
|
<QTd>
|
||||||
|
|
|
@ -20,6 +20,7 @@ import ZoneDescriptorProxy from 'src/pages/Zone/Card/ZoneDescriptorProxy.vue';
|
||||||
import VnSelect from 'src/components/common/VnSelect.vue';
|
import VnSelect from 'src/components/common/VnSelect.vue';
|
||||||
import VnToSummary from 'src/components/ui/VnToSummary.vue';
|
import VnToSummary from 'src/components/ui/VnToSummary.vue';
|
||||||
import TicketDescriptorMenu from './TicketDescriptorMenu.vue';
|
import TicketDescriptorMenu from './TicketDescriptorMenu.vue';
|
||||||
|
import TicketProblems from 'src/components/TicketProblems.vue';
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const { notify } = useNotify();
|
const { notify } = useNotify();
|
||||||
|
@ -311,83 +312,7 @@ onMounted(async () => {
|
||||||
<template #body="props">
|
<template #body="props">
|
||||||
<QTr :props="props">
|
<QTr :props="props">
|
||||||
<QTd class="q-gutter-x-xs">
|
<QTd class="q-gutter-x-xs">
|
||||||
<QBtn
|
<TicketProblems :row="props.row" />
|
||||||
flat
|
|
||||||
round
|
|
||||||
icon="vn:claims"
|
|
||||||
v-if="props.row.claim"
|
|
||||||
color="primary"
|
|
||||||
:to="{
|
|
||||||
name: 'ClaimCard',
|
|
||||||
params: {
|
|
||||||
id: props.row.claim.claimFk,
|
|
||||||
},
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
<QTooltip>
|
|
||||||
{{ t('ticket.summary.claim') }}:
|
|
||||||
{{ props.row.claim.claimFk }}
|
|
||||||
</QTooltip>
|
|
||||||
</QBtn>
|
|
||||||
<QBtn
|
|
||||||
flat
|
|
||||||
round
|
|
||||||
icon="vn:claims"
|
|
||||||
v-if="props.row.claimBeginning"
|
|
||||||
color="primary"
|
|
||||||
:to="{
|
|
||||||
name: 'ClaimCard',
|
|
||||||
params: {
|
|
||||||
id: props.row.claimBeginning.claimFk,
|
|
||||||
},
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
<QTooltip>
|
|
||||||
{{ t('ticket.summary.claim') }}:
|
|
||||||
{{ props.row.claimBeginning.claimFk }}
|
|
||||||
</QTooltip>
|
|
||||||
</QBtn>
|
|
||||||
<QIcon
|
|
||||||
name="warning"
|
|
||||||
v-show="props.row.visible < 0"
|
|
||||||
color="primary"
|
|
||||||
size="xs"
|
|
||||||
>
|
|
||||||
<QTooltip>
|
|
||||||
{{ t('globals.visible') }}:
|
|
||||||
{{ props.row.visible }}
|
|
||||||
</QTooltip>
|
|
||||||
</QIcon>
|
|
||||||
<QIcon
|
|
||||||
name="vn:reserved"
|
|
||||||
v-show="props.row.reserved"
|
|
||||||
color="primary"
|
|
||||||
size="xs"
|
|
||||||
>
|
|
||||||
<QTooltip>
|
|
||||||
{{ t('ticket.summary.reserved') }}
|
|
||||||
</QTooltip>
|
|
||||||
</QIcon>
|
|
||||||
<QIcon
|
|
||||||
name="vn:unavailable"
|
|
||||||
v-show="props.row.itemShortage"
|
|
||||||
color="primary"
|
|
||||||
size="xs"
|
|
||||||
>
|
|
||||||
<QTooltip>
|
|
||||||
{{ t('ticket.summary.itemShortage') }}
|
|
||||||
</QTooltip>
|
|
||||||
</QIcon>
|
|
||||||
<QIcon
|
|
||||||
name="vn:components"
|
|
||||||
v-show="props.row.hasComponentLack"
|
|
||||||
color="primary"
|
|
||||||
size="xs"
|
|
||||||
>
|
|
||||||
<QTooltip>
|
|
||||||
{{ t('ticket.summary.hasComponentLack') }}
|
|
||||||
</QTooltip>
|
|
||||||
</QIcon>
|
|
||||||
</QTd>
|
</QTd>
|
||||||
<QTd>
|
<QTd>
|
||||||
<QBtn class="link" flat>
|
<QBtn class="link" flat>
|
||||||
|
|
|
@ -38,35 +38,43 @@ onBeforeMount(async () => {
|
||||||
await onClientSelected(initialFormState);
|
await onClientSelected(initialFormState);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function resetAgenciesSelector(formData) {
|
||||||
|
agenciesOptions.value = [];
|
||||||
|
formData.agencyModeId = null;
|
||||||
|
}
|
||||||
|
|
||||||
const fetchClient = async (formData) => {
|
const fetchClient = async (formData) => {
|
||||||
const { data } = await getClient(formData.clientId);
|
const response = await getClient(formData.clientId);
|
||||||
const [client] = data;
|
if (!response) return;
|
||||||
|
const [client] = response.data;
|
||||||
selectedClient.value = client;
|
selectedClient.value = client;
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchAddresses = async (formData) => {
|
const fetchAddresses = async (formData) => {
|
||||||
const { data } = await getAddresses(formData.clientId);
|
const response = await getAddresses(formData.clientId);
|
||||||
addressesOptions.value = data;
|
if (!response) return;
|
||||||
|
addressesOptions.value = response.data;
|
||||||
|
|
||||||
const { defaultAddress } = selectedClient.value;
|
const { defaultAddress } = selectedClient.value;
|
||||||
formData.addressId = defaultAddress.id;
|
formData.addressId = defaultAddress.id;
|
||||||
};
|
};
|
||||||
|
|
||||||
const onClientSelected = async (formData) => {
|
const onClientSelected = async (formData) => {
|
||||||
|
resetAgenciesSelector(formData);
|
||||||
await fetchClient(formData);
|
await fetchClient(formData);
|
||||||
await fetchAddresses(formData);
|
await fetchAddresses(formData);
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchAvailableAgencies = async (formData) => {
|
const fetchAvailableAgencies = async (formData) => {
|
||||||
const { data } = await getAgencies(formData);
|
resetAgenciesSelector(formData);
|
||||||
agenciesOptions.value = data;
|
const response= await getAgencies(formData, selectedClient.value);
|
||||||
|
if (!response) return;
|
||||||
const defaultAgency = agenciesOptions.value.find(
|
|
||||||
(agency) =>
|
const { options, agency } = response
|
||||||
agency.agencyModeFk === selectedClient.value.defaultAddress.agencyModeFk
|
if(options)
|
||||||
);
|
agenciesOptions.value = options;
|
||||||
|
if(agency)
|
||||||
if (defaultAgency) formData.agencyModeId = defaultAgency.agencyModeFk;
|
formData.agencyModeId = agency;
|
||||||
};
|
};
|
||||||
|
|
||||||
const redirectToTicketList = (_, { id }) => {
|
const redirectToTicketList = (_, { id }) => {
|
||||||
|
|
|
@ -38,35 +38,43 @@ onBeforeMount(async () => {
|
||||||
await onClientSelected(initialFormState);
|
await onClientSelected(initialFormState);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function resetAgenciesSelector(formData) {
|
||||||
|
agenciesOptions.value = [];
|
||||||
|
if(formData) formData.agencyModeId = null;
|
||||||
|
}
|
||||||
|
|
||||||
const fetchClient = async (formData) => {
|
const fetchClient = async (formData) => {
|
||||||
const { data } = await getClient(formData.clientId);
|
const response = await getClient(formData.clientId);
|
||||||
const [client] = data;
|
if (!response) return;
|
||||||
|
const [client] = response.data;
|
||||||
selectedClient.value = client;
|
selectedClient.value = client;
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchAddresses = async (formData) => {
|
const fetchAddresses = async (formData) => {
|
||||||
const { data } = await getAddresses(formData.clientId);
|
const response = await getAddresses(formData.clientId);
|
||||||
addressesOptions.value = data;
|
if (!response) return;
|
||||||
|
addressesOptions.value = response.data;
|
||||||
|
|
||||||
const { defaultAddress } = selectedClient.value;
|
const { defaultAddress } = selectedClient.value;
|
||||||
formData.addressId = defaultAddress.id;
|
formData.addressId = defaultAddress.id;
|
||||||
};
|
};
|
||||||
|
|
||||||
const onClientSelected = async (formData) => {
|
const onClientSelected = async (formData) => {
|
||||||
|
resetAgenciesSelector(formData);
|
||||||
await fetchClient(formData);
|
await fetchClient(formData);
|
||||||
await fetchAddresses(formData);
|
await fetchAddresses(formData);
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchAvailableAgencies = async (formData) => {
|
const fetchAvailableAgencies = async (formData) => {
|
||||||
const { data } = await getAgencies(formData);
|
resetAgenciesSelector(formData);
|
||||||
agenciesOptions.value = data;
|
const response= await getAgencies(formData, selectedClient.value);
|
||||||
|
if (!response) return;
|
||||||
const defaultAgency = agenciesOptions.value.find(
|
|
||||||
(agency) =>
|
const { options, agency } = response
|
||||||
agency.agencyModeFk === selectedClient.value.defaultAddress.agencyModeFk
|
if(options)
|
||||||
);
|
agenciesOptions.value = options;
|
||||||
|
if(agency)
|
||||||
if (defaultAgency) formData.agencyModeId = defaultAgency.agencyModeFk;
|
formData.agencyModeId = agency;
|
||||||
};
|
};
|
||||||
|
|
||||||
const redirectToTicketList = (_, { id }) => {
|
const redirectToTicketList = (_, { id }) => {
|
||||||
|
|
|
@ -229,37 +229,46 @@ const columns = computed(() => [
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
function resetAgenciesSelector(formData) {
|
||||||
|
agenciesOptions.value = [];
|
||||||
|
if(formData) formData.agencyModeId = null;
|
||||||
|
}
|
||||||
|
|
||||||
function redirectToLines(id) {
|
function redirectToLines(id) {
|
||||||
const url = `#/ticket/${id}/sale`;
|
const url = `#/ticket/${id}/sale`;
|
||||||
window.open(url, '_blank');
|
window.open(url, '_blank');
|
||||||
}
|
}
|
||||||
|
|
||||||
const onClientSelected = async (formData) => {
|
const onClientSelected = async (formData) => {
|
||||||
|
resetAgenciesSelector(formData);
|
||||||
await fetchClient(formData);
|
await fetchClient(formData);
|
||||||
await fetchAddresses(formData);
|
await fetchAddresses(formData);
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchAvailableAgencies = async (formData) => {
|
const fetchAvailableAgencies = async (formData) => {
|
||||||
const { data } = await getAgencies(formData);
|
resetAgenciesSelector(formData);
|
||||||
agenciesOptions.value = data;
|
const response= await getAgencies(formData, selectedClient.value);
|
||||||
|
if (!response) return;
|
||||||
const defaultAgency = agenciesOptions.value.find(
|
|
||||||
(agency) =>
|
const { options, agency } = response
|
||||||
agency.agencyModeFk === selectedClient.value.defaultAddress.agencyModeFk
|
if(options)
|
||||||
);
|
agenciesOptions.value = options;
|
||||||
|
if(agency)
|
||||||
if (defaultAgency) formData.agencyModeId = defaultAgency.agencyModeFk;
|
formData.agencyModeId = agency;
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchClient = async (formData) => {
|
const fetchClient = async (formData) => {
|
||||||
const { data } = await getClient(formData.clientId);
|
const response = await getClient(formData.clientId);
|
||||||
const [client] = data;
|
if (!response) return;
|
||||||
|
const [client] = response.data;
|
||||||
selectedClient.value = client;
|
selectedClient.value = client;
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchAddresses = async (formData) => {
|
const fetchAddresses = async (formData) => {
|
||||||
const { data } = await getAddresses(formData.clientId);
|
const response = await getAddresses(formData.clientId);
|
||||||
addressesOptions.value = data;
|
if (!response) return;
|
||||||
|
addressesOptions.value = response.data;
|
||||||
|
|
||||||
const { defaultAddress } = selectedClient.value;
|
const { defaultAddress } = selectedClient.value;
|
||||||
formData.addressId = defaultAddress.id;
|
formData.addressId = defaultAddress.id;
|
||||||
|
|
|
@ -208,3 +208,9 @@ ticketList:
|
||||||
toLines: Go to lines
|
toLines: Go to lines
|
||||||
addressNickname: Address nickname
|
addressNickname: Address nickname
|
||||||
ref: Reference
|
ref: Reference
|
||||||
|
rounding: Rounding
|
||||||
|
noVerifiedData: No verified data
|
||||||
|
purchaseRequest: Purchase request
|
||||||
|
notVisible: Not visible
|
||||||
|
clientFrozen: Client frozen
|
||||||
|
componentLack: Component lack
|
||||||
|
|
|
@ -213,3 +213,9 @@ ticketList:
|
||||||
toLines: Ir a lineas
|
toLines: Ir a lineas
|
||||||
addressNickname: Alias consignatario
|
addressNickname: Alias consignatario
|
||||||
ref: Referencia
|
ref: Referencia
|
||||||
|
rounding: Redondeo
|
||||||
|
noVerifiedData: Sin datos comprobados
|
||||||
|
purchaseRequest: Petición de compra
|
||||||
|
notVisible: No visible
|
||||||
|
clientFrozen: Cliente congelado
|
||||||
|
componentLack: Faltan componentes
|
||||||
|
|
|
@ -12,7 +12,6 @@ import RoleDescriptorProxy from 'src/pages/Account/Role/Card/RoleDescriptorProxy
|
||||||
import DepartmentDescriptorProxy from 'src/pages/Department/Card/DepartmentDescriptorProxy.vue';
|
import DepartmentDescriptorProxy from 'src/pages/Department/Card/DepartmentDescriptorProxy.vue';
|
||||||
import { useAdvancedSummary } from 'src/composables/useAdvancedSummary';
|
import { useAdvancedSummary } from 'src/composables/useAdvancedSummary';
|
||||||
import WorkerDescriptorMenu from './WorkerDescriptorMenu.vue';
|
import WorkerDescriptorMenu from './WorkerDescriptorMenu.vue';
|
||||||
import axios from 'axios';
|
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
@ -28,76 +27,6 @@ const entityId = computed(() => $props.id || route.params.id);
|
||||||
const basicDataUrl = ref(null);
|
const basicDataUrl = ref(null);
|
||||||
const advancedSummary = ref();
|
const advancedSummary = ref();
|
||||||
|
|
||||||
const filter = {
|
|
||||||
include: [
|
|
||||||
{
|
|
||||||
relation: 'user',
|
|
||||||
scope: {
|
|
||||||
fields: ['name', 'nickname', 'roleFk'],
|
|
||||||
|
|
||||||
include: [
|
|
||||||
{
|
|
||||||
relation: 'role',
|
|
||||||
scope: {
|
|
||||||
fields: ['name'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
relation: 'emailUser',
|
|
||||||
scope: {
|
|
||||||
fields: ['email'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
relation: 'department',
|
|
||||||
scope: {
|
|
||||||
include: {
|
|
||||||
relation: 'department',
|
|
||||||
scope: {
|
|
||||||
fields: ['name'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
relation: 'boss',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
relation: 'client',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
relation: 'sip',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
relation: 'business',
|
|
||||||
scope: {
|
|
||||||
include: [
|
|
||||||
{
|
|
||||||
relation: 'department',
|
|
||||||
scope: {
|
|
||||||
fields: ['id', 'name'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
relation: 'reasonEnd',
|
|
||||||
scope: {
|
|
||||||
fields: ['id', 'reason'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
relation: 'workerBusinessProfessionalCategory',
|
|
||||||
scope: {
|
|
||||||
fields: ['id', 'description'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
onBeforeMount(async () => {
|
onBeforeMount(async () => {
|
||||||
advancedSummary.value = await useAdvancedSummary('Workers', entityId.value);
|
advancedSummary.value = await useAdvancedSummary('Workers', entityId.value);
|
||||||
basicDataUrl.value = `#/worker/${entityId.value}/basic-data`;
|
basicDataUrl.value = `#/worker/${entityId.value}/basic-data`;
|
||||||
|
@ -107,8 +36,8 @@ onBeforeMount(async () => {
|
||||||
<template>
|
<template>
|
||||||
<CardSummary
|
<CardSummary
|
||||||
ref="summary"
|
ref="summary"
|
||||||
:url="`Workers/summary`"
|
url="Workers/summary"
|
||||||
:user-filter="{ where: { id: entityId }, filter }"
|
:user-filter="{ where: { id: entityId } }"
|
||||||
data-key="Worker"
|
data-key="Worker"
|
||||||
>
|
>
|
||||||
<template #header="{ entity }">
|
<template #header="{ entity }">
|
||||||
|
|
|
@ -44,6 +44,7 @@ const shelvingCard = {
|
||||||
path: ':id',
|
path: ':id',
|
||||||
component: () => import('pages/Shelving/Card/ShelvingCard.vue'),
|
component: () => import('pages/Shelving/Card/ShelvingCard.vue'),
|
||||||
redirect: { name: 'ShelvingSummary' },
|
redirect: { name: 'ShelvingSummary' },
|
||||||
|
meta: { menu: ['ShelvingBasicData', 'ShelvingLog'] },
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
name: 'ShelvingSummary',
|
name: 'ShelvingSummary',
|
||||||
|
@ -81,13 +82,10 @@ export default {
|
||||||
title: 'shelving',
|
title: 'shelving',
|
||||||
icon: 'vn:inventory',
|
icon: 'vn:inventory',
|
||||||
moduleName: 'Shelving',
|
moduleName: 'Shelving',
|
||||||
|
menu: ['ShelvingList', 'ParkingMain'],
|
||||||
},
|
},
|
||||||
component: RouterView,
|
component: RouterView,
|
||||||
redirect: { name: 'ShelvingMain' },
|
redirect: { name: 'ShelvingMain' },
|
||||||
menus: {
|
|
||||||
main: ['ShelvingList', 'ParkingMain'],
|
|
||||||
card: ['ShelvingBasicData', 'ShelvingLog'],
|
|
||||||
},
|
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: '',
|
path: '',
|
||||||
|
|
|
@ -62,10 +62,9 @@ describe('Client list', () => {
|
||||||
it('Client founded create order', () => {
|
it('Client founded create order', () => {
|
||||||
const search = 'Jessica Jones';
|
const search = 'Jessica Jones';
|
||||||
cy.searchByLabel('Name', search);
|
cy.searchByLabel('Name', search);
|
||||||
cy.openActionDescriptor('New order');
|
cy.clickButtonWith('icon', 'icon-basketadd');
|
||||||
cy.waitForElement('#formModel');
|
cy.waitForElement('#formModel');
|
||||||
cy.waitForElement('.q-form');
|
cy.waitForElement('.q-form');
|
||||||
cy.checkValueForm(1, search);
|
cy.checkValueForm(1, search);
|
||||||
cy.checkValueForm(2, search);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -7,6 +7,5 @@ describe('Client notes', () => {
|
||||||
});
|
});
|
||||||
it('Should load layout', () => {
|
it('Should load layout', () => {
|
||||||
cy.get('.q-page').should('be.visible');
|
cy.get('.q-page').should('be.visible');
|
||||||
cy.get('.q-page > :nth-child(2) > :nth-child(1)').should('be.visible');
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -8,12 +8,12 @@ describe('EntryMy when is supplier', () => {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
// https://redmine.verdnatura.es/issues/8418
|
|
||||||
it.skip('should open buyLabel when is supplier', () => {
|
it('should open buyLabel when is supplier', () => {
|
||||||
cy.get(
|
cy.get(
|
||||||
'[to="/null/3"] > .q-card > .column > .q-btn > .q-btn__content > .q-icon'
|
'[to="/null/3"] > .q-card > :nth-child(2) > .q-btn > .q-btn__content > .q-icon'
|
||||||
).click();
|
).click();
|
||||||
cy.get('.q-card__actions > .q-btn').click();
|
cy.dataCy('printLabelsBtn').click();
|
||||||
cy.window().its('open').should('be.called');
|
cy.window().its('open').should('be.called');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/// <reference types="cypress" />
|
/// <reference types="cypress" />
|
||||||
describe('Item shelving', () => {
|
describe('ItemBarcodes', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.viewport(1920, 1080);
|
cy.viewport(1920, 1080);
|
||||||
cy.login('developer');
|
cy.login('developer');
|
||||||
|
|
|
@ -12,28 +12,22 @@ describe('Item tag', () => {
|
||||||
cy.get('.q-page-sticky > div').click();
|
cy.get('.q-page-sticky > div').click();
|
||||||
cy.dataCy('Tag_select').eq(7).type('Tallos');
|
cy.dataCy('Tag_select').eq(7).type('Tallos');
|
||||||
cy.get('.q-menu .q-item').contains('Tallos').click();
|
cy.get('.q-menu .q-item').contains('Tallos').click();
|
||||||
cy.get(
|
cy.get(':nth-child(8) > [label="Value"]').type('1');
|
||||||
':nth-child(8) > [label="Value"] > .q-field > .q-field__inner > .q-field__control > .q-field__control-container > [data-cy="Value_input"]'
|
|
||||||
).type('1');
|
|
||||||
+cy.dataCy('crudModelDefaultSaveBtn').click();
|
+cy.dataCy('crudModelDefaultSaveBtn').click();
|
||||||
cy.checkNotification("The tag or priority can't be repeated for an item");
|
cy.checkNotification("The tag or priority can't be repeated for an item");
|
||||||
});
|
});
|
||||||
// https://redmine.verdnatura.es/issues/8422
|
|
||||||
it.skip('should add a new tag', () => {
|
it('should add a new tag', () => {
|
||||||
cy.get('.q-page').should('be.visible');
|
cy.get('.q-page').should('be.visible');
|
||||||
cy.get('.q-page-sticky > div').click();
|
cy.get('.q-page-sticky > div').click();
|
||||||
cy.get('.q-page-sticky > div').click();
|
cy.get('.q-page-sticky > div').click();
|
||||||
cy.dataCy('Tag_select').eq(7).click();
|
cy.dataCy('Tag_select').eq(7).click();
|
||||||
cy.get('.q-menu .q-item').contains('Ancho de la base').click();
|
cy.get('.q-menu .q-item').contains('Ancho de la base').type('{enter}');
|
||||||
cy.get(
|
cy.get(':nth-child(8) > [label="Value"]').type('50');
|
||||||
':nth-child(8) > [label="Value"] > .q-field > .q-field__inner > .q-field__control > .q-field__control-container > [data-cy="Value_input"]'
|
|
||||||
).type('50');
|
|
||||||
cy.dataCy('crudModelDefaultSaveBtn').click();
|
cy.dataCy('crudModelDefaultSaveBtn').click();
|
||||||
cy.checkNotification('Data saved');
|
cy.checkNotification('Data saved');
|
||||||
cy.get(
|
cy.dataCy('itemTags').children(':nth-child(8)').find('.justify-center > .q-icon').click();
|
||||||
'[data-cy="itemTags"] > :nth-child(7) > .justify-center > .q-icon'
|
|
||||||
).click();
|
|
||||||
cy.dataCy('VnConfirm_confirm').click();
|
cy.dataCy('VnConfirm_confirm').click();
|
||||||
cy.checkNotification('Data saved');
|
cy.checkNotification('Data saved');
|
||||||
});
|
});
|
||||||
});
|
});
|
|
@ -1,5 +1,10 @@
|
||||||
/// <reference types="cypress" />
|
/// <reference types="cypress" />
|
||||||
describe('Item type', () => {
|
describe('Item type', () => {
|
||||||
|
const workerError = 'employeeNick';
|
||||||
|
const worker = 'buyerNick';
|
||||||
|
const category = 'Artificial';
|
||||||
|
const type = 'Flower';
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.viewport(1920, 1080);
|
cy.viewport(1920, 1080);
|
||||||
cy.login('developer');
|
cy.login('developer');
|
||||||
|
@ -8,32 +13,24 @@ describe('Item type', () => {
|
||||||
|
|
||||||
it('should throw an error if the code already exists', () => {
|
it('should throw an error if the code already exists', () => {
|
||||||
cy.dataCy('vnTableCreateBtn').click();
|
cy.dataCy('vnTableCreateBtn').click();
|
||||||
cy.get(
|
cy.dataCy('codeInput').type('ALS');
|
||||||
'div.fit > .q-field > .q-field__inner > .q-field__control > .q-field__control-container > [data-cy="Code_input"]'
|
cy.dataCy('nameInput').type('Alstroemeria');
|
||||||
).type('ALS');
|
cy.dataCy('vnWorkerSelect').type(workerError);
|
||||||
cy.get(
|
cy.get('.q-menu .q-item').contains(workerError).click();
|
||||||
'div.fit > .q-field > .q-field__inner > .q-field__control > .q-field__control-container > [data-cy="Name_input"]'
|
cy.dataCy('itemCategorySelect').type(category);
|
||||||
).type('Alstroemeria');
|
cy.get('.q-menu .q-item').contains(category).click();
|
||||||
cy.dataCy('Worker_select').type('employeeNick');
|
|
||||||
cy.get('.q-menu .q-item').contains('employeeNick').click();
|
|
||||||
cy.dataCy('ItemCategory_select').type('Artificial');
|
|
||||||
cy.get('.q-menu .q-item').contains('Artificial').click();
|
|
||||||
cy.dataCy('FormModelPopup_save').click();
|
cy.dataCy('FormModelPopup_save').click();
|
||||||
cy.checkNotification('An item type with the same code already exists');
|
cy.checkNotification('An item type with the same code already exists');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create a new type', () => {
|
it('should create a new type', () => {
|
||||||
cy.dataCy('vnTableCreateBtn').click();
|
cy.dataCy('vnTableCreateBtn').click();
|
||||||
cy.get(
|
cy.dataCy('codeInput').type('LIL');
|
||||||
'div.fit > .q-field > .q-field__inner > .q-field__control > .q-field__control-container > [data-cy="Code_input"]'
|
cy.dataCy('nameInput').type('Lilium');
|
||||||
).type('LIL');
|
cy.dataCy('vnWorkerSelect').type(worker);
|
||||||
cy.get(
|
cy.get('.q-menu .q-item').contains(worker).click();
|
||||||
'div.fit > .q-field > .q-field__inner > .q-field__control > .q-field__control-container > [data-cy="Name_input"]'
|
cy.dataCy('itemCategorySelect').type(type);
|
||||||
).type('Lilium');
|
cy.get('.q-menu .q-item').contains(type).click();
|
||||||
cy.dataCy('Worker_select').type('buyerNick');
|
|
||||||
cy.get('.q-menu .q-item').contains('buyerNick').click();
|
|
||||||
cy.dataCy('ItemCategory_select').type('Flower');
|
|
||||||
cy.get('.q-menu .q-item').contains('Flower').click();
|
|
||||||
cy.dataCy('FormModelPopup_save').click();
|
cy.dataCy('FormModelPopup_save').click();
|
||||||
cy.checkNotification('Data created');
|
cy.checkNotification('Data created');
|
||||||
});
|
});
|
||||||
|
|
|
@ -53,4 +53,29 @@ describe('TicketList', () => {
|
||||||
cy.checkNotification('Data created');
|
cy.checkNotification('Data created');
|
||||||
cy.url().should('match', /\/ticket\/\d+\/summary/);
|
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');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
/// <reference types="cypress" />
|
/// <reference types="cypress" />
|
||||||
describe('VnSearchBar', () => {
|
describe('VnSearchBar', () => {
|
||||||
const employeeId = ' #1';
|
const employeeId = ' #1';
|
||||||
const salesPersonId = ' #18';
|
|
||||||
const idGap = '.q-item > .q-item__label';
|
const idGap = '.q-item > .q-item__label';
|
||||||
const vnTableRow = '.q-virtual-scroll__content';
|
const vnTableRow = '.q-virtual-scroll__content';
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
@ -12,11 +11,10 @@ describe('VnSearchBar', () => {
|
||||||
|
|
||||||
it('should redirect to account summary page', () => {
|
it('should redirect to account summary page', () => {
|
||||||
searchAndCheck('1', employeeId);
|
searchAndCheck('1', employeeId);
|
||||||
searchAndCheck('salesPerson', salesPersonId);
|
searchAndCheck('employee', employeeId);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should stay on the list page if there are several results or none', () => {
|
it('should stay on the list page if there are several results or none', () => {
|
||||||
cy.typeSearchbar('salesA{enter}');
|
|
||||||
cy.typeSearchbar('salesA{enter}');
|
cy.typeSearchbar('salesA{enter}');
|
||||||
checkTableLength(2);
|
checkTableLength(2);
|
||||||
|
|
||||||
|
@ -29,7 +27,6 @@ describe('VnSearchBar', () => {
|
||||||
const searchAndCheck = (searchTerm, expectedText) => {
|
const searchAndCheck = (searchTerm, expectedText) => {
|
||||||
cy.clearSearchbar();
|
cy.clearSearchbar();
|
||||||
cy.typeSearchbar(`${searchTerm}{enter}`);
|
cy.typeSearchbar(`${searchTerm}{enter}`);
|
||||||
cy.typeSearchbar(`${searchTerm}{enter}`);
|
|
||||||
cy.get(idGap).should('have.text', expectedText);
|
cy.get(idGap).should('have.text', expectedText);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -8,16 +8,16 @@ describe('WagonCreate', () => {
|
||||||
it('should create and delete a new wagon', () => {
|
it('should create and delete a new wagon', () => {
|
||||||
cy.dataCy('vnTableCreateBtn').click();
|
cy.dataCy('vnTableCreateBtn').click();
|
||||||
cy.get(
|
cy.get(
|
||||||
'.grid-create > [label="Label"] > .q-field > .q-field__inner > .q-field__control > .q-field__control-container > [data-cy="Label_input"]'
|
'.grid-create > [label="Label"] > .q-field > .q-field__inner > .q-field__control > .q-field__control-container > [data-cy="Label_input"]',
|
||||||
).type('1234');
|
).type('1234');
|
||||||
cy.get(
|
cy.get(
|
||||||
'.grid-create > [label="Plate"] > .q-field > .q-field__inner > .q-field__control > .q-field__control-container > [data-cy="Plate_input"]'
|
'.grid-create > [label="Plate"] > .q-field > .q-field__inner > .q-field__control > .q-field__control-container > [data-cy="Plate_input"]',
|
||||||
).type('1234ABCD');
|
).type('1234ABCD');
|
||||||
cy.get(
|
cy.get(
|
||||||
'.grid-create > [label="Volume"] > .q-field > .q-field__inner > .q-field__control > .q-field__control-container > [data-cy="Volume_input"]'
|
'.grid-create > [label="Volume"] > .q-field > .q-field__inner > .q-field__control > .q-field__control-container > [data-cy="Volume_input"]',
|
||||||
).type('100');
|
).type('100');
|
||||||
cy.dataCy('Type_select').type('{downarrow}{enter}');
|
cy.dataCy('Type_select').type('{downarrow}{enter}');
|
||||||
// // Delete wagon type created
|
|
||||||
cy.get('[to="/null/1"] > .q-card > .column > [title="Remove"]').click();
|
cy.get('[title="Remove"] > .q-btn__content > .q-icon').click();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -6,14 +6,10 @@ describe('WagonTypeCreate', () => {
|
||||||
cy.waitForElement('.q-page', 6000);
|
cy.waitForElement('.q-page', 6000);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create a new wagon type', () => {
|
it('should create a new wagon type and then delete it', () => {
|
||||||
cy.get('.q-page-sticky > div > .q-btn').click();
|
cy.get('.q-page-sticky > div > .q-btn').click();
|
||||||
cy.get('input').first().type('Example for testing');
|
cy.get('input').first().type('Example for testing');
|
||||||
cy.get('button[type="submit"]').click();
|
cy.get('button[type="submit"]').click();
|
||||||
});
|
cy.get('[title="Remove"] > .q-btn__content > .q-icon').first().click();
|
||||||
it('delete a wagon type', () => {
|
|
||||||
cy.get(
|
|
||||||
'[to="/null/2"] > .q-card > .column > [title="Remove"] > .q-btn__content > .q-icon'
|
|
||||||
).click();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -289,40 +289,13 @@ Cypress.Commands.add('openActionDescriptor', (opt) => {
|
||||||
cy.openActionsDescriptor();
|
cy.openActionsDescriptor();
|
||||||
const listItem = '[role="menu"] .q-list .q-item';
|
const listItem = '[role="menu"] .q-list .q-item';
|
||||||
cy.contains(listItem, opt).click();
|
cy.contains(listItem, opt).click();
|
||||||
1;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Cypress.Commands.add('openActionsDescriptor', () => {
|
Cypress.Commands.add('openActionsDescriptor', () => {
|
||||||
cy.get('[data-cy="descriptor-more-opts"]').click();
|
cy.get('[data-cy="descriptor-more-opts"]').click();
|
||||||
});
|
});
|
||||||
|
|
||||||
Cypress.Commands.add('clickButtonsDescriptor', (id) => {
|
Cypress.Commands.add('clickButtonDescriptor', (id) => {
|
||||||
cy.get(`.actions > .q-card__actions> .q-btn:nth-child(${id})`)
|
|
||||||
.invoke('removeAttr', 'target')
|
|
||||||
.click();
|
|
||||||
});
|
|
||||||
|
|
||||||
Cypress.Commands.add('openActionDescriptor', (opt) => {
|
|
||||||
cy.openActionsDescriptor();
|
|
||||||
const listItem = '[role="menu"] .q-list .q-item';
|
|
||||||
cy.contains(listItem, opt).click();
|
|
||||||
1;
|
|
||||||
});
|
|
||||||
|
|
||||||
Cypress.Commands.add('clickButtonsDescriptor', (id) => {
|
|
||||||
cy.get(`.actions > .q-card__actions> .q-btn:nth-child(${id})`)
|
|
||||||
.invoke('removeAttr', 'target')
|
|
||||||
.click();
|
|
||||||
});
|
|
||||||
|
|
||||||
Cypress.Commands.add('openActionDescriptor', (opt) => {
|
|
||||||
cy.openActionsDescriptor();
|
|
||||||
const listItem = '[role="menu"] .q-list .q-item';
|
|
||||||
cy.contains(listItem, opt).click();
|
|
||||||
1;
|
|
||||||
});
|
|
||||||
|
|
||||||
Cypress.Commands.add('clickButtonsDescriptor', (id) => {
|
|
||||||
cy.get(`.actions > .q-card__actions> .q-btn:nth-child(${id})`)
|
cy.get(`.actions > .q-card__actions> .q-btn:nth-child(${id})`)
|
||||||
.invoke('removeAttr', 'target')
|
.invoke('removeAttr', 'target')
|
||||||
.click();
|
.click();
|
||||||
|
@ -374,3 +347,21 @@ Cypress.Commands.add('addBtnClick', () => {
|
||||||
.and('be.visible')
|
.and('be.visible')
|
||||||
.click();
|
.click();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Cypress.Commands.add('clickButtonWith', (type, value) => {
|
||||||
|
switch (type) {
|
||||||
|
case 'icon':
|
||||||
|
cy.clickButtonWithIcon(value);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
cy.clickButtonWithText(value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Cypress.Commands.add('clickButtonWithIcon', (iconClass) => {
|
||||||
|
cy.get(`.q-icon.${iconClass}`).parent().click();
|
||||||
|
});
|
||||||
|
Cypress.Commands.add('clickButtonWithText', (buttonText) => {
|
||||||
|
cy.get('.q-btn').contains(buttonText).click();
|
||||||
|
});
|
||||||
|
|
Loading…
Reference in New Issue