diff --git a/CHANGELOG.md b/CHANGELOG.md index 8e1d4c433..f1d10b26e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,184 @@ +# Version 24.38 - 2024-09-17 + +### Added 🆕 + +- chore: refs #6772 fix e2e (origin/6772-warmfix-fixE2e) by:jorgep +- chore: refs #7323 worker changes by:jorgep +- chore: refs #7353 fix warnings by:jorgep +- chore: refs #7353 use Vue component nomenclature by:jorgep +- chore: refs #7356 fix type by:jorgep +- feat(AccountConnections): use VnToken by:alexm +- feat: add key to routerView by:Javier Segarra +- feat: add plus shortcut in VnTable by:Javier Segarra +- feat: add row by:Javier Segarra +- feat: addRow withour dialog by:Javier Segarra +- feat: apply mixin by:Javier Segarra +- feat by:Javier Segarra +- feat: change navBar buttons by:Javier Segarra +- feat: dense rows by:Javier Segarra +- feat: fields with wrong name by:jgallego +- feat: fix bugs and filters by:Javier Segarra +- feat: fix refund parameters by:jgallego +- feat: handle create row by:Javier Segarra +- feat: handle dates by:Javier Segarra +- feat: handle qCheckbox 3rd state by:Javier Segarra +- feat: imrpove VnInputTime to set cursor at start by:Javier Segarra +- feat: keyShortcut directive by:Javier Segarra +- feat: minor fixes by:jgallego +- feat: only filter by isDestiny by:Javier Segarra +- feat: refs #211153 businessDataLinkGrafana by:robert +- feat: refs #7129 add km start and end on create form by:pablone +- feat: refs #7353 add filter & fix customTags by:jorgep +- feat: refs #7353 add locale by:jorgep +- feat: refs #7353 add no one opt by:jorgep +- feat: refs #7353 add right icons by:jorgep +- feat: refs #7353 imporve toDateFormat by:jorgep +- feat: refs #7353 salesPerson nickname & id by:jorgep +- feat: refs #7353 split sections by:jorgep +- feat: refs #7847 remove reload btn by:jorgep +- feat: refs #7847 remove reload fn by:jorgep +- feat: refs #7889 added shortcuts to modules by:Jon +- feat: refs #7911 added shortcut to modules by:Jon +- feat: refuncInvoiceForm component by:jgallego +- feat: remove duplicity by:Javier Segarra +- feat: remove future itemFixedPrices by:Javier Segarra +- feat: replace stickyButtons by subtoolbar by:Javier Segarra +- feat: required validation by:Javier Segarra +- feat: show bad dates by:Javier Segarra +- feat: showdate icons by:Javier Segarra +- feat: solve ItemFixedFilterPanel by:Javier Segarra +- feat: transfer an invoice by:jgallego +- feat: try to fix ItemFixedFilterPanel by:Javier Segarra +- feat: unnecessary changes by:Javier Segarra +- feat: update changelog (origin/7896_down_devToTest_2436) by:Javier Segarra +- feat: updates by:Javier Segarra +- feat: update version and changelog by:Javier Segarra +- feat: vnInput\* by:Javier Segarra +- feat: with VnTable by:Javier Segarra +- refs #6772 feat: fix approach by:Javier Segarra +- refs #6772 feat: refresh shelving.basic-data by:Javier Segarra +- style: show subName value by:Javier Segarra + +### Changed 📦 + +- perf: add v-shortcut in VnCard by:Javier Segarra +- perf: approach by:Javier Segarra +- perf: change directive location by:Javier Segarra +- perf: change slots order by:Javier Segarra +- perf: examples by:Javier Segarra +- perf: hide icon for VnInputDate by:Javier Segarra +- perf: improve ItemFixedPricefilterPanel by:Javier Segarra +- perf: improve mainShrotcutMixin by:Javier Segarra +- perf: minor clean code by:Javier Segarra +- perf: onRowchange by:Javier Segarra +- perf: order by by:Javier Segarra +- perf: order components by:Javier Segarra +- perf: refs #7889 perf shortcut test by:Jon +- perf: remove console.log by:Javier Segarra +- perf: remove icons in header slot by:Javier Segarra +- perf: remove print variables by:Javier Segarra +- perf: restore CustomerBasicData by:Javier Segarra +- refactor: deleted useless prop by:Jon +- refactor: deleted useless prop in FetchedTags by:Jon +- refactor: refs #7323 drop useless code by:jorgep +- refactor: refs #7353 clients correction by:jorgep +- refactor: refs #7353 clients correction wip by:jorgep +- refactor: refs #7353 ease logic by:jorgep +- refactor: refs #7353 order correction by:jorgep +- refactor: refs #7353 simplify code by:jorgep +- refactor: refs #7353 tickets correction by:jorgep +- refactor: refs #7353 use global locales by:jorgep +- refactor: refs #7354 changed descriptor menu options by:Jon +- refactor: refs #7354 changed icon color in table and notification when deleting a zone by:Jon +- refactor: refs #7354 fix tableFilters by:Jon +- refactor: refs #7354 modified VnInputTime by:Jon +- refactor: refs #7354 refactor deliveryPanel by:Jon +- refactor: refs #7354 refactor zones section and fixed e2e tests by:Jon +- refactor: refs #7354 requested changes by:Jon +- refactor: refs #7354 reverse deliveryPanel changes by:Jon +- refactor: refs #7354 Zone migration changes by:Jon +- refactor: refs #7889 deleted subtitle attr and use keyBinding instead by:Jon +- refactor: refs #7889 modified shortcut and dashboard, and added tootlip in LeftMenu by:Jon +- refs #6722 perf: not fetch when id not exists by:Javier Segarra +- refs #6772 perf: change variable name by:JAVIER SEGARRA MARTINEZ +- refs #6772 perf: use ArrayData (6772_reload_sections) by:Javier Segarra +- refs #7283 refactor fix ItemDescriptor by:carlossa +- refs #7283 refactor ItexDescriptor by:carlossa + +### Fixed 🛠️ + +- chore: refs #6772 fix e2e (origin/6772-warmfix-fixE2e) by:jorgep +- chore: refs #7353 fix warnings by:jorgep +- chore: refs #7356 fix type by:jorgep +- feat: fix bugs and filters by:Javier Segarra +- feat: fix refund parameters by:jgallego +- feat: minor fixes by:jgallego +- feat: refs #7353 add filter & fix customTags by:jorgep +- feat: try to fix ItemFixedFilterPanel by:Javier Segarra +- fix: add border-top by:Javier Segarra +- fix: added missing descriptors and small details by:Jon +- fix branch by:carlossa +- fix: call upsert when crudModel haschanges by:Javier Segarra +- fix(ClaimList): fix summary by:alexm +- fix: cli warnings by:Javier Segarra +- fix: editTableOptions by:Javier Segarra +- fix events and descriptor menu by:Jon +- fix: InvoiceIn sections (origin/6772_reload_sections) by:Javier Segarra +- fix: minor changes by:Javier Segarra +- fix: minor error whit dates by:Javier Segarra +- fix: module icon by:Javier Segarra +- fix: options QDate by:Javier Segarra +- fix: refs #6900 e2e error by:jorgep +- fix: refs #6900 rollback by:jorgep +- fix: refs #7353 css by:jorgep +- fix: refs #7353 hide search param (origin/7353-warmfix-fixSearchbar) by:jorgep +- fix: refs #7353 iron out filter by:jorgep +- fix: refs #7353 iron out ticket table by:jorgep +- fix: refs #7353 padding by:jorgep +- fix: refs #7353 salesClientTable by:jorgep +- fix: refs #7353 salesorderTable by:jorgep +- fix: refs #7353 saleTicketMonitors by:jorgep +- fix: refs #7353 use same datakey by:jorgep +- fix: refs #7353 vnTable colors by:jorgep +- fix: refs #7354 e2e tests by:Jon +- fix: refs #7354 fix delivery days by:Jon +- fix: refs #7354 fix list searchbar and filters by:Jon +- fix: refs #7354 fix VnSearchbar search for zone section & finished basic tests by:Jon +- fix: refs #7354 fix VnTable filters and agency field by:Jon +- fix: refs #7354 fix zoneSearchbar by:Jon +- fix: refs #7354 requested changes by:Jon +- fix: refs #7356 colors by:jorgep +- fix: refs #7356 create claim dialog by:jorgep +- fix: refs #7889 fixed shortcut test by:Jon +- fix: refs #7903 fixed ticket's search bar and keybinding tooltip by:Jon +- fix: refs #7911 fixed shortcut and related files by:Jon +- fix: remove condition duplicated by:Javier Segarra +- fix: remove property by:Javier Segarra +- fix tootltip by:carlossa +- fix traduction by:carlossa +- fix(VnSectionMain): add QPage by:alexm +- fix(zone): zoneLocation and the others searchbar by:alexm +- refactor: refs #7354 fix tableFilters by:Jon +- refactor: refs #7354 refactor zones section and fixed e2e tests by:Jon +- refs #6772 feat: fix approach by:Javier Segarra +- refs #6772 fix: claimPhoto reload by:Javier Segarra +- refs #6896 fix searchbar by:carlossa +- refs #6897 fix entry by:carlossa +- refs #6899 fix invoiceFix by:carlossa +- refs #6899 fix order by:carlossa +- refs #7283 fix by:carlossa +- refs #7283 fix ItemDescriptor warehouse by:carlossa +- refs #7283 refactor fix ItemDescriptor by:carlossa +- refs #7355 #7366 fix account, summary, list, travelList, tooltip by:carlossa +- refs #7355 fix accountPrivileges by:carlossa +- refs #7355 fix accounts, vnTable by:carlossa +- refs #7355 fix privileges by:carlossa +- refs #7355 fix roles filters by:carlossa +- refs #7355 fix total by:carlossa +- refs #7355 fix views summarys, entryList, travelList refact by:carlossa +- refs #7366 fix travel hours by:carlossa +- test: fix e2e by:Javier Segarra + # Version 24.36 - 2024-08-27 ### Added 🆕 diff --git a/package.json b/package.json index eaffd8d85..eaaa0b812 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "salix-front", - "version": "24.40.0", + "version": "24.42.0", "description": "Salix frontend", "productName": "Salix", "author": "Verdnatura", @@ -62,4 +62,4 @@ "vite": "^5.1.4", "vitest": "^0.31.1" } -} \ No newline at end of file +} diff --git a/src/boot/axios.js b/src/boot/axios.js index 9b32275bd..99a163cca 100644 --- a/src/boot/axios.js +++ b/src/boot/axios.js @@ -5,8 +5,10 @@ import useNotify from 'src/composables/useNotify.js'; const session = useSession(); const { notify } = useNotify(); +const baseUrl = '/api/'; -axios.defaults.baseURL = '/api/'; +axios.defaults.baseURL = baseUrl; +const axiosNoError = axios.create({ baseURL: baseUrl }); const onRequest = (config) => { const token = session.getToken(); @@ -79,5 +81,7 @@ const onResponseError = (error) => { axios.interceptors.request.use(onRequest, onRequestError); axios.interceptors.response.use(onResponse, onResponseError); +axiosNoError.interceptors.request.use(onRequest); +axiosNoError.interceptors.response.use(onResponse); -export { onRequest, onResponseError }; +export { onRequest, onResponseError, axiosNoError }; diff --git a/src/boot/quasar.js b/src/boot/quasar.js index e2035c880..5db6edd24 100644 --- a/src/boot/quasar.js +++ b/src/boot/quasar.js @@ -2,9 +2,15 @@ import { boot } from 'quasar/wrappers'; import qFormMixin from './qformMixin'; import mainShortcutMixin from './mainShortcutMixin'; import keyShortcut from './keyShortcut'; +import useNotify from 'src/composables/useNotify.js'; +const { notify } = useNotify(); export default boot(({ app }) => { app.mixin(qFormMixin); app.mixin(mainShortcutMixin); app.directive('shortcut', keyShortcut); + app.config.errorHandler = function (err) { + console.error(err); + notify('globals.error', 'negative', 'error'); + }; }); diff --git a/src/components/CreateBankEntityForm.vue b/src/components/CreateBankEntityForm.vue index c46ac7752..0a3c10f57 100644 --- a/src/components/CreateBankEntityForm.vue +++ b/src/components/CreateBankEntityForm.vue @@ -1,5 +1,5 @@ - + diff --git a/src/components/common/VnCard.vue b/src/components/common/VnCard.vue index 5cee06582..0d80f43ce 100644 --- a/src/components/common/VnCard.vue +++ b/src/components/common/VnCard.vue @@ -24,7 +24,9 @@ const stateStore = useStateStore(); const route = useRoute(); const router = useRouter(); const url = computed(() => { - if (props.baseUrl) return `${props.baseUrl}/${route.params.id}`; + if (props.baseUrl) { + return `${props.baseUrl}/${route.params.id}`; + } return props.customUrl; }); const searchRightDataKey = computed(() => { @@ -40,8 +42,10 @@ onBeforeMount(async () => { try { if (!props.baseUrl) arrayData.store.filter.where = { id: route.params.id }; await arrayData.fetch({ append: false, updateRouter: false }); - } catch (e) { - router.push({ name: 'WorkerList' }); + } catch { + const { matched: matches } = router.currentRoute.value; + const { path } = matches.at(-1); + router.push({ path: path.replace(/:id.*/, '') }); } }); @@ -79,7 +83,7 @@ if (props.baseUrl) { - + diff --git a/src/components/common/VnComponent.vue b/src/components/common/VnComponent.vue index fa99f9892..bd25c787c 100644 --- a/src/components/common/VnComponent.vue +++ b/src/components/common/VnComponent.vue @@ -17,17 +17,15 @@ const $props = defineProps({ }, }); -let mixed; const componentArray = computed(() => { if (typeof $props.prop === 'object') return [$props.prop]; return $props.prop; }); function mix(toComponent) { - if (mixed) return mixed; const { component, attrs, event } = toComponent; const customComponent = $props.components[component]; - mixed = { + return { component: customComponent?.component ?? component, attrs: { ...toValueAttrs(attrs), @@ -37,7 +35,6 @@ function mix(toComponent) { }, event: { ...customComponent?.event, ...event }, }; - return mixed; } function toValueAttrs(attrs) { diff --git a/src/components/common/VnDmsList.vue b/src/components/common/VnDmsList.vue index 68ff0e359..52dd6ef79 100644 --- a/src/components/common/VnDmsList.vue +++ b/src/components/common/VnDmsList.vue @@ -5,12 +5,14 @@ import { useRoute } from 'vue-router'; import { useQuasar, QCheckbox, QBtn, QInput } from 'quasar'; import axios from 'axios'; +import VnUserLink from '../ui/VnUserLink.vue'; +import { downloadFile } from 'src/composables/downloadFile'; +import VnImg from 'components/ui/VnImg.vue'; import VnPaginate from 'components/ui/VnPaginate.vue'; import VnDms from 'src/components/common/VnDms.vue'; import VnConfirm from 'components/ui/VnConfirm.vue'; import VnInputDate from 'components/common/VnInputDate.vue'; -import VnUserLink from '../ui/VnUserLink.vue'; -import { downloadFile } from 'src/composables/downloadFile'; +import { useSession } from 'src/composables/useSession'; const route = useRoute(); const quasar = useQuasar(); @@ -18,6 +20,7 @@ const { t } = useI18n(); const rows = ref(); const dmsRef = ref(); const formDialog = ref({}); +const token = useSession().getTokenMultimedia(); const $props = defineProps({ model: { @@ -89,6 +92,23 @@ const dmsFilter = { }; const columns = computed(() => [ + { + label: '', + name: 'file', + align: 'left', + component: VnImg, + props: (prop) => { + return { + storage: 'dms', + collection: null, + resolution: null, + id: prop.row.file.split('.')[0], + token: token, + class: 'rounded', + ratio: 1, + }; + }, + }, { align: 'left', field: 'id', @@ -142,13 +162,6 @@ const columns = computed(() => [ 'model-value': Boolean(prop.value), }), }, - { - align: 'left', - field: 'file', - label: t('globals.file'), - name: 'file', - component: 'span', - }, { align: 'left', field: 'worker', @@ -387,7 +400,14 @@ defineExpose({ /> - + {{ t('Upload file') }} @@ -395,10 +415,6 @@ defineExpose({ + + es: + Edit travel: Editar envío + Travel: Envíos + Booked trucks: Camiones reservados + Buyer: Comprador + Reserve: Reservado + Bought: Comprado + More: Más + Date: Fecha + Reserve some space: Reservar espacio + This buyer has already made a reservation for this date: Este comprador ya ha hecho una reserva para esta fecha + diff --git a/src/pages/Entry/EntryStockBoughtDetail.vue b/src/pages/Entry/EntryStockBoughtDetail.vue new file mode 100644 index 000000000..2c1a5a47e --- /dev/null +++ b/src/pages/Entry/EntryStockBoughtDetail.vue @@ -0,0 +1,129 @@ + + + + + + + + + + + {{ row?.entryFk }} + + + + + + {{ row?.itemName }} + + + + + + + + + + es: + Buyer: Comprador + Reserve: Reservado + Bought: Comprado + More: Más + Date: Fecha + Entry: Entrada + Item: Artículo + Name: Nombre + Volume: Volumen + Packaging: Embalage + diff --git a/src/pages/Entry/EntryStockBoughtFilter.vue b/src/pages/Entry/EntryStockBoughtFilter.vue new file mode 100644 index 000000000..7694cfe6c --- /dev/null +++ b/src/pages/Entry/EntryStockBoughtFilter.vue @@ -0,0 +1,63 @@ + + + + + + + {{ t(`params.${tag.label}`) }}: + {{ formatFn(tag.value) }} + + + + + + + + + + + + + en: + params: + dated: Date + workerFk: Worker + es: + Date: Fecha + params: + dated: Date + workerFk: Trabajador + diff --git a/src/pages/Entry/locale/en.yml b/src/pages/Entry/locale/en.yml index f0965b097..a9faa814b 100644 --- a/src/pages/Entry/locale/en.yml +++ b/src/pages/Entry/locale/en.yml @@ -11,4 +11,4 @@ shipped: Shipped fromShipped: Shipped(from) toShipped: Shipped(to) printLabels: Print stickers -printLabel: Print sticker +viewLabel: View sticker diff --git a/src/pages/Entry/locale/es.yml b/src/pages/Entry/locale/es.yml index aba04571e..eb1e3f88a 100644 --- a/src/pages/Entry/locale/es.yml +++ b/src/pages/Entry/locale/es.yml @@ -15,4 +15,4 @@ shipped: F. salida fromShipped: F. salida(desde) toShipped: F. salida(hasta) printLabels: Imprimir etiquetas -printLabel: Imprimir etiqueta +viewLabel: Ver etiqueta diff --git a/src/pages/InvoiceIn/Card/InvoiceInBasicData.vue b/src/pages/InvoiceIn/Card/InvoiceInBasicData.vue index 045517a3f..c9468557f 100644 --- a/src/pages/InvoiceIn/Card/InvoiceInBasicData.vue +++ b/src/pages/InvoiceIn/Card/InvoiceInBasicData.vue @@ -281,6 +281,7 @@ async function onSubmit() { v-else icon="add_circle" round + shortcut="+" padding="xs" @click="setCreateDms()" > diff --git a/src/pages/InvoiceIn/Card/InvoiceInDueDay.vue b/src/pages/InvoiceIn/Card/InvoiceInDueDay.vue index 1593ea1be..e8f73848b 100644 --- a/src/pages/InvoiceIn/Card/InvoiceInDueDay.vue +++ b/src/pages/InvoiceIn/Card/InvoiceInDueDay.vue @@ -230,7 +230,7 @@ async function insert() { - + diff --git a/src/pages/Monitor/MonitorOrders.vue b/src/pages/Monitor/MonitorOrders.vue index eb455a239..52d442d0a 100644 --- a/src/pages/Monitor/MonitorOrders.vue +++ b/src/pages/Monitor/MonitorOrders.vue @@ -132,7 +132,6 @@ const openTab = (id) => :table="{ 'row-key': 'id', selection: 'multiple', - 'hide-bottom': true, }" default-mode="table" :row-click="({ id }) => openTab(id)" diff --git a/src/pages/Monitor/Ticket/MonitorTicketFilter.vue b/src/pages/Monitor/Ticket/MonitorTicketFilter.vue index 167a10465..57248d580 100644 --- a/src/pages/Monitor/Ticket/MonitorTicketFilter.vue +++ b/src/pages/Monitor/Ticket/MonitorTicketFilter.vue @@ -11,7 +11,7 @@ import FetchData from 'src/components/FetchData.vue'; import { dateRange } from 'src/filters'; defineProps({ dataKey: { type: String, required: true } }); -const { t } = useI18n(); +const { t, te } = useI18n(); const warehouses = ref(); const groupedStates = ref(); @@ -26,6 +26,12 @@ const handleScopeDays = (params, days, callback) => { } if (callback) callback(); }; + +const getLocale = (label) => { + const param = label.split('.').at(-1); + const globalLocale = `globals.params.${param}`; + return te(globalLocale) ? t(globalLocale) : t(`params.${param}`); +}; (warehouses = data)" /> @@ -40,13 +46,14 @@ const handleScopeDays = (params, days, callback) => { - + @@ -64,7 +71,7 @@ const handleScopeDays = (params, days, callback) => { @@ -105,12 +112,12 @@ const handleScopeDays = (params, days, callback) => { outlined dense rounded - :label="t('params.salesPersonFk')" + :label="t('globals.params.salesPersonFk')" v-model="params.salesPersonFk" url="Workers/search" :params="{ departmentCodes: ['VT'] }" is-outlined - option-value="code" + option-value="id" option-label="name" :no-one="true" > @@ -158,7 +165,7 @@ const handleScopeDays = (params, days, callback) => { outlined dense rounded - :label="t('params.stateFk')" + :label="t('globals.params.stateFk')" v-model="params.stateFk" url="States" is-outlined @@ -184,7 +191,7 @@ const handleScopeDays = (params, days, callback) => { outlined dense rounded - :label="t('params.warehouseFk')" + :label="t('globals.params.warehouseFk')" v-model="params.warehouseFk" :options="warehouses" /> @@ -196,7 +203,7 @@ const handleScopeDays = (params, days, callback) => { outlined dense rounded - :label="t('params.provinceFk')" + :label="t('globals.params.provinceFk')" v-model="params.provinceFk" url="Provinces" /> @@ -235,22 +242,15 @@ const handleScopeDays = (params, days, callback) => { en: params: - clientFk: Client id orderFk: Order id scopeDays: Days onward nickname: Nickname - salesPersonFk: Sales person refFk: Invoice agencyModeFk: Agency - stateFk: State groupedStates: Grouped State - warehouseFk: Warehouse - provinceFk: Province myTeam: My team problems: With problems pending: Pending - from: From - to: To alertLevel: Grouped State FREE: Free DELIVERED: Delivered @@ -261,22 +261,15 @@ en: es: params: - clientFk: Id cliente orderFk: Id cesta scopeDays: Días en adelante nickname: Nombre mostrado - salesPersonFk: Comercial refFk: Factura agencyModeFk: Agencia - stateFk: Estado groupedStates: Estado agrupado - warehouseFk: Almacén - provinceFk: Provincia myTeam: Mi equipo problems: Con problemas pending: Pendiente - from: Desde - To: Hasta alertLevel: Estado agrupado FREE: Libre DELIVERED: Servido diff --git a/src/pages/Monitor/Ticket/MonitorTicketSearchbar.vue b/src/pages/Monitor/Ticket/MonitorTicketSearchbar.vue index 4950ab381..f1c347588 100644 --- a/src/pages/Monitor/Ticket/MonitorTicketSearchbar.vue +++ b/src/pages/Monitor/Ticket/MonitorTicketSearchbar.vue @@ -3,7 +3,7 @@ import VnSearchbar from 'components/ui/VnSearchbar.vue'; [ label: t('salesTicketsTable.problems'), name: 'totalProblems', align: 'left', - columnFilter: false, attrs: { dense: true, @@ -65,7 +64,6 @@ const columns = computed(() => [ name: 'id', field: 'id', align: 'left', - columnFilter: { component: 'number', name: 'id', @@ -108,9 +106,7 @@ const columns = computed(() => [ { label: t('salesTicketsTable.date'), name: 'shippedDate', - style: { 'max-width': '100px' }, align: 'left', - columnFilter: { component: 'date', name: 'shippedDate', @@ -164,7 +160,6 @@ const columns = computed(() => [ label: t('salesTicketsTable.state'), name: 'state', align: 'left', - style: { 'max-width': '100px' }, columnFilter: { component: 'select', name: 'stateFk', @@ -193,7 +188,6 @@ const columns = computed(() => [ label: t('salesTicketsTable.zone'), name: 'zoneFk', align: 'left', - columnFilter: { component: 'select', name: 'zoneFk', @@ -210,8 +204,6 @@ const columns = computed(() => [ name: 'totalWithVat', field: 'totalWithVat', align: 'left', - style: { 'max-width': '75px' }, - columnFilter: { component: 'number', name: 'totalWithVat', @@ -370,7 +362,7 @@ const openTab = (id) => - + > {{ $t('salesTicketsTable.tooLittle') }} - + - - - {{ row.id }} - - - + + {{ row.id }} + + - - {{ row.nickname }} + + - + - + - + - - - {{ formatShippedDate(row.shippedDate) }} - - + + {{ formatShippedDate(row.shippedDate) }} + - - - + - + {{ row.refFk }} @@ -477,32 +463,33 @@ const openTab = (id) => > {{ row.state }} - + - - - {{ $t('salesTicketsTable.isFragile') }} - - + + {{ $t('salesTicketsTable.isFragile') }} + - + {{ row.zoneName }} - + - - - {{ toCurrency(row.totalWithVat) }} - - + + {{ toCurrency(row.totalWithVat) }} + + diff --git a/src/pages/Order/Card/OrderCatalogFilter.vue b/src/pages/Order/Card/OrderCatalogFilter.vue index 938cc4fe2..354c44747 100644 --- a/src/pages/Order/Card/OrderCatalogFilter.vue +++ b/src/pages/Order/Card/OrderCatalogFilter.vue @@ -374,8 +374,10 @@ function addOrder(value, field, params) { /> - diff --git a/src/pages/Order/Card/OrderCreateDialog.vue b/src/pages/Order/Card/OrderCreateDialog.vue new file mode 100644 index 000000000..9d5c9281e --- /dev/null +++ b/src/pages/Order/Card/OrderCreateDialog.vue @@ -0,0 +1,220 @@ + + + + (clientOptions = data)" + :filter="{ fields: ['id', 'name', 'defaultAddressFk'], order: 'id' }" + auto-load + /> + + + + + + + + + {{ `${scope.opt.id}: ${scope.opt.name}` }} + + + + + + + + + + + {{ + `${scope.opt.nickname}: ${scope.opt.street},${scope.opt.city}` + }} + + + + + + + + fetchAgencyList(data.landed, data.addressId) + " + /> + + + + + + + + + + + es: + No default address found for the client: No hay ninguna dirección asociada a este cliente. + diff --git a/src/pages/Order/Card/OrderLines.vue b/src/pages/Order/Card/OrderLines.vue index 17a157797..175c956e1 100644 --- a/src/pages/Order/Card/OrderLines.vue +++ b/src/pages/Order/Card/OrderLines.vue @@ -249,7 +249,7 @@ watch( @on-fetch="(data) => (orderSummary.vat = data)" auto-load /> - + [ { align: 'left', @@ -169,6 +170,13 @@ const getDateColor = (date) => { if (comparation == 0) return 'bg-warning'; if (comparation < 0) return 'bg-success'; }; + +onMounted(() => { + if (!route.query.createForm) return; + const clientId = route.query.createForm; + const id = JSON.parse(clientId); + fetchClientAddress(id.clientFk, id); +}); @@ -184,13 +192,14 @@ const getDateColor = (date) => { :order="['landed DESC', 'clientFk ASC', 'id DESC']" :create="{ urlCreate: 'Orders/new', - title: 'Create Order', + title: t('module.cerateOrder'), onDataSaved: (url) => { tableRef.redirect(url); }, formInitialData: { active: true, addressId: null, + clientFk: null, }, }" :user-params="{ showEmpty: false }" @@ -221,7 +230,7 @@ const getDateColor = (date) => { fetchClientAddress(id, data)" /> diff --git a/src/pages/Order/locale/en.yml b/src/pages/Order/locale/en.yml index b630a18ed..4349bc76f 100644 --- a/src/pages/Order/locale/en.yml +++ b/src/pages/Order/locale/en.yml @@ -10,6 +10,7 @@ module: total: Total salesPerson: Sales Person address: Address + cerateOrder: Create order lines: item: Item warehouse: Warehouse diff --git a/src/pages/Order/locale/es.yml b/src/pages/Order/locale/es.yml index 055d22719..cef06cb6d 100644 --- a/src/pages/Order/locale/es.yml +++ b/src/pages/Order/locale/es.yml @@ -10,6 +10,7 @@ module: total: Total salesPerson: Comercial address: Dirección + cerateOrder: Crear cesta lines: item: Artículo warehouse: Almacén diff --git a/src/pages/Route/Agency/AgencyList.vue b/src/pages/Route/Agency/AgencyList.vue index 42aede8a0..9d456c1da 100644 --- a/src/pages/Route/Agency/AgencyList.vue +++ b/src/pages/Route/Agency/AgencyList.vue @@ -27,12 +27,15 @@ const columns = computed(() => [ condition: () => true, }, isId: true, + columnFilter: false, }, { align: 'left', label: t('globals.name'), name: 'name', isTitle: true, + columnFilter: false, + columnClass: 'expand', }, { align: 'left', @@ -70,18 +73,33 @@ const columns = computed(() => [ data-key="AgencyList" :expr-builder="exprBuilder" /> - + + + + + + es: isOwn: Tiene propietario diff --git a/src/pages/Route/Agency/Card/AgencyWorkcenter.vue b/src/pages/Route/Agency/Card/AgencyWorkcenter.vue index 3531ad288..1f3cab5d0 100644 --- a/src/pages/Route/Agency/Card/AgencyWorkcenter.vue +++ b/src/pages/Route/Agency/Card/AgencyWorkcenter.vue @@ -88,7 +88,7 @@ async function deleteWorCenter(id) { - + { {{ props.value }} - + diff --git a/src/pages/Route/Card/RouteSearchbar.vue b/src/pages/Route/Card/RouteSearchbar.vue index 48ad09151..a8e11cef6 100644 --- a/src/pages/Route/Card/RouteSearchbar.vue +++ b/src/pages/Route/Card/RouteSearchbar.vue @@ -3,7 +3,6 @@ import VnSearchbar from 'components/ui/VnSearchbar.vue'; import { useI18n } from 'vue-i18n'; const { t } = useI18n(); - { - { {{ t('Add stop') }} - + diff --git a/src/pages/Route/Roadmap/RoadmapSummary.vue b/src/pages/Route/Roadmap/RoadmapSummary.vue index 7f8b7107b..3fb36b4f7 100644 --- a/src/pages/Route/Roadmap/RoadmapSummary.vue +++ b/src/pages/Route/Roadmap/RoadmapSummary.vue @@ -149,8 +149,8 @@ const filter = { es: Carrier: Transportista - Tractor Plate: Matrícula tractor - Trailer Plate: Matrícula trailer + Tractor Plate: Matrícula tractora + Trailer Plate: Matrícula remolque Phone: Teléfono Worker: Trabajador Observations: Observaciones diff --git a/src/pages/Route/RouteExtendedList.vue b/src/pages/Route/RouteExtendedList.vue new file mode 100644 index 000000000..51da4ec12 --- /dev/null +++ b/src/pages/Route/RouteExtendedList.vue @@ -0,0 +1,360 @@ + + + + + + + + {{ t('route.Select the starting date') }} + + + + + + + + + {{ t('globals.clone') }} + + + + + + + + + + + + + + {{ 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 7e2358236..d0feb9a65 100644 --- a/src/pages/Route/RouteList.vue +++ b/src/pages/Route/RouteList.vue @@ -1,32 +1,19 @@ - - - - - {{ t('Select the starting date') }} - - - - - - - - - {{ t('globals.clone') }} - - - - - - - - {{ t('Clone Selected Routes') }} - - - {{ t('Download selected routes as PDF') }} - - - {{ t('Mark as served') }} - + + + {{ row?.workerUserName }} + + - - - -en: - newRoute: New Route - hourStarted: Started hour - hourFinished: Finished hour -es: - From: Desde - To: Hasta - Worker: Trabajador - Agency: Agencia - Vehicle: Vehículo - Volume: Volumen - Date: Fecha - Description: Descripción - Hour started: Hora inicio - Hour finished: Hora fin - KmStart: Km inicio - KmEnd: Km fin - Served: Servida - newRoute: Nueva Ruta - Clone Selected Routes: Clonar rutas seleccionadas - Select the starting date: Seleccione la fecha de inicio - Stating date: Fecha de inicio - Cancel: Cancelar - Mark as served: Marcar como servidas - Download selected routes as PDF: Descargar rutas seleccionadas como PDF - Add ticket: Añadir tickets - Preview: Vista previa - Summary: Resumen - Route is closed: La ruta está cerrada - Route is not served: La ruta no está servida - hourStarted: Hora de inicio - hourFinished: Hora de fin - diff --git a/src/pages/Route/RouteRoadmap.vue b/src/pages/Route/RouteRoadmap.vue index 306387cbe..3687442f5 100644 --- a/src/pages/Route/RouteRoadmap.vue +++ b/src/pages/Route/RouteRoadmap.vue @@ -87,7 +87,7 @@ const columns = computed(() => [ actions: [ { title: t('Ver cmr'), - icon: 'visibility', + icon: 'preview', isPrimary: true, action: (row) => viewSummary(row?.id, RoadmapSummary), }, @@ -237,4 +237,5 @@ es: Price: Precio Observations: Observaciones Preview: Vista previa + Select the estimated date of departure (ETD): Selecciona la fecha estimada de salida diff --git a/src/pages/Route/RouteTickets.vue b/src/pages/Route/RouteTickets.vue index 9356f7590..3bdad4fec 100644 --- a/src/pages/Route/RouteTickets.vue +++ b/src/pages/Route/RouteTickets.vue @@ -342,10 +342,7 @@ const openSmsDialog = async () => { - + {{ value }} {{ t('Open buscaman') }} @@ -353,7 +350,7 @@ const openSmsDialog = async () => { - + {{ value }} @@ -361,7 +358,7 @@ const openSmsDialog = async () => { - + {{ value }} @@ -396,7 +393,7 @@ const openSmsDialog = async () => { - + {{ t('Add ticket') }} diff --git a/src/pages/Route/locale/en.yml b/src/pages/Route/locale/en.yml new file mode 100644 index 000000000..617d704d2 --- /dev/null +++ b/src/pages/Route/locale/en.yml @@ -0,0 +1,25 @@ +route: + Worker: Worker + Agency: Agency + Vehicle: Vehicle + Description: Description + hourStarted: H.Start + hourFinished: H.End + createRoute: Create route + From: From + To: To + Date: Date + KmStart: Km start + KmEnd: Km end + Served: Served + Clone Selected Routes: Clone selected routes + Select the starting date: Select the starting date + Stating date: Starting date + Cancel: Cancel + Mark as served: Mark as served + Download selected routes as PDF: Download selected routes as PDF + Add ticket: Add ticket + Preview: Preview + Summary: Summary + Route is closed: Route is closed + Route is not served: Route is not served diff --git a/src/pages/Route/locale/es.yml b/src/pages/Route/locale/es.yml new file mode 100644 index 000000000..ed96ad915 --- /dev/null +++ b/src/pages/Route/locale/es.yml @@ -0,0 +1,25 @@ +route: + Worker: Trabajador + Agency: Agencia + Vehicle: Vehículo + Description: Descripción + hourStarted: H.Inicio + hourFinished: H.Fin + createRoute: Crear ruta + From: Desde + To: Hasta + Date: Fecha + KmStart: Km inicio + KmEnd: Km fin + Served: Servida + Clone Selected Routes: Clonar rutas seleccionadas + Select the starting date: Seleccione la fecha de inicio + Stating date: Fecha de inicio + Cancel: Cancelar + Mark as served: Marcar como servidas + Download selected routes as PDF: Descargar rutas seleccionadas como PDF + Add ticket: Añadir tickets + Preview: Vista previa + Summary: Resumen + Route is closed: La ruta está cerrada + Route is not served: La ruta no está servida diff --git a/src/pages/Supplier/Card/SupplierAccounts.vue b/src/pages/Supplier/Card/SupplierAccounts.vue index b0e8b06e8..177466478 100644 --- a/src/pages/Supplier/Card/SupplierAccounts.vue +++ b/src/pages/Supplier/Card/SupplierAccounts.vue @@ -102,9 +102,7 @@ const setWireTransfer = async () => { - {{ - t('components.iban_tooltip') - }} + {{ t('components.iban_tooltip') }} @@ -115,6 +113,7 @@ const setWireTransfer = async () => { option-label="bic" option-value="id" hide-selected + :roles-allowed-to-create="['financial']" > { - { {{ t('Add account') }} - + diff --git a/src/pages/Supplier/Card/SupplierAddresses.vue b/src/pages/Supplier/Card/SupplierAddresses.vue index 4bb6d5622..f46a3be19 100644 --- a/src/pages/Supplier/Card/SupplierAddresses.vue +++ b/src/pages/Supplier/Card/SupplierAddresses.vue @@ -26,7 +26,13 @@ const addressesFilter = { { relation: 'province', scope: { - fields: ['id', 'name'], + fields: ['id', 'name', 'countryFk'], + include: [ + { + relation: 'country', + scope: { fields: ['id', 'name'] }, + }, + ], }, }, ], diff --git a/src/pages/Supplier/Card/SupplierAddressesCreate.vue b/src/pages/Supplier/Card/SupplierAddressesCreate.vue index 6e51ee94e..290373039 100644 --- a/src/pages/Supplier/Card/SupplierAddressesCreate.vue +++ b/src/pages/Supplier/Card/SupplierAddressesCreate.vue @@ -21,6 +21,7 @@ const newAddressForm = reactive({ provinceFk: null, phone: null, mobile: null, + province: null, }); const onDataSaved = () => { @@ -84,7 +85,16 @@ function handleLocation(data, location) { handleLocation(data, location)" > diff --git a/src/pages/Supplier/Card/SupplierConsumptionFilter.vue b/src/pages/Supplier/Card/SupplierConsumptionFilter.vue index 3fc61b15e..401bde8fa 100644 --- a/src/pages/Supplier/Card/SupplierConsumptionFilter.vue +++ b/src/pages/Supplier/Card/SupplierConsumptionFilter.vue @@ -1,56 +1,21 @@ - (buyersOptions = data)" - auto-load - /> - (itemTypesOptions = data)" - auto-load - /> - (itemCategoriesOptions = data)" - auto-load - /> - + {{ t(`params.${tag.label}`) }}: @@ -82,7 +47,9 @@ const itemCategoriesOptions = ref([]); :label="t('params.buyerId')" v-model="params.buyerId" @update:model-value="searchFn()" - :options="buyersOptions" + url="TicketRequests/getItemTypeWorker" + :fields="['id', 'nickname']" + sort-by="nickname ASC" option-value="id" option-label="nickname" hide-selected @@ -98,7 +65,10 @@ const itemCategoriesOptions = ref([]); :label="t('params.typeId')" v-model="params.typeId" @update:model-value="searchFn()" - :options="itemTypesOptions" + url="ItemTypes" + :include="['category']" + :fields="['id', 'name', 'categoryFk']" + sort-by="name ASC" option-value="id" option-label="name" hide-selected @@ -125,7 +95,9 @@ const itemCategoriesOptions = ref([]); :label="t('params.categoryId')" v-model="params.categoryId" @update:model-value="searchFn()" - :options="itemCategoriesOptions" + url="ItemCategories" + :fields="['id', 'name']" + sort-by="name ASC" option-value="id" option-label="name" hide-selected diff --git a/src/pages/Supplier/Card/SupplierContacts.vue b/src/pages/Supplier/Card/SupplierContacts.vue index 35e8b98fc..3f2063784 100644 --- a/src/pages/Supplier/Card/SupplierContacts.vue +++ b/src/pages/Supplier/Card/SupplierContacts.vue @@ -84,9 +84,10 @@ const insertRow = () => { - { {{ t('Add contact') }} - + diff --git a/src/pages/Supplier/Card/SupplierDescriptor.vue b/src/pages/Supplier/Card/SupplierDescriptor.vue index 6e60a336c..5754031b3 100644 --- a/src/pages/Supplier/Card/SupplierDescriptor.vue +++ b/src/pages/Supplier/Card/SupplierDescriptor.vue @@ -109,7 +109,7 @@ const getEntryQueryParams = (supplier) => { :subtitle="data.subtitle" :filter="filter" @on-fetch="setData" - data-key="supplier" + data-key="supplierDescriptor" :summary="$props.summary" > diff --git a/src/pages/Supplier/Card/SupplierFiscalData.vue b/src/pages/Supplier/Card/SupplierFiscalData.vue index 65c34c4ed..553fc0f94 100644 --- a/src/pages/Supplier/Card/SupplierFiscalData.vue +++ b/src/pages/Supplier/Card/SupplierFiscalData.vue @@ -51,6 +51,23 @@ function handleLocation(data, location) { :url="`Suppliers/${route.params.id}`" :url-update="`Suppliers/${route.params.id}/updateFiscalData`" model="supplier" + :filter="{ + fields: ['id', 'name', 'city', 'postCode', 'countryFk', 'provinceFk'], + include: [ + { + relation: 'province', + scope: { + fields: ['id', 'name'], + }, + }, + { + relation: 'country', + scope: { + fields: ['id', 'name'], + }, + }, + ], + }" auto-load :clear-store-on-unmount="false" > @@ -130,7 +147,12 @@ function handleLocation(data, location) { handleLocation(data, location)" > diff --git a/src/pages/Supplier/SupplierList.vue b/src/pages/Supplier/SupplierList.vue index d8404632c..ad668f0c0 100644 --- a/src/pages/Supplier/SupplierList.vue +++ b/src/pages/Supplier/SupplierList.vue @@ -75,6 +75,19 @@ const columns = computed(() => [ }, visible: false, }, + { + align: 'left', + label: t('supplier.list.tableVisibleColumns.country'), + name: 'country', + columnFilter: { + component: 'select', + name: 'countryFk', + attrs: { + url: 'countries', + fields: ['id', 'name'], + }, + }, + }, ]); diff --git a/src/pages/Ticket/Card/BasicData/BasicDataTable.vue b/src/pages/Ticket/Card/BasicData/TicketBasicData.vue similarity index 60% rename from src/pages/Ticket/Card/BasicData/BasicDataTable.vue rename to src/pages/Ticket/Card/BasicData/TicketBasicData.vue index 7f2f100ad..ab96a6e75 100644 --- a/src/pages/Ticket/Card/BasicData/BasicDataTable.vue +++ b/src/pages/Ticket/Card/BasicData/TicketBasicData.vue @@ -4,7 +4,6 @@ import { useI18n } from 'vue-i18n'; import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue'; import FetchedTags from 'components/ui/FetchedTags.vue'; -import RightMenu from 'src/components/common/RightMenu.vue'; import FetchData from 'components/FetchData.vue'; import { useStateStore } from 'stores/useStateStore'; @@ -115,7 +114,7 @@ const totalNewPrice = computed(() => { const totalDifference = computed(() => { return rows.value.reduce((acc, item) => acc + item.component?.difference || 0, 0); }); -const showMovablecolumn = computed(() => (haveDifferences.value > 0 ? ['movable'] : [])); +const showMovableColumn = computed(() => (haveDifferences.value > 0 ? ['movable'] : [])); const haveDifferences = computed(() => _ticketData.value.sale?.haveDifferences); const ticketHaveNegatives = () => { let _haveNegatives = false; @@ -145,85 +144,83 @@ onUnmounted(() => (stateStore.rightDrawer = false)); @on-fetch="(data) => (ticketUpdateActions = data)" auto-load /> - - - + + + + {{ t('basicData.total') }} + + + + + {{ t('basicData.price') }}: + {{ toCurrency(totalPrice) }} + + + + + {{ t('basicData.newPrice') }}: {{ toCurrency(totalNewPrice) }} + + + + + {{ t('basicData.difference') }}: {{ toCurrency(totalDifference) }} + + + + + + + {{ t('basicData.chargeDifference') }} + + + - - - {{ t('basicData.total') }} - - - - - {{ t('basicData.price') }}: - {{ toCurrency(totalPrice) }} - - - - - {{ t('basicData.newPrice') }}: {{ toCurrency(totalNewPrice) }} - - - - - {{ t('basicData.difference') }}: {{ toCurrency(totalDifference) }} - - - - - - - {{ t('basicData.chargeDifference') }} - - - - - - - - - - - - {{ t('basicData.withoutNegativesInfo') }} - - - - - - + + + + + + + + + {{ t('basicData.withoutNegativesInfo') }} + + + + + (stateStore.rightDrawer = false)); flat > - - + + {{ row.itemFk }} - + {{ row.item.name }} {{ row.item.subName }} diff --git a/src/pages/Ticket/Card/BasicData/TicketBasicDataForm.vue b/src/pages/Ticket/Card/BasicData/TicketBasicDataForm.vue index 28c6fcf15..fdc75abda 100644 --- a/src/pages/Ticket/Card/BasicData/TicketBasicDataForm.vue +++ b/src/pages/Ticket/Card/BasicData/TicketBasicDataForm.vue @@ -12,6 +12,7 @@ import VnInputTime from 'components/common/VnInputTime.vue'; import axios from 'axios'; import useNotify from 'src/composables/useNotify.js'; +import { useValidator } from 'src/composables/useValidator'; import { toTimeFormat } from 'filters/date.js'; const $props = defineProps({ @@ -23,7 +24,7 @@ const $props = defineProps({ }); const emit = defineEmits(['updateForm']); - +const { validate } = useValidator(); const { notify } = useNotify(); const router = useRouter(); const { t } = useI18n(); @@ -51,18 +52,18 @@ const agencyByWarehouseFilter = computed(() => ({ }, })); -const zonesFilter = computed(() => ({ - fields: ['id', 'name'], - order: 'name ASC', - where: formData.value?.agencyModeFk - ? { - shipped: formData.value?.shipped, - addressFk: formData.value?.addressFk, - agencyModeFk: formData.value?.agencyModeFk, - warehouseFk: formData.value?.warehouseFk, - } - : {}, -})); +function zoneWhere() { + if (formData?.value?.agencyModeFk) { + return formData.value?.agencyModeFk + ? { + shipped: formData.value?.shipped, + addressFk: formData.value?.addressFk, + agencyModeFk: formData.value?.agencyModeFk, + warehouseFk: formData.value?.warehouseFk, + } + : {}; + } +} const getLanded = async (params) => { try { @@ -293,13 +294,6 @@ onMounted(() => onFormModelInit()); @on-fetch="(data) => (agenciesOptions = data)" auto-load /> - (zonesOptions = data)" - auto-load - /> onFormModelInit()); hide-selected map-options :required="true" + :rules="validate('basicData.client')" > @@ -333,6 +328,7 @@ onMounted(() => onFormModelInit()); hide-selected map-options :required="true" + :rules="validate('basicData.warehouse')" /> @@ -345,6 +341,7 @@ onMounted(() => onFormModelInit()); hide-selected map-options :required="true" + :rules="validate('basicData.address')" > @@ -392,6 +389,7 @@ onMounted(() => onFormModelInit()); :label="t('basicData.alias')" v-model="formData.nickname" :required="true" + :rules="validate('basicData.alias')" /> @@ -404,6 +402,7 @@ onMounted(() => onFormModelInit()); hide-selected map-options :required="true" + :rules="validate('basicData.company')" /> onFormModelInit()); hide-selected map-options @focus="agencyFetchRef.fetch()" + :rules="validate('basicData.agency')" /> @@ -444,16 +448,19 @@ onMounted(() => onFormModelInit()); :label="t('basicData.shipped')" v-model="formData.shipped" :required="true" + :rules="validate('basicData.shipped')" /> diff --git a/src/pages/Ticket/Card/BasicData/TicketBasicDataView.vue b/src/pages/Ticket/Card/BasicData/TicketBasicDataView.vue index af47761a2..92640f898 100644 --- a/src/pages/Ticket/Card/BasicData/TicketBasicDataView.vue +++ b/src/pages/Ticket/Card/BasicData/TicketBasicDataView.vue @@ -3,7 +3,7 @@ import { ref, onBeforeMount } from 'vue'; import { useI18n } from 'vue-i18n'; import { useRoute, useRouter } from 'vue-router'; -import BasicDataTable from './BasicDataTable.vue'; +import TicketBasicData from './TicketBasicData.vue'; import TicketBasicDataForm from './TicketBasicDataForm.vue'; import { useVnConfirm } from 'composables/useVnConfirm'; @@ -158,7 +158,10 @@ onBeforeMount(async () => await getTicketData()); color="primary" animated keep-alive - style="max-width: 800px; margin: auto" + style="margin: auto" + :style="{ + 'max-width': step > 1 ? 'none' : '800px', + }" > await getTicketData()); /> - (formData = $event)" diff --git a/src/pages/Ticket/Card/ExpeditionNewTicket.vue b/src/pages/Ticket/Card/ExpeditionNewTicket.vue index 55ca700bc..9183ae405 100644 --- a/src/pages/Ticket/Card/ExpeditionNewTicket.vue +++ b/src/pages/Ticket/Card/ExpeditionNewTicket.vue @@ -31,6 +31,7 @@ const router = useRouter(); const { notify } = useNotify(); const newTicketFormData = reactive({}); +const date = new Date(); const createTicket = async () => { try { @@ -64,7 +65,11 @@ const createTicket = async () => { > - + import { useI18n } from 'vue-i18n'; -import { useRoute } from 'vue-router'; -import { computed } from 'vue'; import VnCard from 'components/common/VnCard.vue'; import TicketDescriptor from './TicketDescriptor.vue'; import TicketFilter from '../TicketFilter.vue'; const { t } = useI18n(); -const route = useRoute(); - -const routeName = computed(() => route.name); -const customRouteRedirectName = computed(() => routeName.value); routeName.value); :descriptor="TicketDescriptor" search-data-key="TicketList" :searchbar-props="{ - customRouteRedirectName, + url: 'Tickets/filter', label: t('card.search'), info: t('card.searchInfo'), }" diff --git a/src/pages/Ticket/Card/TicketComponents.vue b/src/pages/Ticket/Card/TicketComponents.vue index 6131c92db..0bccdaacd 100644 --- a/src/pages/Ticket/Card/TicketComponents.vue +++ b/src/pages/Ticket/Card/TicketComponents.vue @@ -5,15 +5,16 @@ import { useRoute } from 'vue-router'; import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue'; import FetchedTags from 'components/ui/FetchedTags.vue'; -import RightMenu from 'src/components/common/RightMenu.vue'; import FetchData from 'components/FetchData.vue'; import ZoneDescriptorProxy from 'src/pages/Zone/Card/ZoneDescriptorProxy.vue'; +import VnImg from 'src/components/ui/VnImg.vue'; import { useStateStore } from 'stores/useStateStore'; import { dashIfEmpty } from 'src/filters'; import { useArrayData } from 'composables/useArrayData'; import { toCurrency } from 'filters/index'; import axios from 'axios'; +import VnTable from 'src/components/VnTable/VnTable.vue'; const route = useRoute(); const stateStore = useStateStore(); @@ -75,22 +76,39 @@ const columns = computed(() => [ name: 'item', align: 'left', }, + { + align: 'left', + label: t('lines.image'), + name: 'image', + columnField: { + component: VnImg, + attrs: (id) => { + return { + id, + width: '50px', + }; + }, + }, + columnFilter: false, + }, { label: t('ticketComponents.description'), name: 'description', align: 'left', + columnClass: 'expand', }, { label: t('ticketComponents.quantity'), name: 'quantity', field: 'quantity', align: 'left', - format: (val) => dashIfEmpty(val), + format: (row) => dashIfEmpty(row.quantity), }, { label: t('ticketComponents.serie'), name: 'serie', align: 'left', + format: (row) => dashIfEmpty(row.serie), }, { label: t('ticketComponents.components'), @@ -174,181 +192,166 @@ onUnmounted(() => (stateStore.rightDrawer = false)); @on-fetch="(data) => (components = data)" auto-load /> - - - + + + + {{ t('ticketComponents.total') }} + + + + {{ t('ticketComponents.baseToCommission') }}: + + {{ toCurrency(getBase) }} + + + {{ t('ticketComponents.totalWithoutVat') }}: + + {{ toCurrency(getTotal) }} + + + + + + {{ t('ticketComponents.components') }} + + + - - - {{ t('ticketComponents.total') }} - - - - {{ t('ticketComponents.baseToCommission') }}: - - {{ toCurrency(getBase) }} - - - {{ t('ticketComponents.totalWithoutVat') }}: - - {{ toCurrency(getTotal) }} - - - - - - {{ t('ticketComponents.components') }} - - - - - {{ component.name }}: - - {{ - toCurrency(component.value, 'EUR', 3) - }} - - - - - - {{ t('ticketComponents.zoneBreakdown') }} - - - - - {{ t('ticketComponents.price') }}: - - {{ toCurrency(ticketData?.zonePrice, 'EUR', 2) }} - - - - {{ t('ticketComponents.bonus') }}: - - {{ toCurrency(ticketData?.zoneBonus, 'EUR', 2) }} - - - - {{ t('ticketComponents.zone') }}: - - - {{ dashIfEmpty(ticketData?.zone?.name) }} - - - - - - {{ t('ticketComponents.volume') }}: - - {{ ticketVolume }} - - - - {{ t('ticketComponents.packages') }}: - - {{ dashIfEmpty(ticketData?.packages) }} - - - - - - {{ t('ticketComponents.theoricalCost') }} - - - - - {{ t('ticketComponents.totalPrice') }}: - - {{ toCurrency(theoricalCost, 'EUR', 2) }} - - - - - + {{ component.name }}: + + {{ + toCurrency(component.value, 'EUR', 3) + }} + + + + + + {{ t('ticketComponents.zoneBreakdown') }} + + + + + {{ t('ticketComponents.price') }}: + + {{ toCurrency(ticketData?.zonePrice, 'EUR', 2) }} + + + + {{ t('ticketComponents.bonus') }}: + + {{ toCurrency(ticketData?.zoneBonus, 'EUR', 2) }} + + + + {{ t('ticketComponents.zone') }}: + + + {{ dashIfEmpty(ticketData?.zone?.name) }} + + + + + + {{ t('ticketComponents.volume') }}: + + {{ ticketVolume }} + + + + {{ t('ticketComponents.packages') }}: + + {{ dashIfEmpty(ticketData?.packages) }} + + + + + + {{ t('ticketComponents.theoricalCost') }} + + + + + {{ t('ticketComponents.totalPrice') }}: + + {{ toCurrency(theoricalCost, 'EUR', 2) }} + + + + - - - - {{ row.itemFk }} - - - + + + {{ row.itemFk }} + + - - - - {{ row.item.name }} - {{ row.item.subName }} - - - + + + + - - - - - {{ saleComponent.component?.componentType?.name }} - - - + + + {{ row.item.name }} + {{ row.item.subName }} + + - - - - - {{ saleComponent.component?.name }} - - - + + + + {{ saleComponent.component?.componentType?.name }} + + - - - - + + + + {{ saleComponent.component?.name }} + + + + + + + {{ toCurrency(saleComponent.value, 'EUR', 3) }} + + + + + + + {{ toCurrency(saleComponent.value * row.quantity, 'EUR', 3) }} + + + - - - - - {{ toCurrency(saleComponent.value * row.quantity, 'EUR', 3) }} - - - - - + + + diff --git a/src/pages/Ticket/Card/TicketDescriptor.vue b/src/pages/Ticket/Card/TicketDescriptor.vue index f68c897db..70fd9ab1e 100644 --- a/src/pages/Ticket/Card/TicketDescriptor.vue +++ b/src/pages/Ticket/Card/TicketDescriptor.vue @@ -2,13 +2,13 @@ import { ref, computed } from 'vue'; import { useRoute } from 'vue-router'; import { useI18n } from 'vue-i18n'; -import { toDate } from 'src/filters'; import CustomerDescriptorProxy from 'pages/Customer/Card/CustomerDescriptorProxy.vue'; import CardDescriptor from 'components/ui/CardDescriptor.vue'; import TicketDescriptorMenu from './TicketDescriptorMenu.vue'; import VnLv from 'src/components/ui/VnLv.vue'; import useCardDescription from 'src/composables/useCardDescription'; import VnUserLink from 'src/components/ui/VnUserLink.vue'; +import { toDateTimeFormat } from 'src/filters/date'; const $props = defineProps({ id: { @@ -30,13 +30,24 @@ const filter = { { relation: 'address', scope: { - fields: ['id', 'name', 'mobile', 'phone'], + fields: ['id', 'name', 'mobile', 'phone', 'incotermsFk'], }, }, { relation: 'client', scope: { - fields: ['id', 'name', 'salesPersonFk', 'phone', 'mobile', 'email'], + fields: [ + 'id', + 'name', + 'salesPersonFk', + 'phone', + 'mobile', + 'email', + 'isActive', + 'isFreezed', + 'isTaxDataChecked', + 'hasElectronicInvoice', + ], include: [ { relation: 'user', @@ -87,6 +98,10 @@ const filter = { }; const data = ref(useCardDescription()); + +function ticketFilter(ticket) { + return JSON.stringify({ clientFk: ticket.clientFk }); +} @@ -128,7 +143,10 @@ const data = ref(useCardDescription()); /> - + - + + + {{ t('Client inactive') }} + + + {{ t('Client Frozen') }} + + + {{ t('Client has debt') }} + + + {{ t('Client not checked') }} + {{ t('ticket.card.customerCard') }} + + {{ t('ticket.card.ticketList') }} + + + {{ t('ticket.card.newOrder') }} + @@ -168,4 +239,8 @@ const data = ref(useCardDescription()); es: This ticket is deleted: Este ticket está eliminado Go to module index: Ir al índice del modulo + Client inactive: Cliente inactivo + Client not checked: Cliente no verificado + Client has debt: Cliente con deuda + Client Frozen: Cliente congelado diff --git a/src/pages/Ticket/Card/TicketDescriptorMenu.vue b/src/pages/Ticket/Card/TicketDescriptorMenu.vue index 4cf4e633f..12e03551b 100644 --- a/src/pages/Ticket/Card/TicketDescriptorMenu.vue +++ b/src/pages/Ticket/Card/TicketDescriptorMenu.vue @@ -1,6 +1,6 @@ + + + + + + {{ t('Transfer client') }} + + + + + + + + + + {{ `#${scope.opt.id} - ` }} + {{ scope.opt.name }} + + + + + + + + + + + + + {{ t('addTurn') }} + + + + + + + + + + + + + + + + - {{ t('Open Delivery Note...') }} + {{ t('Show Delivery Note...') }} - {{ t('With prices') }} + {{ t('as PDF') }} - {{ t('Without prices') }} + {{ t('as PDF without prices') }} - {{ t('As CSV') }} + {{ t('as CSV') }} @@ -220,21 +484,21 @@ function openConfirmDialog(callback) { v-ripple clickable > - {{ t('With prices') }} + {{ t('Send PDF') }} - {{ t('Without prices') }} + {{ t('Send PDF to tablet') }} - {{ t('As CSV') }} + {{ t('Send CSV') }} @@ -243,8 +507,26 @@ function openConfirmDialog(callback) { - {{ t('Open Proforma Invoice') }} + {{ t('Show Proforma') }} + + + + + {{ t('Change shipped hour') }} + + + + + + + + @@ -259,24 +541,72 @@ function openConfirmDialog(callback) { {{ t('Pending payment') }} - {{ t('Minimum amount') }} + {{ t('Minimum import') }} - {{ t('Order changes') }} + {{ t('Notify changes') }} + + + + + {{ t('Make invoice') }} + + + + + + {{ + hasPdf ? t('Regenerate PDF invoice') : t('Generate PDF invoice') + }} + {{ t('To clone ticket') }} + + + + + {{ t('Recalculate components') }} + + + + + + {{ t('Refund all...') }} + + + + + + + + {{ t('with warehouse') }} + + + + + {{ t('without warehouse') }} + + + + + @@ -307,29 +637,61 @@ function openConfirmDialog(callback) { + + en: + addTurn: Add turn invoiceIds: "Invoices have been generated with the following ids: {invoiceIds}" es: - Open Delivery Note...: Abrir albarán... + Show Delivery Note...: Ver albarán... Send Delivery Note...: Enviar albarán... - With prices: Con precios - Without prices: Sin precios - As CSV: Como CSV - Open Proforma Invoice: Abrir factura proforma + as PDF: como PDF + as PDF without prices: como PDF sin precios + as CSV: Como CSV + Send PDF: Enviar PDF + Send PDF to tablet: Enviar PDF a tablet + Send CSV: Enviar CSV + Show Proforma: Ver proforma Delete ticket: Eliminar ticket - Send SMS...: Enviar SMS + Send SMS...: Enviar SMS... Pending payment: Pago pendiente - Minimum amount: Importe mínimo - Order changes: Cambios del pedido + Minimum import: Importe mínimo + Notify changes: Notificar cambios Ticket deleted: Ticket eliminado You can undo this action within the first hour: Puedes deshacer esta acción dentro de la primera hora To clone ticket: Clonar ticket Ticket cloned: Ticked clonado It was not able to clone the ticket: No se pudo clonar el ticket + Generate PDF invoice: Generar PDF factura + Regenerate PDF invoice: Regenerar PDF factura + The invoice PDF document has been regenerated: El documento PDF de la factura ha sido regenerado + Transfer client: Transferir cliente + Client: Cliente + addTurn: Añadir a turno + What is the day of receipt of the ticket?: ¿Cuál es el día de preparación del pedido? + Current ticket deleted and added to shift: Ticket actual eliminado y añadido al turno + Refund all...: Abonar todo... + with warehouse: con almacén + without warehouse: sin almacén + Make invoice: Crear factura + Change shipped hour: Cambiar hora de envío + Shipped hour: Hora de envío + Recalculate components: Recalcular componentes + Are you sure you want to recalculate components?: ¿Seguro que quieres recalcular los componentes? + Data saved: Datos guardados + Are you sure you want to invoice this ticket?: ¿Seguro que quieres facturar este ticket? + You are going to invoice this ticket: Vas a facturar este ticket + Ticket invoiced: Ticket facturado Set weight: Establecer peso Weight set: Peso establecido This ticket may be invoiced, do you want to continue?: Es posible que se facture este ticket, desea continuar? invoiceIds: "Se han generado las facturas con los siguientes ids: {invoiceIds}" + This ticket will be removed from current route! Continue anyway?: ¡Se eliminará el ticket de la ruta actual! ¿Continuar de todas formas? + You are going to delete this ticket: Vas a eliminar este ticket diff --git a/src/pages/Ticket/Card/TicketExpedition.vue b/src/pages/Ticket/Card/TicketExpedition.vue index c4ab63b39..4becb3db3 100644 --- a/src/pages/Ticket/Card/TicketExpedition.vue +++ b/src/pages/Ticket/Card/TicketExpedition.vue @@ -1,39 +1,35 @@ @@ -73,13 +85,14 @@ watch( :label="t('ticketNotes.description')" v-model="row.description" class="col" + @keyup.enter="handleSave" /> {{ t('ticketNotes.removeNote') }} @@ -87,17 +100,18 @@ watch( - {{ t('ticketNotes.addNote') }} - + diff --git a/src/pages/Ticket/Card/TicketPackage.vue b/src/pages/Ticket/Card/TicketPackage.vue index a76fce2b6..c0418bcf6 100644 --- a/src/pages/Ticket/Card/TicketPackage.vue +++ b/src/pages/Ticket/Card/TicketPackage.vue @@ -10,6 +10,7 @@ import FetchData from 'components/FetchData.vue'; import VnInputDate from 'src/components/common/VnInputDate.vue'; import { useArrayData } from 'src/composables/useArrayData'; +import VnRow from 'src/components/ui/VnRow.vue'; const route = useRoute(); const { t } = useI18n(); @@ -114,17 +115,20 @@ watch( - - - {{ t('package.addPackage') }} - - + + + + {{ t('package.addPackage') }} + + + diff --git a/src/pages/Ticket/Card/TicketPurchaseRequest.vue b/src/pages/Ticket/Card/TicketPurchaseRequest.vue index 8d84e2b46..d0af9efd0 100644 --- a/src/pages/Ticket/Card/TicketPurchaseRequest.vue +++ b/src/pages/Ticket/Card/TicketPurchaseRequest.vue @@ -1,27 +1,35 @@ - - - - redirectToTicketSummary(row.ticketFk)" - > - - - - - - - - - {{ row.requester?.user?.nickname }} - - - - - - - - {{ row.atender?.user?.nickname }} - - - - - - - - - - - - - - - - - - {{ row.sale.itemFk }} - - - - - - - - - {{ t('globals.delete') }} - - - - - - - - - - - - (attendersOptions = data)" + /> + + + + + + + {{ row.requester?.user?.nickname }} + + + + + + {{ row.atender?.user?.nickname }} + + + + + + + + + + {{ row.price }} + + + + + + + {{ dashIfEmpty(row.sale?.itemFk) }} + + + + {{ t(getRequestState(row.isOk)) }} + + + + - - {{ t('purchaseRequest.newRequest') }} - - - + + + + + + es: New: Nueva diff --git a/src/pages/Ticket/Card/TicketSale.vue b/src/pages/Ticket/Card/TicketSale.vue index 2ea12bb05..d87f6c402 100644 --- a/src/pages/Ticket/Card/TicketSale.vue +++ b/src/pages/Ticket/Card/TicketSale.vue @@ -16,11 +16,12 @@ import TicketSaleMoreActions from './TicketSaleMoreActions.vue'; import TicketTransfer from './TicketTransfer.vue'; import { useStateStore } from 'stores/useStateStore'; -import { toCurrency, toPercentage, dashIfEmpty } from 'src/filters'; +import { toCurrency, toPercentage } from 'src/filters'; import { useArrayData } from 'composables/useArrayData'; import { useVnConfirm } from 'composables/useVnConfirm'; import useNotify from 'src/composables/useNotify.js'; import axios from 'axios'; +import VnTable from 'src/components/VnTable/VnTable.vue'; const route = useRoute(); const router = useRouter(); @@ -33,7 +34,8 @@ const stateBtnDropdownRef = ref(null); const arrayData = useArrayData('ticketData'); const { store } = arrayData; - +const selectedRows = ref([]); +const hasSelectedRows = computed(() => selectedRows.value.length > 0); const ticketConfig = ref(null); const isLocked = ref(false); const isTicketEditable = ref(false); @@ -47,6 +49,7 @@ const transfer = ref({ lastActiveTickets: [], sales: [], }); +const tableRef = ref([]); watch( () => route.params.id, @@ -55,86 +58,89 @@ watch( const columns = computed(() => [ { - label: '', + align: 'left', name: 'statusIcons', - align: 'left', }, { - label: '', - name: 'picture', - align: 'left', + align: 'center', + label: t('lines.image'), + name: 'image', + columnField: { + component: VnImg, + attrs: (id) => { + return { + id, + width: '50px', + }; + }, + }, + columnFilter: false, }, { + align: 'left', label: t('ticketSale.visible'), name: 'visible', - field: 'visible', - align: 'left', - sortable: true, + format: (row, dashIfEmpty) => dashIfEmpty(row.visible), }, { + align: 'left', label: t('ticketSale.available'), name: 'available', - field: 'available', - align: 'left', - sortable: true, + format: (row, dashIfEmpty) => dashIfEmpty(row.available), }, { + align: 'left', label: t('ticketSale.id'), name: 'itemFk', - field: 'itemFk', - align: 'left', - sortable: true, }, { + align: 'left', label: t('ticketSale.quantity'), name: 'quantity', - field: 'quantity', - align: 'left', - sortable: true, + format: (row) => toCurrency(row.quantity), }, { + align: 'left', label: t('ticketSale.item'), name: 'item', - field: 'item', - align: 'left', - sortable: true, + format: (row) => row?.item?.name, + columnClass: 'expand', }, { + align: 'left', label: t('ticketSale.price'), name: 'price', - field: 'price', - align: 'left', - sortable: true, - format: (val) => toCurrency(val), + format: (row) => toCurrency(row.price), }, { + align: 'left', label: t('ticketSale.discount'), name: 'discount', - field: 'discount', - align: 'left', - sortable: true, + format: (row) => toPercentage(row.discount), }, { + align: 'left', label: t('ticketSale.amount'), name: 'amount', - field: 'amount', - align: 'left', - sortable: true, - format: (val) => toCurrency(val), + format: (row) => parseInt(row.amount * row.quantity), }, { + align: 'left', label: t('ticketSale.packaging'), name: 'itemPackingTypeFk', - field: 'item', - align: 'left', - sortable: true, - format: (val) => dashIfEmpty(val?.itemPackingTypeFk), + format: (row, dashIfEmpty) => dashIfEmpty(row?.item?.itemPackingTypeFk), }, { - label: '', - name: 'history', - align: 'left', - columnFilter: null, + align: 'right', + name: 'tableActions', + actions: [ + { + title: t('ticketSale.history'), + icon: 'history', + isPrimary: true, + action: (row) => goToLog(row.id), + }, + ], }, ]); @@ -210,6 +216,7 @@ const addSale = async (sale) => { sale.item = newSale.item; notify('globals.dataSaved', 'positive'); + window.location.reload(); } catch (err) { console.error('Error adding sale', err); } @@ -259,7 +266,7 @@ const getMana = async () => { const selectedValidSales = computed(() => { if (!sales.value) return; - return selectedSales.value.filter((sale) => sale.id != undefined); + return [...selectedRows.value]; }); const onOpenEditPricePopover = async (sale) => { @@ -374,7 +381,7 @@ const changeTicketState = async (val) => { }; const removeSelectedSales = () => { - selectedSales.value.forEach((sale) => { + selectedRows.value.forEach((sale) => { const index = sales.value.indexOf(sale); sales.value.splice(index, 1); }); @@ -382,19 +389,29 @@ const removeSelectedSales = () => { const removeSales = async () => { try { - const params = { sales: selectedValidSales.value, ticketId: store.data.id }; + const params = { + sales: selectedRows.value.filter((sale) => sale.id), + ticketId: store.data.id, + }; + selectedRows.value + .filter((sale) => !sale.id) + .forEach((sale) => + tableRef.value.CrudModelRef.formData.splice(sale.$index, 1) + ); + + if (params.sales.length == 0) return; await axios.post('Sales/deleteSales', params); removeSelectedSales(); notify('globals.dataSaved', 'positive'); + window.location.reload(); } catch (err) { console.error('Error deleting sales', err); } }; -const insertRow = () => sales.value.push({ ...DEFAULT_EDIT }); - const setTransferParams = async () => { try { + selectedSales.value = selectedValidSales.value; const checkedSales = JSON.parse(JSON.stringify(selectedSales.value)); transfer.value = { lastActiveTickets: [], @@ -418,9 +435,70 @@ onMounted(async () => { stateStore.rightDrawer = true; getConfig(); getSales(); + getItems(); }); onUnmounted(() => (stateStore.rightDrawer = false)); + +const items = ref([]); +const newRow = ref({}); + +async function getItems() { + const { data } = await axios.get(`Items/withName`); + items.value = data; +} + +const updateItem = (row) => { + const selectedItem = items.value.find((item) => item.id === row.itemFk); + if (selectedItem) { + row.item = selectedItem; + row.itemFk = selectedItem.id; + row.price = selectedItem.price; + row.discount = 0; + row.quantity = 0; + row.amount = row.price * row.quantity; + } + endNewRow(selectedItem); +}; + +function handleOnDataSave({ CrudModelRef }) { + const { copy } = addRow(CrudModelRef.formData); + CrudModelRef.insert(copy); +} + +const addRow = (original = null) => { + let copy = null; + if (!original) { + copy = { isNew: true }; + } else { + copy = { + itemFk: original.itemFk, + item: original.item, + quantity: original.quantity, + price: original.price, + discount: original.discount, + amount: original.amount, + isNew: true, + }; + } + newRow.value = copy; + return { original, copy }; +}; + +const endNewRow = (row) => { + if (row.itemFk && row.quantity) { + row.isNew = false; + } +}; + +watch( + () => newRow.value.itemFk, + (newItemFk) => { + if (newItemFk) { + updateItem(newRow.value); + } + } +); @@ -471,7 +549,7 @@ onUnmounted(() => (stateStore.rightDrawer = false)); :ticket="store.data" :is-ticket-editable="isTicketEditable" :sales="selectedValidSales" - :disable="!selectedSales.length" + :disable="!hasSelectedRows" :mana="mana" :ticket-config="ticketConfig" @get-mana="getMana()" @@ -480,7 +558,7 @@ onUnmounted(() => (stateStore.rightDrawer = false)); (stateStore.rightDrawer = false)); {{ t('Transfer lines') }} @@ -507,252 +585,233 @@ onUnmounted(() => (stateStore.rightDrawer = false)); - + - + {{ t('ticketSale.subtotal') }}: {{ toCurrency(store.data?.totalWithoutVat) }} - + {{ t('ticketSale.tax') }}: {{ toCurrency(store.data?.totalWithVat - store.data?.totalWithoutVat) }} - + {{ t('ticketSale.total') }}: {{ toCurrency(store.data?.totalWithVat) }} - - - - - - - {{ t('ticketSale.claim') }}: - {{ row.claim?.claimFk }} - - - - + + + - {{ t('ticketSale.visible') }}: {{ row.visible || 0 }} + {{ t('ticketSale.claim') }}: + {{ row.claim?.claimFk }} - - - {{ t('ticketSale.reserved') }} - - - - - {{ t('ticketSale.noVisible') }} - - - - - {{ t('ticketSale.hasComponentLack') }} - - - - - - - - - - - - - - - {{ row.visible }} - - - - - - - {{ row.available }} - - - - - - - - {{ row.itemFk }} - - - - - - - - #{{ scope.opt?.id }} - {{ scope.opt?.name }} - - - - - - - - - - {{ row.quantity }} - - - - - - {{ row.concept }} - {{ row.item?.subName }} - - - - - - - - - - - - {{ toCurrency(row.price) }} - - - - - - {{ toCurrency(row.price) }} - - - - - - - {{ toPercentage(row.discount / 100) }} - - - - - - {{ toPercentage(row.discount / 100) }} - - - - - - - {{ t('ticketSale.history') }} - - - - - - + + + {{ t('ticketSale.visible') }}: {{ row.visible || 0 }} + + + + + {{ t('ticketSale.reserved') }} + + + - {{ t('Add item') }} + {{ t('ticketSale.noVisible') }} - + + + + {{ t('ticketSale.hasComponentLack') }} + + - + + + + + + + + {{ row.visible }} + + + + + {{ row.available }} + + + + + + + + + {{ scope.opt?.id }} - {{ scope.opt?.name }} + + + + + + {{ row?.itemFk }} + + + + + + {{ row?.item?.name }} + + {{ row?.item?.subName.toUpperCase() }} + + + + + + + + + + + {{ row.quantity }} + + + + + {{ toCurrency(row.price) }} + + + + + + {{ toCurrency(row.price) }} + + + + + {{ toPercentage(row.discount / 100) }} + + + + + + {{ toPercentage(row.discount / 100) }} + + + {{ toCurrency(row.quantity * row.price) }} + + - - + + {{ t('Add item to basket') }} + + es: New item: Nuevo artículo diff --git a/src/pages/Ticket/Card/TicketSaleTracking.vue b/src/pages/Ticket/Card/TicketSaleTracking.vue index 6978d92c8..e7830bf37 100644 --- a/src/pages/Ticket/Card/TicketSaleTracking.vue +++ b/src/pages/Ticket/Card/TicketSaleTracking.vue @@ -25,7 +25,7 @@ const saleTrackingFetchDataRef = ref(null); const sales = ref([]); const saleTrackings = ref([]); -const itemShelvignsSales = ref([]); +const itemShelvingsSales = ref([]); const saleTrackingUrl = computed(() => `SaleTrackings/${route.params.id}/filter`); const oldQuantity = ref(null); @@ -88,7 +88,7 @@ const logTableColumns = computed(() => [ label: t('ticketSaleTracking.original'), name: 'original', field: 'originalQuantity', - align: 'original', + align: 'left', sortable: true, }, { @@ -177,7 +177,7 @@ const getItemShelvingSales = async (sale) => { const { data } = await axios.get(`ItemShelvingSales/filter`, { params: { filter: JSON.stringify(filter) }, }); - itemShelvignsSales.value = data; + itemShelvingsSales.value = data; } catch (error) { console.error(error); } @@ -337,7 +337,7 @@ const qCheckBoxController = (sale, action) => { :no-data-label="t('globals.noResults')" > - + { - + - - {{ row.itemFk }} - - + + + {{ row.itemFk }} + + + @@ -416,8 +418,18 @@ const qCheckBoxController = (sale, action) => { + + + {{ row.quantity }} + + + + + {{ dashIfEmpty(row.parkingFk) }} + + - + { data-key="saleTrackingLog" :rows="saleTrackings" :columns="logTableColumns" - class="q-pa-sm" + class="q-pa-sm full-width" > - - {{ row.name }} - + + + {{ row.name }} + + @@ -469,12 +483,12 @@ const qCheckBoxController = (sale, action) => { > - + { - - {{ row.name }} - + + + {{ row.name }} + + - + { - + div { + max-width: 900px; + } +} diff --git a/src/pages/Ticket/Card/TicketService.vue b/src/pages/Ticket/Card/TicketService.vue index 63dd454ba..45a870f7f 100644 --- a/src/pages/Ticket/Card/TicketService.vue +++ b/src/pages/Ticket/Card/TicketService.vue @@ -25,7 +25,7 @@ const { notify } = useNotify(); const selected = ref([]); const defaultTaxClass = ref(null); - +const isSaving = ref(false); const crudModelFilter = computed(() => ({ where: { ticketFk: route.params.id }, })); @@ -50,7 +50,7 @@ const createRefund = async () => { if (!selected.value.length) return; const params = { - servicesIds: selected.value.map((s) => +s.ticketFk), + servicesIds: selected.value.map((s) => +s.id), withWarehouse: false, negative: true, }; @@ -104,7 +104,31 @@ const columns = computed(() => [ sortable: true, align: 'left', }, + { + label: '', + name: 'actions', + align: 'left', + columnFilter: null, + }, ]); + +async function deleteService(row) { + const serviceId = row.id; + if (!row.id) ticketServiceCrudRef.value.reset(); + else { + const { data } = await axios.delete(`TicketServices/${serviceId}`); + if (data) notify('Service deleted successfully', 'positive'); + ticketServiceCrudRef.value.reload(); + } +} + +async function handleSave() { + if (!isSaving.value) { + isSaving.value = true; + await ticketServiceCrudRef.value?.saveChanges(); + isSaving.value = false; + } +} @@ -123,6 +147,8 @@ const columns = computed(() => [ :data-required="crudModelRequiredData" auto-load v-model:selected="selected" + :order="['description ASC']" + :default-remove="false" > [ v-model.number="row.price" type="number" min="0" + @keyup.enter="handleSave" /> + + + + + {{ t('globals.delete') }} + + + + - + +ñ diff --git a/src/pages/Ticket/Card/TicketSummary.vue b/src/pages/Ticket/Card/TicketSummary.vue index d19c1be49..b6a60122c 100644 --- a/src/pages/Ticket/Card/TicketSummary.vue +++ b/src/pages/Ticket/Card/TicketSummary.vue @@ -1,4 +1,5 @@ (editableStates = data)" + :filter="{ fields: ['code', 'name', 'id', 'alertLevel'], order: 'name ASC' }" auto-load + @on-fetch="(data) => (editableStates = data)" /> - - - - - {{ item.name }} - - - - + - + - - {{ entity.ticketState?.state?.name }} - + + {{ entity.ticketState.state.name }} + @@ -148,14 +169,22 @@ async function changeState(value) { :label="t('ticket.summary.agency')" :value="entity.agencyMode?.name" /> - + + + + {{ entity?.zone?.name }} + + + + - + + + + {{ entity.routeFk }} + + + + @@ -184,9 +220,9 @@ async function changeState(value) { :value="dashIfEmpty(entity.weight)" /> - + @@ -245,6 +281,7 @@ async function changeState(value) { type="textarea" class="notes" readonly + autogrow /> @@ -262,13 +299,14 @@ async function changeState(value) { /> @@ -291,11 +329,10 @@ async function changeState(value) { - + - {{ t('ticket.summary.claim') }}: - {{ props.row.claim.claimFk }} + + {{ t('ticket.summary.claim') }}: + {{ props.row.claim.claimFk }} + - {{ t('ticket.summary.claim') }}: - {{ props.row.claimBeginning.claimFk }} + + {{ t('ticket.summary.claim') }}: + {{ props.row.claimBeginning.claimFk }} + - {{ t('ticket.summary.visible') }}: - {{ props.row.visible }} + + {{ t('ticket.summary.visible') }}: + {{ props.row.visible }} + {{ t('ticket.summary.reserved') }} @@ -354,8 +390,8 @@ async function changeState(value) { {{ t('ticket.summary.itemShortage') }} @@ -364,8 +400,8 @@ async function changeState(value) { {{ t('ticket.summary.hasComponentLack') }} @@ -382,8 +418,34 @@ async function changeState(value) { /> - {{ props.row.visible }} - {{ props.row.available }} + + + {{ props.row.visible }} + + + {{ props.row.visible }} + + + + + {{ props.row.available }} + + + {{ props.row.available }} + + {{ props.row.quantity }} @@ -413,14 +475,11 @@ async function changeState(value) { - - - + + + - + {{ t('ticket.summary.created') }} {{ t('ticket.summary.package') }} {{ t('ticket.summary.quantity') }} @@ -434,13 +493,15 @@ async function changeState(value) { + + - + - + {{ t('ticket.summary.quantity') }} {{ t('globals.description') }} {{ t('ticket.summary.price') }} @@ -461,12 +522,62 @@ async function changeState(value) { + + + + + + {{ t('ticket.summary.description') }} + {{ t('ticket.summary.created') }} + {{ t('ticket.summary.requester') }} + {{ t('ticket.summary.attender') }} + {{ t('ticket.summary.quantity') }} + {{ t('ticket.summary.price') }} + {{ t('ticket.summary.item') }} + {{ t('ticket.summary.ok') }} + + + + + {{ props.row.description }} + {{ toDate(props.row.created) }} + {{ props.row.requester?.user?.username }} + {{ props.row.atender?.user?.username }} + {{ props.row.quantity }} + {{ toCurrency(props.row.price) }} + + + {{ props.row.itemFk }} + + + + + + + {{ t('Accepted') }} + + + {{ t('Denied') }} + + + + + + + + + +en: + ItemPicker: Item Picker + Packager: Packager + Delivery: Delivery + SalesPerson: Sales Person + Administrative: Administrative + Weight: Weight + InvoiceOut: Invoice Out + DropOff: Drop Off + Sustitución: Sustitution +es: + ItemPicker: Items + Packager: Encajador + Delivery: Envío + SalesPerson: Comercial + Administrative: Administrativa + Weight: Peso + InvoiceOut: Facturas + DropOff: Despacho + Sustitución: Sustitución + Accepted: Aceptado + Denied: Denegado + diff --git a/src/pages/Ticket/Card/TicketTracking.vue b/src/pages/Ticket/Card/TicketTracking.vue index f7cbb14e9..00b517765 100644 --- a/src/pages/Ticket/Card/TicketTracking.vue +++ b/src/pages/Ticket/Card/TicketTracking.vue @@ -96,8 +96,8 @@ const openCreateModal = () => createTrackingDialogRef.value.show(); :no-data-label="t('globals.noResults')" > - - + + {{ row.user?.name }} diff --git a/src/pages/Ticket/Card/TicketTransfer.vue b/src/pages/Ticket/Card/TicketTransfer.vue index 9a22c764c..e1a011a84 100644 --- a/src/pages/Ticket/Card/TicketTransfer.vue +++ b/src/pages/Ticket/Card/TicketTransfer.vue @@ -1,12 +1,11 @@ + + + + + + + + + + + + + +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/TicketVolume.vue b/src/pages/Ticket/Card/TicketVolume.vue index 68d2a1f73..2cf7ffc42 100644 --- a/src/pages/Ticket/Card/TicketVolume.vue +++ b/src/pages/Ticket/Card/TicketVolume.vue @@ -5,17 +5,18 @@ import { useRoute } from 'vue-router'; import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue'; import FetchedTags from 'components/ui/FetchedTags.vue'; -import RightMenu from 'src/components/common/RightMenu.vue'; import FetchData from 'components/FetchData.vue'; import { useStateStore } from 'stores/useStateStore'; import { dashIfEmpty } from 'src/filters'; import axios from 'axios'; +import VnTable from 'src/components/VnTable/VnTable.vue'; const route = useRoute(); const stateStore = useStateStore(); const { t } = useI18n(); const salesRef = ref(null); +const tableRef = ref(); watch( () => route.params.id, @@ -34,37 +35,42 @@ const salesFilter = computed(() => ({ const sales = ref([]); const packingTypeVolume = ref([]); -const rows = computed(() => sales.value); const columns = computed(() => [ { + align: 'left', label: t('volume.item'), - name: 'item', - align: 'left', + name: 'itemFk', + chip: { + condition: () => true, + }, + isId: true, }, { + align: 'left', label: t('volume.description'), - name: 'description', - align: 'left', + name: 'concept', + columnClass: 'expand', + cardVisible: true, }, { + align: 'left', label: t('volume.packingType'), - name: 'quantity', - field: (row) => row.item.itemPackingTypeFk, - align: 'left', - format: (val) => dashIfEmpty(val), + name: 'itemPackingTypeFk', + cardVisible: true, + format: (row, dashIfEmpty) => dashIfEmpty(row.item.itemPackingTypeFk), }, { + align: 'left', label: t('volume.quantity'), name: 'quantity', - field: 'quantity', - align: 'left', + cardVisible: true, }, { - label: t('volume.volumeQuantity'), - name: 'quantity', - field: (row) => row.saleVolume?.volume, align: 'left', + label: t('volume.volumeQuantity'), + name: 'volume', + cardVisible: true, }, ]); @@ -87,9 +93,7 @@ const applyVolumes = async (salesData) => { } }; -onMounted(() => { - stateStore.rightDrawer = true; -}); +onMounted(() => (stateStore.rightDrawer = true)); onUnmounted(() => (stateStore.rightDrawer = false)); @@ -102,52 +106,55 @@ onUnmounted(() => (stateStore.rightDrawer = false)); @on-fetch="(data) => applyVolumes(data)" auto-load /> - - - - - - {{ t('volume.type') }}: - {{ dashIfEmpty(packingType.description) }} - - - - {{ t('volume.volume') }}: {{ packingType.volume }} - - - - - - - - - {{ row.itemFk }} - - - + + + + {{ t('volume.type') }}: + {{ dashIfEmpty(packingType.description) }} + + + + {{ t('volume.volume') }}: {{ packingType.volume }} + + + + + + + + {{ row.itemFk }} + + - - - - {{ row.item.name }} - {{ row.item.subName }} - - - + + {{ row.item.name }} + {{ row.item.subName }} + - + + {{ packingTypeVolume?.[rowIndex]?.volume }} + + diff --git a/src/pages/Ticket/TicketAdvance.vue b/src/pages/Ticket/TicketAdvance.vue index eb5b715ee..43b500dc0 100644 --- a/src/pages/Ticket/TicketAdvance.vue +++ b/src/pages/Ticket/TicketAdvance.vue @@ -133,6 +133,14 @@ const ticketColumns = computed(() => [ sortable: true, columnFilter: null, }, + { + label: t('advanceTickets.preparation'), + name: 'preparation', + field: 'preparation', + align: 'left', + sortable: true, + columnFilter: null, + }, { label: t('advanceTickets.liters'), name: 'liters', @@ -448,11 +456,12 @@ const handleCloseProgressDialog = () => { const handleCancelProgress = () => (cancelProgress.value = true); onMounted(async () => { - let today = Date.vnNew().toISOString(); + let today = Date.vnNew(); const tomorrow = new Date(today); tomorrow.setDate(tomorrow.getDate() + 1); userParams.dateFuture = tomorrow; userParams.dateToAdvance = today; + userParams.scopeDays = 1; userParams.warehouseFk = user.value.warehouseFk; const filter = { limit: 0 }; await arrayData.addFilter({ filter, userParams }); @@ -542,6 +551,7 @@ onMounted(async () => { style="max-width: 99%" > + {{ userParams.scopeDays }} { + diff --git a/src/pages/Ticket/TicketAdvanceFilter.vue b/src/pages/Ticket/TicketAdvanceFilter.vue index 209a1a307..b25ebdea6 100644 --- a/src/pages/Ticket/TicketAdvanceFilter.vue +++ b/src/pages/Ticket/TicketAdvanceFilter.vue @@ -9,6 +9,7 @@ import VnInputDate from 'src/components/common/VnInputDate.vue'; import axios from 'axios'; import { onMounted } from 'vue'; +import VnInputNumber from 'src/components/common/VnInputNumber.vue'; const { t } = useI18n(); const props = defineProps({ @@ -116,6 +117,15 @@ onMounted(async () => await getItemPackingTypes()); + + + + + +import { useRoute, useRouter } from 'vue-router'; +import { onBeforeMount, reactive, ref } from 'vue'; +import { useI18n } from 'vue-i18n'; +import { useDialogPluginComponent } from 'quasar'; + +import FormModelPopup from 'components/FormModelPopup.vue'; +import FetchData from 'components/FetchData.vue'; +import VnRow from 'components/ui/VnRow.vue'; +import VnSelect from 'components/common/VnSelect.vue'; +import VnInputDate from 'components/common/VnInputDate.vue'; + +import { useState } from 'composables/useState'; +import axios from 'axios'; + +const { t } = useI18n(); +const route = useRoute(); +const router = useRouter(); +const state = useState(); +const user = state.getUser(); +defineEmits(['confirm', ...useDialogPluginComponent.emits]); + +const initialFormState = reactive({ + clientId: Number(route.query?.clientFk) || null, + addressId: null, + agencyModeId: null, + warehouseId: user.value.warehouseFk, + landed: null, +}); +const clientOptions = ref([]); +const agenciesOptions = ref([]); +const addressesOptions = ref([]); +const warehousesOptions = ref([]); +const selectedClient = ref(null); + +onBeforeMount(async () => { + await onClientSelected(initialFormState); +}); + +const fetchClient = async (formData) => { + try { + const filter = { + include: { + relation: 'defaultAddress', + scope: { + fields: ['id', 'agencyModeFk'], + }, + }, + where: { id: formData.clientId }, + }; + const params = { filter: JSON.stringify(filter) }; + const { data } = await axios.get('Clients', { params }); + const [client] = data; + selectedClient.value = client; + } catch (err) { + console.error('Error fetching client'); + } +}; + +const fetchAddresses = async (formData) => { + try { + if (!formData.clientId) return; + + const filter = { + fields: ['nickname', 'street', 'city', 'id'], + where: { isActive: true }, + order: 'nickname ASC', + }; + const params = { filter: JSON.stringify(filter) }; + const { data } = await axios.get(`Clients/${formData.clientId}/addresses`, { + params, + }); + addressesOptions.value = data; + + const { defaultAddress } = selectedClient.value; + formData.addressId = defaultAddress.id; + } catch (err) { + console.error(`Error fetching addresses`, err); + return err.response; + } +}; + +const onClientSelected = async (formData) => { + await fetchClient(formData); + await fetchAddresses(formData); +}; + +const fetchAvailableAgencies = async (formData) => { + if (!formData.warehouseId || !formData.addressId || !formData.landed) return; + let params = { + warehouseFk: formData.warehouseId, + addressFk: formData.addressId, + landed: formData.landed, + }; + + const { data } = await axios.get('Agencies/getAgenciesWithWarehouse', { params }); + + agenciesOptions.value = data; + + const defaultAgency = agenciesOptions.value.find( + (agency) => + agency.agencyModeFk === selectedClient.value.defaultAddress.agencyModeFk + ); + + if (defaultAgency) formData.agencyModeId = defaultAgency.agencyModeFk; +}; + +const redirectToTicketList = (_, { id }) => { + router.push({ name: 'TicketSummary', params: { id } }); +}; + + + + (clientOptions = data)" + :filter="{ fields: ['id', 'name', 'defaultAddressFk'], order: 'id' }" + auto-load + /> + (warehousesOptions = data)" + order="name" + auto-load + /> + + + + + + onClientSelected(data)" + > + + + + + {{ scope.opt.name }} + + + {{ `#${scope.opt.id}` }} + + + + + + + + + + fetchAvailableAgencies(data)" + > + + + + + {{ scope.opt.nickname }} + + + {{ `${scope.opt.street}, ${scope.opt.city}` }} + + + + + + + + + + fetchAvailableAgencies(data)" + /> + + + + + fetchAvailableAgencies(data)" + /> + + + + + + + + + + diff --git a/src/pages/Ticket/TicketFilter.vue b/src/pages/Ticket/TicketFilter.vue index 3b9833ce2..8f71aad08 100644 --- a/src/pages/Ticket/TicketFilter.vue +++ b/src/pages/Ticket/TicketFilter.vue @@ -115,6 +115,15 @@ const warehouses = ref([]); /> + + + + + diff --git a/src/pages/Ticket/TicketFutureFilter.vue b/src/pages/Ticket/TicketFutureFilter.vue index bb597a525..6345f62b3 100644 --- a/src/pages/Ticket/TicketFutureFilter.vue +++ b/src/pages/Ticket/TicketFutureFilter.vue @@ -153,7 +153,7 @@ onMounted(async () => { :label="t('params.state')" v-model="params.state" :options="stateOptions" - option-value="code" + option-value="id" option-label="name" @update:model-value="searchFn()" dense @@ -169,7 +169,7 @@ onMounted(async () => { :label="t('params.futureState')" v-model="params.futureState" :options="stateOptions" - option-value="code" + option-value="id" option-label="name" @update:model-value="searchFn()" dense diff --git a/src/pages/Ticket/TicketList.vue b/src/pages/Ticket/TicketList.vue index cbd102317..ad97e75c1 100644 --- a/src/pages/Ticket/TicketList.vue +++ b/src/pages/Ticket/TicketList.vue @@ -1,9 +1,12 @@ + (companiesOptions = data)" + auto-load + /> + (accountingOptions = data)" + auto-load + /> - + + + + + + {{ t('No verified data') }} + + + + + {{ t('Purchase request') }} + + + + + {{ t('Not visible') }} + + + + + {{ t('Client frozen') }} + + + + {{ t('Risk') }}: {{ row.risk }} + + + + {{ t('Component lack') }} + + + + + {{ t('Rounding') }} + + + + + + + {{ row.salesPerson }} + + + + + + + {{ toDate(row.shippedDate) }} + + + + + + {{ row.nickname }} + + + + + + {{ row.addressNickname }} + + + + + + + {{ row.state }} + + + + {{ row.state }} + + + + + {{ dashIfEmpty(row.refFk) }} + + + + + + {{ dashIfEmpty(row.zoneName) }} + + + + + + {{ row.totalWithVat }} + + (stateStore.rightDrawer = true)); option-label="name" hide-selected @update:model-value="(client) => onClientSelected(data)" + :sort-by="'id ASC'" > @@ -323,12 +696,136 @@ onMounted(() => (stateStore.rightDrawer = true)); - - - {{ row.state }} - - + + + + {{ t('ticketList.createInvoice') }} + + + + + + {{ t('ticketList.accountPayment') }} + + + + + + {{ t('ticketList.addPayment') }} + + + + + + + + + + + + {{ t('ticketList.cash') }} + + + + + + + + + + + + + + + + + + + + + + + + + + + {{ t('ticketList.sendDocuware') }} + + @@ -337,4 +834,5 @@ es: You can search by ticket id or alias: Puedes buscar por id o alias del ticket Zone: Zona New ticket: Nuevo ticket + Component lack: Faltan componentes diff --git a/src/pages/Ticket/locale/en.yml b/src/pages/Ticket/locale/en.yml index 305228669..58367e3a2 100644 --- a/src/pages/Ticket/locale/en.yml +++ b/src/pages/Ticket/locale/en.yml @@ -39,6 +39,7 @@ ticketSale: agency: Agency address: Address advanceTickets: + preparation: Preparation origin: Origin destination: Destination originAgency: 'Origin agency: {agency}' @@ -66,6 +67,8 @@ advanceTickets: advanceWithoutNegativeTitle: Advance tickets (without negatives) advanceWithoutNegativeSubtitle: Advance {selectedTickets} tickets confirmation errorsList: Errors list + search: Search advance tickets + searchInfo: Search advance tickets by ID or client ID futureTickets: problems: Problems ticketId: ID @@ -104,7 +107,7 @@ expedition: name: Name packageType: Package type counter: Counter - externalId: externalId + externalId: external Id created: Created state: State historyAction: Status log @@ -117,6 +120,10 @@ expedition: removeExpeditionSubtitle: Are you sure you want to delete this expedition? worker: Worker move: Move + isScanned: Is scanned + yes: Yes + no: No + removeExpedition: Delete expedition basicData: next: Next back: Back @@ -232,7 +239,7 @@ package: removePackage: Remove package ticketList: id: Id - nickname: Nickname + nickname: Ticket nickname state: State shipped: Shipped zone: Zone @@ -241,3 +248,27 @@ ticketList: summary: Summary client: Customer createTicket: Create ticket + createInvoice: Create invoice + 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 + bank: Bank + cash: Cash + deliveredAmount: Delivered amount + amountToReturn: Amount to return + viewReceipt: View receipt + sendEmail: Send email + compensation: Compensation + creditCard: Credit card + transfers: Transfers + province: Province + warehouse: Warehouse + hour: Hour + closure: Closure + toLines: Go to lines + addressNickname: Address nickname + ref: Reference diff --git a/src/pages/Ticket/locale/es.yml b/src/pages/Ticket/locale/es.yml index 30c5550be..1acaf154b 100644 --- a/src/pages/Ticket/locale/es.yml +++ b/src/pages/Ticket/locale/es.yml @@ -86,6 +86,7 @@ weeklyTickets: search: Buscar por tickets programados searchInfo: Buscar tickets programados por el identificador o el identificador del cliente advanceTickets: + preparation: Preparación origin: Origen destination: Destinatario originAgency: 'Agencia origen: {agency}' @@ -113,6 +114,8 @@ advanceTickets: advanceWithoutNegativeTitle: Adelantar tickets (sin negativos) advanceWithoutNegativeSubtitle: '¿Desea adelantar {selectedTickets} tickets?' errorsList: Lista de errores + search: Buscar por tickets adelantados + searchInfo: Buscar tickets adelantados por el identificador o el identificador del cliente futureTickets: problems: Problemas ticketId: ID @@ -191,9 +194,9 @@ expedition: id: Expedición item: Artículo name: Nombre - packageType: Package type + packageType: Embalaje counter: Contador - externalId: externalId + externalId: ID externo created: Fecha creación state: Estado historyAction: Historial de estados @@ -206,6 +209,10 @@ expedition: removeExpeditionSubtitle: ¿Está seguro de eliminar esta expedición? worker: Trabajador move: Mover + isScanned: Escaneado + yes: Sí + no: No + removeExpedition: Eliminar expedición package: package: Embalaje quantity: Cantidad @@ -235,7 +242,7 @@ You can search by ticket id or alias: Puedes buscar por id o alias del ticket Select lines to see the options: Selecciona líneas para ver las opciones ticketList: id: Id - nickname: Alias + nickname: Alias ticket state: Estado shipped: F. Envío zone: Zona @@ -244,3 +251,27 @@ ticketList: summary: Resumen client: Cliente createTicket: Crear ticket + createInvoice: Crear factura + accountPayment: Pago a cuenta... + sendDocuware: Marcar como servido/s y enviar albarán/es a la tablet + addPayment: Añadir pago + date: Fecha + company: Empresa + amount: Importe + reference: Referencia + bank: Caja + cash: Efectivo + deliveredAmount: Cantidad entregada + amountToReturn: Cantidad a devolver + viewReceipt: Ver recibido + sendEmail: Enviar correo + compensation: Compensación + creditCard: Tarjeta de crédito + transfers: Transferencias + province: Provincia + warehouse: Almacén + hour: Hora + closure: Cierre + toLines: Ir a lineas + addressNickname: Alias consignatario + ref: Referencia diff --git a/src/pages/Travel/Card/TravelBasicData.vue b/src/pages/Travel/Card/TravelBasicData.vue index 8a369a0dd..a3620a6ba 100644 --- a/src/pages/Travel/Card/TravelBasicData.vue +++ b/src/pages/Travel/Card/TravelBasicData.vue @@ -70,6 +70,9 @@ const agenciesOptions = ref([]); hide-selected /> + + + `#/travel/${entityId.value}/${param}`; - + {{ value }} diff --git a/src/pages/Travel/Card/TravelThermographs.vue b/src/pages/Travel/Card/TravelThermographs.vue index 6d83581ee..38b9125b1 100644 --- a/src/pages/Travel/Card/TravelThermographs.vue +++ b/src/pages/Travel/Card/TravelThermographs.vue @@ -47,6 +47,18 @@ const TableColumns = computed(() => { name: 'temperatureFk', align: 'left', }, + { + label: t('globals.maxTemperature'), + field: 'maxTemperature', + name: 'maxTemperature', + align: 'left', + }, + { + label: t('globals.minTemperature'), + field: 'minTemperature', + name: 'minTemperature', + align: 'left', + }, { label: t('travel.thermographs.state'), field: 'result', @@ -92,11 +104,7 @@ const openRemoveDialog = async (id) => { }, }) .onOk(async () => { - try { - await removeThermograph(id); - } catch (err) { - console.error('Error removing thermograph'); - } + await removeThermograph(id); }); }; @@ -106,9 +114,7 @@ const redirectToThermographForm = (action, id) => { }; if (action === 'edit' && id) { - const params = {}; - params.thermographId = id; - routeDetails.params = params; + routeDetails.query = { travelThermographFk: id }; } router.push(routeDetails); }; @@ -213,4 +219,6 @@ es: Thermograph removed: Termógrafo eliminado Are you sure you want to remove the thermograph?: ¿Seguro que quieres quitar el termógrafo? No results: Sin resultados + Max Temperature: Temperatura máxima + Min Temperature: Temperatura mínima diff --git a/src/pages/Travel/Card/TravelThermographsForm.vue b/src/pages/Travel/Card/TravelThermographsForm.vue index 7f40873b1..42acf30b9 100644 --- a/src/pages/Travel/Card/TravelThermographsForm.vue +++ b/src/pages/Travel/Card/TravelThermographsForm.vue @@ -1,6 +1,6 @@ - (allowedContentTypes = data.join(', '))" auto-load /> - (thermographsOptions = data)" - :filter="thermographFilter" - auto-load - /> { :filter="{ order: 'name' }" auto-load /> + (temperaturesOptions = data)" + auto-load + url="Temperatures" + /> + (thermographsOptions = data)" + :filter="thermographFilter" + auto-load + /> { @@ -285,6 +259,26 @@ const onThermographCreated = async (data) => { option-label="name" /> + + + + + + { - -es: - Select files: Selecciona ficheros - Thermograph created: Termógrafo creado - New thermograph: Nuevo termógrafo + es: + Select files: Selecciona ficheros + Thermograph created: Termógrafo creado + New thermograph: Nuevo termógrafo diff --git a/src/pages/Travel/ExtraCommunityFilter.vue b/src/pages/Travel/ExtraCommunityFilter.vue index a8bbde75b..75b744168 100644 --- a/src/pages/Travel/ExtraCommunityFilter.vue +++ b/src/pages/Travel/ExtraCommunityFilter.vue @@ -112,6 +112,7 @@ warehouses(); -import { onMounted, ref } from 'vue'; +import { onMounted, ref, computed } from 'vue'; import { useI18n } from 'vue-i18n'; -import { useRouter } from 'vue-router'; -import { useRoute } from 'vue-router'; +import { useRouter, useRoute } from 'vue-router'; import { useStateStore } from 'stores/useStateStore'; import VnTable from 'components/VnTable/VnTable.vue'; import { useSummaryDialog } from 'src/composables/useSummaryDialog'; -import { computed } from 'vue'; import TravelSummary from './Card/TravelSummary.vue'; import VnSearchbar from 'components/ui/VnSearchbar.vue'; import { toDate } from 'src/filters'; import { getDateQBadgeColor } from 'src/composables/getDateQBadgeColor.js'; + const { viewSummary } = useSummaryDialog(); const router = useRouter(); const { t } = useI18n(); @@ -24,6 +23,11 @@ const $props = defineProps({ }, }); const entityId = computed(() => $props.id || route.params.id); + +onMounted(async () => { + stateStore.rightDrawer = true; +}); + const cloneTravel = (travelData) => { const stringifiedTravelData = JSON.stringify(travelData); redirectToCreateView(stringifiedTravelData); @@ -37,10 +41,6 @@ const redirectCreateEntryView = (travelData) => { router.push({ name: 'EntryCreate', query: { travelFk: travelData.id } }); }; -onMounted(async () => { - stateStore.rightDrawer = true; -}); - const columns = computed(() => [ { align: 'left', @@ -158,6 +158,15 @@ const columns = computed(() => [ cardVisible: true, create: true, }, + { + align: 'left', + name: 'daysOnward', + label: t('travel.travelList.tableVisibleColumns.daysOnward'), + visible: false, + columnFilter: { + inWhere: false, + }, + }, { align: 'right', label: '', @@ -204,12 +213,14 @@ const columns = computed(() => [ editorFk: entityId, }, }" + :user-params="{ daysOnward: 7 }" order="landed DESC" :columns="columns" auto-load redirect="travel" :is-editable="false" :use-model="true" + chip-locale="travel.travelList.tableVisibleColumns" > [ :class="{ 'is-active': row.isReceived }" /> + + handleScopeDays(evt.target.value)" + @remove="handleScopeDays()" + class="q-px-xs q-pr-lg" + filled + dense + /> + diff --git a/src/pages/Wagon/Type/WagonCreateTray.vue b/src/pages/Wagon/Type/WagonCreateTray.vue new file mode 100644 index 000000000..304fa83ac --- /dev/null +++ b/src/pages/Wagon/Type/WagonCreateTray.vue @@ -0,0 +1,116 @@ + + + + (wagonColors = data)" + auto-load + /> + + + + + + + + {{ scope.opt.name }} + + + + + + + + + + + + en: + Select a tray: Select a tray + colors: + white: White + red: Red + green: Green + blue: Blue + es: + Select a tray color: Seleccione un color + Add new tray: Añadir nueva bandeja + Height: Altura + The minimum height between trays is 50cm: La altura mínima entre bandejas es de 50cm + The maximum height of the wagon is 200cm: La altura máxima del vagón es de 200cm + A tray with the same height already exists, try with a different height: Ya existe una bandeja con la misma altura, prueba con una diferente + colors: + white: Blanco + red: Rojo + green: Verde + blue: Azul + diff --git a/src/pages/Wagon/Type/WagonTypeCreate.vue b/src/pages/Wagon/Type/WagonTypeCreate.vue deleted file mode 100644 index bc9c1a40c..000000000 --- a/src/pages/Wagon/Type/WagonTypeCreate.vue +++ /dev/null @@ -1,433 +0,0 @@ - - - - - - - - - - - - - {{ - t('wagon.warnings.minHeightBetweenTrays') + - wagonConfig.minHeightBetweenTrays + - ' cm' - }} - - {{ - t('wagon.warnings.maxWagonHeight') + - wagonConfig.maxWagonHeight + - ' cm' - }} - - - - - - - - - - - - - - - - - - - - - - - - - - {{ t('wagon.type.trayColor') }} - - - - - - - - - - - - - - - - - diff --git a/src/pages/Wagon/Type/WagonTypeEdit.vue b/src/pages/Wagon/Type/WagonTypeEdit.vue new file mode 100644 index 000000000..eb8205d72 --- /dev/null +++ b/src/pages/Wagon/Type/WagonTypeEdit.vue @@ -0,0 +1,293 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + en: + tray: Tray + wagonColor: Wagon color + Select a tray: Select a tray + es: + tray: Bandeja + wagonColor: Color de la bandeja + Select a tray: Seleccione una bandeja + Create new Wagon type: Crear nuevo tipo de vagón + Add new tray: Añadir nueva bandeja + Height: Altura + Tray added successfully: Bandeja añadida correctamente + Tray deleted successfully: Bandeja eliminada correctamente + diff --git a/src/pages/Wagon/Type/WagonTypeList.vue b/src/pages/Wagon/Type/WagonTypeList.vue index b7bbf8c5d..c0943c58e 100644 --- a/src/pages/Wagon/Type/WagonTypeList.vue +++ b/src/pages/Wagon/Type/WagonTypeList.vue @@ -1,80 +1,136 @@ - - - - + + + + + - - - + + + + - - - - - - + + + + + {{ t('globals.new') }} + + + +en: + nameNotEmpty: The name cannot be empty +es: + Create new Wagon type: Crear nuevo tipo de vagón + Name: Nombre + nameNotEmpty: El nombre no puede estar vacío + diff --git a/src/pages/Wagon/WagonList.vue b/src/pages/Wagon/WagonList.vue index c4824b861..02e3b6d16 100644 --- a/src/pages/Wagon/WagonList.vue +++ b/src/pages/Wagon/WagonList.vue @@ -1,19 +1,20 @@ @@ -88,10 +52,7 @@ const filter = { - + @@ -128,13 +89,9 @@ const filter = { - - - + + - arrayData.store?.data); - -const isHr = computed(() => useRole().hasAny(['hr'])); - -const canSend = computed(() => useAcl().hasAny('WorkerTimeControl', 'sendMail', 'WRITE')); - +const canSend = computed(() => + 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)); const columns = computed(() => { @@ -257,58 +260,32 @@ const fetchHours = async () => { } }; -const fetchWorkerTimeControlMails = async (filter) => { - try { - const { data } = await axios.get('WorkerTimeControlMails', { - params: { filter: JSON.stringify(filter) }, - }); - - return data; - } catch (err) { - console.error('Error fetching worker time control mails'); - } -}; - const fetchWeekData = async () => { + const where = { + year: selectedDate.value.getFullYear(), + week: selectedWeekNumber.value, + }; try { - const filter = { - where: { - workerFk: route.params.id, - year: selectedDate.value ? selectedDate.value?.getFullYear() : null, - week: selectedWeekNumber.value, - }, - }; + const mail = ( + await axiosNoError.get(`Workers/${route.params.id}/mail`, { + params: { filter: { where } }, + }) + ).data[0]; - const data = await fetchWorkerTimeControlMails(filter); - if (!data.length) { - state.value = null; - } else { - const [mail] = data; + if (!mail) state.value = null; + else { state.value = mail.state; reason.value = mail.reason; } - await canBeResend(); + canResend.value = !!( + await axiosNoError.get('WorkerTimeControlMails/count', { params: { where } }) + ).data.count; } catch (err) { console.error('Error fetching week data'); } }; -const canBeResend = async () => { - canResend.value = false; - - const filter = { - where: { - year: selectedDate.value.getFullYear(), - week: selectedWeekNumber.value, - }, - limit: 1, - }; - - const data = await fetchWorkerTimeControlMails(filter); - if (data.length) canResend.value = true; -}; - const setHours = (data) => { for (const weekDay of weekDays.value) { if (data) { @@ -449,7 +426,7 @@ onMounted(async () => { { @click="isSatisfied()" /> { { {{ secondsToHoursMinutes(day.dayData?.workedHours) }} - {{ t('Add time') }} - + diff --git a/src/pages/Worker/WorkerCreate.vue b/src/pages/Worker/WorkerCreate.vue index 297aa4182..b51209879 100644 --- a/src/pages/Worker/WorkerCreate.vue +++ b/src/pages/Worker/WorkerCreate.vue @@ -194,7 +194,6 @@ async function autofillBic(worker) { handleLocation(data, location)" :disable="formData.isFreelance" > diff --git a/src/pages/Worker/WorkerDepartmentTree.vue b/src/pages/Worker/WorkerDepartmentTree.vue index 392539c86..c73cb59b9 100644 --- a/src/pages/Worker/WorkerDepartmentTree.vue +++ b/src/pages/Worker/WorkerDepartmentTree.vue @@ -180,17 +180,18 @@ function handleEvent(type, event, node) { {{ t('Remove') }} - {{ t('Create') }} - + diff --git a/src/pages/Worker/WorkerList.vue b/src/pages/Worker/WorkerList.vue index b8ef3f9d8..4c9964c0b 100644 --- a/src/pages/Worker/WorkerList.vue +++ b/src/pages/Worker/WorkerList.vue @@ -264,7 +264,6 @@ async function autofillBic(worker) { handleLocation(data, location)" :disable="data.isFreelance" > diff --git a/src/pages/Zone/Card/ZoneBasicData.vue b/src/pages/Zone/Card/ZoneBasicData.vue index 512d07636..535f2393d 100644 --- a/src/pages/Zone/Card/ZoneBasicData.vue +++ b/src/pages/Zone/Card/ZoneBasicData.vue @@ -64,6 +64,15 @@ const agencyOptions = ref([]); type="number" min="0" /> + + @@ -128,4 +137,5 @@ es: Bonus: Bonificación Inflation: Inflación Volumetric: Volumétrico + Max length m³: Medida máxima tumbado diff --git a/src/pages/Zone/Delivery/ZoneDeliveryList.vue b/src/pages/Zone/Delivery/ZoneDeliveryList.vue index ca87dbd84..975cbdb67 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 89e53132e..5a7f0bb4c 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/customer.js b/src/router/modules/customer.js index 5b73ddc84..1b707f1a2 100644 --- a/src/router/modules/customer.js +++ b/src/router/modules/customer.js @@ -175,7 +175,7 @@ export default { path: 'edit', name: 'CustomerAddressEdit', meta: { - title: 'address-edit', + title: 'addressEdit', }, component: () => import( diff --git a/src/router/modules/entry.js b/src/router/modules/entry.js index 365615b87..4750a4301 100644 --- a/src/router/modules/entry.js +++ b/src/router/modules/entry.js @@ -12,7 +12,7 @@ export default { component: RouterView, redirect: { name: 'EntryMain' }, menus: { - main: ['EntryList', 'MyEntries', 'EntryLatestBuys'], + main: ['EntryList', 'MyEntries', 'EntryLatestBuys', 'EntryStockBought'], card: ['EntryBasicData', 'EntryBuys', 'EntryNotes', 'EntryDms', 'EntryLog'], }, children: [ @@ -58,6 +58,15 @@ export default { }, component: () => import('src/pages/Entry/EntryLatestBuys.vue'), }, + { + path: 'stock-Bought', + name: 'EntryStockBought', + meta: { + title: 'reserves', + icon: 'deployed_code_history', + }, + component: () => import('src/pages/Entry/EntryStockBought.vue'), + }, ], }, { diff --git a/src/router/modules/route.js b/src/router/modules/route.js index 3c5c860cf..9a7b16df3 100644 --- a/src/router/modules/route.js +++ b/src/router/modules/route.js @@ -11,7 +11,14 @@ export default { component: RouterView, redirect: { name: 'RouteMain' }, menus: { - main: ['RouteList', 'RouteAutonomous', 'RouteRoadmap', 'CmrList', 'AgencyList'], + main: [ + 'RouteList', + 'RouteExtendedList', + 'RouteAutonomous', + 'RouteRoadmap', + 'CmrList', + 'AgencyList', + ], card: ['RouteBasicData', 'RouteTickets', 'RouteLog'], }, children: [ @@ -19,9 +26,6 @@ export default { path: '/route', name: 'RouteMain', component: () => import('src/components/common/VnSectionMain.vue'), - props: { - leftDrawer: false, - }, redirect: { name: 'RouteList' }, children: [ { @@ -33,6 +37,15 @@ export default { }, component: () => import('src/pages/Route/RouteList.vue'), }, + { + path: 'extended-list', + name: 'RouteExtendedList', + meta: { + title: 'RouteExtendedList', + icon: 'format_list_bulleted', + }, + component: () => import('src/pages/Route/RouteExtendedList.vue'), + }, { path: 'create', name: 'RouteCreate', @@ -78,7 +91,7 @@ export default { name: 'AgencyList', meta: { title: 'agencyList', - icon: 'view_list', + icon: 'list', }, component: () => import('src/pages/Route/Agency/AgencyList.vue'), diff --git a/src/router/modules/ticket.js b/src/router/modules/ticket.js index dcc238f95..6e407b88b 100644 --- a/src/router/modules/ticket.js +++ b/src/router/modules/ticket.js @@ -198,7 +198,7 @@ export default { name: 'TicketPackage', meta: { title: 'packages', - icon: 'vn:bin', + icon: 'vn:bucket', }, component: () => import('src/pages/Ticket/Card/TicketPackage.vue'), }, diff --git a/src/router/modules/wagon.js b/src/router/modules/wagon.js index d3d14a888..e25e585eb 100644 --- a/src/router/modules/wagon.js +++ b/src/router/modules/wagon.js @@ -11,7 +11,7 @@ export default { component: RouterView, redirect: { name: 'WagonMain' }, menus: { - main: ['WagonList', 'WagonTypeList', 'WagonCounter'], + main: ['WagonList', 'WagonTypeList', 'WagonCounter', 'WagonTray'], card: [], }, children: [ @@ -81,7 +81,7 @@ export default { title: 'typeCreate', icon: 'create', }, - component: () => import('src/pages/Wagon/Type/WagonTypeCreate.vue'), + component: () => import('src/pages/Wagon/Type/WagonTypeList.vue'), }, { path: ':id/edit', @@ -90,7 +90,7 @@ export default { title: 'typeEdit', icon: 'edit', }, - component: () => import('src/pages/Wagon/Type/WagonTypeCreate.vue'), + component: () => import('src/pages/Wagon/Type/WagonTypeEdit.vue'), }, ], }, diff --git a/test/cypress/integration/claim/claimDevelopment.spec.js b/test/cypress/integration/claim/claimDevelopment.spec.js index 903f58d4b..81fc33ecd 100755 --- a/test/cypress/integration/claim/claimDevelopment.spec.js +++ b/test/cypress/integration/claim/claimDevelopment.spec.js @@ -8,6 +8,8 @@ describe('ClaimDevelopment', () => { cy.viewport(1920, 1080); cy.login('developer'); cy.visit(`/#/claim/${claimId}/development`); + cy.intercept('GET', /\/api\/Workers\/search/).as('workers'); + cy.intercept('GET', /\/api\/Workers\/search/).as('workers'); cy.waitForElement('tbody'); }); @@ -32,10 +34,19 @@ describe('ClaimDevelopment', () => { }); it('should add and remove new line', () => { + cy.wait(['@workers', '@workers']); cy.addCard(); - cy.get(thirdRow).should('exist'); - const rowData = [false, 'Novato', 'Roces', 'Compradores', 'employeeNick', 'Tour']; + cy.waitForElement(thirdRow); + + const rowData = [ + false, + 'Novato', + 'Roces', + 'Compradores', + 'administrativeNick', + 'Tour', + ]; cy.fillRow(thirdRow, rowData); cy.saveCard(); diff --git a/test/cypress/integration/entry/entryDms.spec.js b/test/cypress/integration/entry/entryDms.spec.js index ed4a3d79c..47dcdba9e 100644 --- a/test/cypress/integration/entry/entryDms.spec.js +++ b/test/cypress/integration/entry/entryDms.spec.js @@ -23,7 +23,7 @@ describe('EntryDms', () => { expect(value).to.have.length(newFileTd++); const newRowSelector = `tbody > :nth-child(${newFileTd})`; cy.waitForElement(newRowSelector); - cy.validateRow(newRowSelector, [u, u, u, u, 'ENTRADA ID 1']); + cy.validateRow(newRowSelector, [u, u, u, u, u, 'ENTRADA ID 1']); //Edit new dms const newDescription = 'entry id 1 modified'; @@ -38,7 +38,7 @@ describe('EntryDms', () => { cy.saveCard(); cy.reload(); - cy.validateRow(newRowSelector, [u, u, u, u, newDescription]); + cy.validateRow(newRowSelector, [u, u, u, u, u, newDescription]); }); }); }); diff --git a/test/cypress/integration/entry/stockBought.spec.js b/test/cypress/integration/entry/stockBought.spec.js new file mode 100644 index 000000000..66e06b79e --- /dev/null +++ b/test/cypress/integration/entry/stockBought.spec.js @@ -0,0 +1,39 @@ +describe('EntryStockBought', () => { + beforeEach(() => { + cy.viewport(1920, 1080); + cy.login('buyer'); + cy.visit(`/#/entry/stock-Bought`); + }); + it('Should edit the reserved space', () => { + cy.get('.q-field__native.q-placeholder').should('have.value', '01/01/2001'); + cy.get('input[name="reserve"]').type('10{enter}'); + cy.get('button[title="Save"]').click(); + cy.get('.q-notification__message').should('have.text', 'Data saved'); + }); + it('Should add a new reserved space for buyerBoss', () => { + cy.get('.q-page-sticky > div > .q-btn > .q-btn__content > .q-icon').click(); + 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('.q-notification__message').should('have.text', 'Data created'); + }); + it('Should check detail for the buyer', () => { + cy.get(':nth-child(1) > .sticky > .q-btn > .q-btn__content > .q-icon').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('.vn-row > div > :nth-child(2)').should('have.text', '60'); + }); +}); diff --git a/test/cypress/integration/ticket/ticketDescriptor.spec.js b/test/cypress/integration/ticket/ticketDescriptor.spec.js index 516b0f13d..8192b7c7c 100644 --- a/test/cypress/integration/ticket/ticketDescriptor.spec.js +++ b/test/cypress/integration/ticket/ticketDescriptor.spec.js @@ -5,7 +5,7 @@ describe('Ticket descriptor', () => { const warehouseValue = ':nth-child(1) > :nth-child(6) > .value > span'; const summaryHeader = '.summaryHeader > div'; const weight = 25; - const weightValue = ':nth-child(10) > .value > span'; + const weightValue = '.summaryBody.row :nth-child(1) > :nth-child(9) > .value > span'; beforeEach(() => { cy.login('developer'); cy.viewport(1920, 1080); diff --git a/test/cypress/integration/vnComponent/vnLocation.spec.js b/test/cypress/integration/vnComponent/vnLocation.spec.js index 30c1d6df2..1872d3591 100644 --- a/test/cypress/integration/vnComponent/vnLocation.spec.js +++ b/test/cypress/integration/vnComponent/vnLocation.spec.js @@ -18,7 +18,7 @@ describe('VnLocation', () => { cy.get(inputLocation).click(); cy.get(inputLocation).clear(); cy.get(inputLocation).type('al'); - cy.get(locationOptions).should('have.length.at.least', 3); + cy.get(locationOptions).should('have.length.at.least', 4); }); it('input filter location as "ecuador"', function () { cy.get(inputLocation).click(); @@ -33,11 +33,32 @@ describe('VnLocation', () => { cy.login('developer'); cy.visit('/#/supplier/567/fiscal-data', { timeout: 7000 }); cy.waitForElement('.q-form'); - cy.get(createLocationButton).click(); }); + it('Find by postalCode', () => { + const postCode = '46600'; + const postCodeLabel = '46600, Valencia(Province one), España'; + const firstOption = '[role="listbox"] .q-item:nth-child(1)'; + + cy.get(inputLocation).click(); + cy.get(inputLocation).clear(); + cy.get(inputLocation).type(postCode); + cy.get(locationOptions) + .get(':nth-child(1)') + .should('have.length.at.least', 2); + cy.get( + firstOption.concat(' > .q-item__section > .q-item__label--caption') + ).should('have.text', postCodeLabel); + cy.get(firstOption).click(); + cy.get('.q-btn-group > .q-btn--standard > .q-btn__content > .q-icon').click(); + cy.reload(); + cy.waitForElement('.q-form'); + cy.get(inputLocation).should('have.value', postCodeLabel); + }); + it('Create postCode', () => { const postCode = '1234475'; const province = 'Valencia'; + cy.get(createLocationButton).click(); cy.get('.q-card > h1').should('have.text', 'New postcode'); cy.get(dialogInputs).eq(0).clear(); cy.get(dialogInputs).eq(0).type(postCode); @@ -54,6 +75,7 @@ describe('VnLocation', () => { it('Create city', () => { const postCode = '9011'; const province = 'Saskatchew'; + cy.get(createLocationButton).click(); cy.get(dialogInputs).eq(0).type(postCode); // city create button cy.get( diff --git a/test/cypress/integration/wagon/wagonCreate.spec.js b/test/cypress/integration/wagon/wagonCreate.spec.js index 9aff3a819..cd248d1bb 100644 --- a/test/cypress/integration/wagon/wagonCreate.spec.js +++ b/test/cypress/integration/wagon/wagonCreate.spec.js @@ -11,7 +11,9 @@ describe('WagonCreate', () => { cy.get('input').eq(1).type('1234ABCD'); cy.get('input').eq(2).type('100'); cy.get('input').eq(3).click(); - cy.get('div[role="listbox"]').find('div.q-item').click(); + cy.get('.q-select > .q-field__inner > .q-field__control').type( + '{downarrow}{enter}' + ); // Save cy.get('button[type="submit"]').click(); @@ -19,12 +21,22 @@ describe('WagonCreate', () => { // Check data has been saved successfully cy.waitForElement('.q-card'); - cy.get('.title').should('have.text', '1234'); - cy.get('[title-label="Plate"] > .value > span').should('have.text', '1234ABCD'); - cy.get(':nth-child(2) > .value > span').should('have.text', '100'); - cy.get(':nth-child(3) > .value > span').should('have.text', 'Wagon Type #1'); + cy.get( + '[to="/null/1"] > .q-card > .no-padding > .q-py-none > .cursor-text' + ).should('have.text', '1234'); + cy.get( + '[to="/null/1"] > .q-card > .no-padding > .q-pr-lg > :nth-child(1) > .vn-label-value > .value > :nth-child(1) > .row > span' + ).should('have.text', '1234ABCD'); + cy.get( + '[to="/null/1"] > .q-card > .no-padding > .q-pr-lg > :nth-child(2) > .vn-label-value > .value > :nth-child(1) > .row > span' + ).should('have.text', '100'); + cy.get( + '[to="/null/1"] > .q-card > .no-padding > .q-pr-lg > :nth-child(3) > .vn-label-value > .value > :nth-child(1) > .row > span' + ).should('have.text', 'Wagon Type #1'); // Delete wagon type created - cy.get('.actions > .q-btn--standard').click(); + cy.get( + '[to="/null/2"] > .q-card > .column > [title="Remove"] > .q-btn__content > .q-icon' + ).click(); }); }); diff --git a/test/cypress/integration/wagonType/wagonTypeCreate.spec.js b/test/cypress/integration/wagonType/wagonTypeCreate.spec.js index 5e8b6b888..0ad98e597 100644 --- a/test/cypress/integration/wagonType/wagonTypeCreate.spec.js +++ b/test/cypress/integration/wagonType/wagonTypeCreate.spec.js @@ -6,52 +6,14 @@ describe('WagonTypeCreate', () => { cy.waitForElement('.q-page', 6000); }); - function chooseColor(color) { - cy.get('div.shelving-down').eq(1).click(); - cy.get('div.q-color-picker__cube').eq(color).click(); - cy.get('div.q-card__section').find('button').click(); - } - - function addTray(position) { - cy.get('div.action-button').last().find('button').click(); - cy.focused().type(position); - cy.focused().blur(); - } - - it('should create and delete a new wagon type', () => { + it('should create a new wagon type', () => { + cy.get('.q-page-sticky > div > .q-btn').click(); cy.get('input').first().type('Example for testing'); - cy.get('div.q-checkbox__bg').click(); - chooseColor(1); - - // Insert invalid position (not minimal height) - addTray(20); - cy.get('div[role="alert"]').should('exist'); - chooseColor(2); - addTray(150); - chooseColor(3); - addTray(100); - - // Insert invalid position (max height reached) - addTray(210); - cy.get('div[role="alert"]').should('exist'); - - // Save cy.get('button[type="submit"]').click(); - - // Check data has been saved successfully - cy.get(':nth-child(1) > :nth-child(1) > .justify-between > .flex > .title') - .contains('Example for testing') - .click(); - cy.get('input').first().should('have.value', 'Example for testing'); - cy.get('div.wagon-tray').should('have.length', 4); - cy.get('div.position').eq(0).find('input').should('have.value', '150'); - cy.get('div.position').eq(1).find('input').should('have.value', '100'); - cy.get('div.position').eq(2).find('input').should('have.value', '50'); - - // Delete wagon type created - cy.go('back'); + }); + it('delete a wagon type', () => { cy.get( - ':nth-child(2) > :nth-child(1) > .card-list-body > .actions > .q-btn--standard' + '[to="/null/2"] > .q-card > .column > [title="Remove"] > .q-btn__content > .q-icon' ).click(); }); }); diff --git a/test/cypress/integration/wagonType/wagonTypeEdit.spec.js b/test/cypress/integration/wagonType/wagonTypeEdit.spec.js new file mode 100644 index 000000000..36dd83411 --- /dev/null +++ b/test/cypress/integration/wagonType/wagonTypeEdit.spec.js @@ -0,0 +1,27 @@ +describe('WagonTypeEdit', () => { + const trayColorRow = + '.q-select > .q-field__inner > .q-field__control > .q-field__control-container'; + beforeEach(() => { + cy.viewport(1920, 1080); + cy.login('developer'); + cy.visit('/#/wagon/type/1/edit'); + }); + + it('should edit the name and the divisible field of the wagon type', () => { + cy.get('.q-card'); + cy.get('input').first().type(' changed'); + cy.get('div.q-checkbox__bg').first().click(); + cy.get('.q-btn--standard').click(); + }); + + it('should delete a tray', () => { + cy.get('.action-button > .q-btn > .q-btn__content > .q-icon').first().click(); + cy.reload(); + }); + + it('should create a tray', () => { + cy.get('.action-button > .q-btn > .q-btn__content > .q-icon').last().click(); + cy.get('input').last().type('150'); + cy.get(trayColorRow).type('{downArrow}{downArrow}{downArrow}{enter}'); + }); +}); diff --git a/test/cypress/support/commands.js b/test/cypress/support/commands.js index a9a405313..43788f59f 100755 --- a/test/cypress/support/commands.js +++ b/test/cypress/support/commands.js @@ -140,6 +140,7 @@ Cypress.Commands.add('removeCard', () => { }); Cypress.Commands.add('addCard', () => { cy.waitForElement('tbody'); + cy.waitForElement('.q-page-sticky > div > .q-btn'); cy.get('.q-page-sticky > div > .q-btn').click(); }); Cypress.Commands.add('clickConfirm', () => { diff --git a/test/vitest/__tests__/pages/Wagons/WagonTypeCreate.spec.js b/test/vitest/__tests__/pages/Wagons/WagonTypeCreate.spec.js deleted file mode 100644 index 60c199b73..000000000 --- a/test/vitest/__tests__/pages/Wagons/WagonTypeCreate.spec.js +++ /dev/null @@ -1,271 +0,0 @@ -import { axios, createWrapper } from 'app/test/vitest/helper'; -import WagonTypeCreate from 'pages/Wagon/Type/WagonTypeCreate.vue'; -import { afterEach, beforeAll, describe, expect, it, vi } from 'vitest'; - -describe('WagonTypeCreate', () => { - let vmCreate, vmEdit; - const entityId = 1; - - beforeAll(() => { - vmEdit = createWrapper(WagonTypeCreate, {propsData: { - id: entityId, - }}).vm; - vmCreate = createWrapper(WagonTypeCreate).vm; - vmEdit.wagonConfig = vmCreate.wagonConfig = {maxTrays: 2 ,minHeightBetweenTrays: 50, maxWagonHeight: 200 }; - vmEdit.wagonTypeColors = vmCreate.wagonTypeColors = [{id: 1, color:'white', rgb:'#000000'}]; - }); - - afterEach(() => { - vi.clearAllMocks(); - }); - - describe('addTray()', () => { - it('should throw message if there are uncomplete trays', async () => { - vi.spyOn(vmEdit.quasar, 'notify'); - vmEdit.wagon = [{ - id: 1, - position: null, - color: vmEdit.wagonTypeColors[0] - }]; - - await vmEdit.addTray(); - - expect(vmEdit.quasar.notify).toHaveBeenCalledWith( - expect.objectContaining({ - type: 'warning', - }) - ); - }); - - it('should create a new tray if the limit has not been reached', async () => { - vmEdit.wagon = [{ - id: 1, - position: 0, - color: vmEdit.wagonTypeColors[0] - }]; - - await vmEdit.addTray(); - expect(vmEdit.wagon.length).toEqual(2); - }); - - it('should throw message if there are uncomplete trays', async () => { - vi.spyOn(vmEdit.quasar, 'notify'); - vmEdit.wagon = [{ - id: 1, - position: 0, - color: vmEdit.wagonTypeColors[0] - },{ - id: 2, - position: 50, - color: vmEdit.wagonTypeColors[0] - }]; - - await vmEdit.addTray(); - - expect(vmEdit.quasar.notify).toHaveBeenCalledWith( - expect.objectContaining({ - type: 'warning', - }) - ); - }); - }); - - describe('deleteTray() reorderIds()', () => { - it('should delete a tray and reorder the ids', async () => { - const trayToDelete = { - id: 1, - position: 0, - color: vmEdit.wagonTypeColors[0] - }; - const trayMaintained = { - id: 2, - position: 50, - color: vmEdit.wagonTypeColors[0] - }; - vmEdit.wagon = [trayToDelete,trayMaintained]; - - await vmEdit.deleteTray(trayToDelete); - - expect(vmEdit.wagon.length).toEqual(1); - expect(vmEdit.wagon[0].id).toEqual(0); - expect(vmEdit.wagon[0].position).toEqual(50); - - }); - }); - - describe('onSubmit()', () => { - it('should make a patch to editWagonType if have id', async () => { - vi.spyOn(axios, 'patch').mockResolvedValue({ data: true }); - const wagon = { - id: entityId, - name: "Mock name", - divisible: true, - trays: [{ - id: 1, - position: 0, - color: vmEdit.wagonTypeColors[0] - }] - } - vmEdit.name = wagon.name; - vmEdit.divisible = wagon.divisible; - vmEdit.wagon = wagon.trays; - - await vmEdit.onSubmit(); - - expect(axios.patch).toHaveBeenCalledWith( - `WagonTypes/editWagonType`, wagon - ); - }); - - it('should make a patch to createtWagonType if not have id', async () => { - vi.spyOn(axios, 'patch').mockResolvedValue({ data: true }); - const wagon = { - name: "Mock name", - divisible: true, - trays: [{ - id: 1, - position: 0, - color: vmCreate.wagonTypeColors[0] - }] - } - vmCreate.name = wagon.name; - vmCreate.divisible = wagon.divisible; - vmCreate.wagon = wagon.trays; - - await vmCreate.onSubmit(); - - expect(axios.patch).toHaveBeenCalledWith( - `WagonTypes/createWagonType`, wagon - ); - }); - }); - - describe('onReset()', () => { - it('should reset if have id', async () => { - vmEdit.name = 'Changed name'; - vmEdit.divisible = false; - vmEdit.wagon = []; - vmEdit.originalData = { - name: 'Original name', - divisible: true, - trays: [{ - id: 1, - position: 0, - color: vmEdit.wagonTypeColors[0] - },{ - id: 2, - position: 50, - color: vmEdit.wagonTypeColors[0] - }] - }; - - vmEdit.onReset(); - - expect(vmEdit.name).toEqual(vmEdit.originalData.name); - expect(vmEdit.divisible).toEqual(vmEdit.originalData.divisible); - expect(vmEdit.wagon).toEqual(vmEdit.originalData.trays); - }); - - it('should reset if not have id', async () => { - vmCreate.name = 'Changed name'; - vmCreate.divisible = false; - vmCreate.wagon = []; - - vmCreate.onReset(); - - expect(vmCreate.name).toEqual(null); - expect(vmCreate.divisible).toEqual(false); - expect(vmCreate.wagon.length).toEqual(1); - }); - }); - - describe('onPositionBlur()', () => { - it('should set position null if position is negative', async () => { - const negativeTray = { - id: 1, - position: -1, - color: vmCreate.wagonTypeColors[0] - }; - - vmCreate.onPositionBlur(negativeTray); - - expect(negativeTray.position).toEqual(null); - }); - - it('should set position and reorder array', async () => { - const trays = [{ - id: 0, - position: 100, - color: vmCreate.wagonTypeColors[0] - },{ - id: 1, - position: 0, - color: vmCreate.wagonTypeColors[0] - }]; - const newTray = { - id: 2, - position: 50, - color: vmCreate.wagonTypeColors[0] - }; - trays.push(newTray); - vmCreate.wagon = trays; - - vmCreate.onPositionBlur(newTray); - - expect(vmCreate.wagon[0].position).toEqual(100); - expect(vmCreate.wagon[1].position).toEqual(50); - expect(vmCreate.wagon[2].position).toEqual(0); - }); - - it('should throw message if not have min height between trays and should set new adequate positions', async () => { - vi.spyOn(vmCreate.quasar, 'notify'); - const trays = [{ - id: 0, - position: 0, - color: vmCreate.wagonTypeColors[0] - }]; - const newTray = { - id: 1, - position: 20, - color: vmCreate.wagonTypeColors[0] - }; - trays.push(newTray); - vmCreate.wagon = trays; - - vmCreate.onPositionBlur(newTray); - - expect(vmCreate.wagon[0].position).toEqual(50); - expect(vmCreate.wagon[1].position).toEqual(0); - expect(vmCreate.quasar.notify).toHaveBeenCalledWith( - expect.objectContaining({ - type: 'warning', - }) - ); - }); - - it('should throw message if max height has been exceed', async () => { - vi.spyOn(vmCreate.quasar, 'notify'); - const trays = [{ - id: 0, - position: 0, - color: vmCreate.wagonTypeColors[0] - }]; - const newTray = { - id: 1, - position: 210, - color: vmCreate.wagonTypeColors[0] - }; - trays.push(newTray); - vmCreate.wagon = trays; - - vmCreate.onPositionBlur(newTray); - - expect(vmCreate.wagon.length).toEqual(1); - expect(vmCreate.quasar.notify).toHaveBeenCalledWith( - expect.objectContaining({ - type: 'warning', - }) - ); - }); - }); -});
{{ t('route.Select the starting date') }}
{{ t('Select the starting date') }}