diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a679cdfc..51dd2010c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,16 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [2414.01] - 2024-04-04 + +### Added + +- (Tickets) => Se añade la opción de clonar ticket. #6951 + +### Changed + +### Fixed + ## [2400.01] - 2024-01-04 ### Added diff --git a/README.md b/README.md index 86fe11ca7..e87a84d60 100644 --- a/README.md +++ b/README.md @@ -5,13 +5,13 @@ Lilium frontend ## Install the dependencies ```bash -bun install +pnpm install ``` ### Install quasar cli ```bash -sudo bun install -g @quasar/cli +sudo npm install -g @quasar/cli ``` ### Start the app in development mode (hot-code reloading, error reporting, etc.) @@ -23,13 +23,13 @@ quasar dev ### Run unit tests ```bash -bun run test:unit +pnpm run test:unit ``` ### Run e2e tests ```bash -npm run test:e2e +pnpm run test:e2e ``` ### Build the app for production diff --git a/package.json b/package.json index beae0b7b9..a35020b66 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "salix-front", - "version": "24.12.0", + "version": "24.14.0", "description": "Salix frontend", "productName": "Salix", "author": "Verdnatura", diff --git a/quasar.config.js b/quasar.config.js index 2d8289508..80ddc3759 100644 --- a/quasar.config.js +++ b/quasar.config.js @@ -29,7 +29,7 @@ module.exports = configure(function (/* ctx */) { // app boot file (/src/boot) // --> boot files are part of "main.js" // https://v2.quasar.dev/quasar-cli/boot-files - boot: ['i18n', 'axios', 'vnDate', 'validations'], + boot: ['i18n', 'axios', 'vnDate', 'validations', 'quasar'], // https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#css css: ['app.scss'], diff --git a/src/boot/axios.js b/src/boot/axios.js index c58cc2d08..e3e7289af 100644 --- a/src/boot/axios.js +++ b/src/boot/axios.js @@ -11,7 +11,7 @@ axios.defaults.baseURL = '/api/'; const onRequest = (config) => { const token = session.getToken(); - if (token.length && config.headers) { + if (token.length && !config.headers.Authorization) { config.headers.Authorization = token; } diff --git a/src/boot/qformMixin.js b/src/boot/qformMixin.js new file mode 100644 index 000000000..8c89c9202 --- /dev/null +++ b/src/boot/qformMixin.js @@ -0,0 +1,21 @@ +import { getCurrentInstance } from 'vue'; + +const filterAvailableInput = element => element.classList.contains('q-field__native') && !element.disabled +const filterAvailableText = element => element.__vueParentComponent.type.name === 'QInput' && element.__vueParentComponent?.attrs?.class !== 'vn-input-date'; + + +export default { + mounted: function () { + const vm = getCurrentInstance(); + if (vm.type.name === 'QForm') + if (!['searchbarForm','filterPanelForm'].includes(this.$el?.id)) { + // AUTOFOCUS + const elementsArray = Array.from(this.$el.elements); + const firstInputElement = elementsArray.filter(filterAvailableInput).find(filterAvailableText); + + if (firstInputElement) { + firstInputElement.focus(); + } + } + }, +}; diff --git a/src/boot/quasar.js b/src/boot/quasar.js new file mode 100644 index 000000000..a8d9b7ad9 --- /dev/null +++ b/src/boot/quasar.js @@ -0,0 +1,6 @@ +import { boot } from 'quasar/wrappers'; +import qFormMixin from './qformMixin'; + +export default boot(({ app }) => { + app.mixin(qFormMixin); +}); diff --git a/src/components/CreateManualInvoiceForm.vue b/src/components/CreateManualInvoiceForm.vue new file mode 100644 index 000000000..f03afbf35 --- /dev/null +++ b/src/components/CreateManualInvoiceForm.vue @@ -0,0 +1,174 @@ + + + + (invoiceOutSerialsOptions = data)" + auto-load + /> + (taxAreasOptions = data)" + auto-load + /> + (ticketsOptions = data)" + auto-load + /> + (clientsOptions = data)" + auto-load + /> + + + + + {{ t('Invoicing in progress...') }} + + + + + + + + #{{ scope.opt?.id }} + {{ + scope.opt?.nickname + }} + + + + + + {{ + t('Or') + }} + + + + + + + + + + + + + + + + + + + + + + + + + +es: + Create manual invoice: Crear factura manual + Ticket: Ticket + Client: Cliente + Max date: Fecha límite + Serial: Serie + Area: Area + Reference: Referencia + Or: O + Invoicing in progress...: Facturación en progreso... + diff --git a/src/components/FormModel.vue b/src/components/FormModel.vue index 56422e5f6..d727f4440 100644 --- a/src/components/FormModel.vue +++ b/src/components/FormModel.vue @@ -84,10 +84,6 @@ const $props = defineProps({ const emit = defineEmits(['onFetch', 'onDataSaved']); -defineExpose({ - save, -}); - const componentIsRendered = ref(false); onMounted(async () => { @@ -238,6 +234,11 @@ watch(formUrl, async () => { reset(); fetch(); }); + +defineExpose({ + save, + isLoading, +}); diff --git a/src/components/FormModelPopup.vue b/src/components/FormModelPopup.vue index cc22c77db..2d8886610 100644 --- a/src/components/FormModelPopup.vue +++ b/src/components/FormModelPopup.vue @@ -1,5 +1,5 @@ +import { ref } from 'vue'; +import { useI18n } from 'vue-i18n'; + +const emit = defineEmits(['onSubmit']); + +const $props = defineProps({ + title: { + type: String, + default: '', + }, + subtitle: { + type: String, + default: '', + }, + defaultSubmitButton: { + type: Boolean, + default: true, + }, + defaultCancelButton: { + type: Boolean, + default: true, + }, + customSubmitButtonLabel: { + type: String, + default: '', + }, +}); + +const { t } = useI18n(); + +const closeButton = ref(null); +const isLoading = ref(false); + +const onSubmit = () => { + emit('onSubmit'); + closeForm(); +}; + +const closeForm = () => { + if (closeButton.value) closeButton.value.click(); +}; + + + + + + + + + {{ title }} + {{ subtitle }} + + + + + + + + + + + diff --git a/src/components/LeftMenu.vue b/src/components/LeftMenu.vue index 1721adfec..278a67129 100644 --- a/src/components/LeftMenu.vue +++ b/src/components/LeftMenu.vue @@ -234,6 +234,6 @@ async function togglePinned(item, event) { max-width: 256px; } .header { - color: #999999; + color: var(--vn-label-color); } diff --git a/src/components/NavBar.vue b/src/components/NavBar.vue index 12366e174..c6722d875 100644 --- a/src/components/NavBar.vue +++ b/src/components/NavBar.vue @@ -10,12 +10,12 @@ import UserPanel from 'components/UserPanel.vue'; import VnBreadcrumbs from './common/VnBreadcrumbs.vue'; const { t } = useI18n(); -const session = useSession(); const stateStore = useStateStore(); const quasar = useQuasar(); const state = useState(); const user = state.getUser(); -const token = session.getToken(); +const { getTokenMultimedia } = useSession(); +const token = getTokenMultimedia(); const appName = 'Lilium'; onMounted(() => stateStore.setMounted()); @@ -106,7 +106,7 @@ const pinnedModulesRef = ref(); width: max-content; } .q-header { - background-color: var(--vn-dark); + background-color: var(--vn-section-color); } diff --git a/src/components/TransferInvoiceForm.vue b/src/components/TransferInvoiceForm.vue new file mode 100644 index 000000000..b7d8f3081 --- /dev/null +++ b/src/components/TransferInvoiceForm.vue @@ -0,0 +1,168 @@ + + + + (clientsOptions = data)" + :filter="{ fields: ['id', 'name'], order: 'id', limit: 30 }" + auto-load + /> + (rectificativeTypeOptions = data)" + auto-load + /> + (siiTypeInvoiceOutsOptions = data)" + auto-load + /> + (invoiceCorrectionTypesOptions = data)" + auto-load + /> + + + + + + + + + + #{{ scope.opt?.id }} - + {{ scope.opt?.name }} + + + + + + + + + + + + + + + + + + {{ scope.opt?.code }} - + {{ scope.opt?.description }} + + + + + + + + + + + + + + + +es: + Transfer invoice: Transferir factura + Transfer client: Transferir cliente + Client: Cliente + Rectificative type: Tipo rectificativa + Class: Clase + Type: Tipo + Transferred invoice: Factura transferida + diff --git a/src/components/UserPanel.vue b/src/components/UserPanel.vue index e0b6b86ed..5c143740e 100644 --- a/src/components/UserPanel.vue +++ b/src/components/UserPanel.vue @@ -7,12 +7,16 @@ import axios from 'axios'; import { useState } from 'src/composables/useState'; import { useSession } from 'src/composables/useSession'; import { localeEquivalence } from 'src/i18n/index'; +import VnSelectFilter from 'src/components/common/VnSelectFilter.vue'; +import VnRow from 'components/ui/VnRow.vue'; +import FetchData from 'components/FetchData.vue'; const state = useState(); const session = useSession(); const router = useRouter(); const { t, locale } = useI18n(); import { useClipboard } from 'src/composables/useClipboard'; +import { ref } from 'vue'; const { copyText } = useClipboard(); const userLocale = computed({ get() { @@ -44,7 +48,10 @@ const darkMode = computed({ }); const user = state.getUser(); -const token = session.getToken(); +const token = session.getTokenMultimedia(); +const warehousesData = ref(); +const companiesData = ref(); +const accountBankData = ref(); onMounted(async () => { updatePreferences(); @@ -87,10 +94,28 @@ function copyUserToken() { - + (warehousesData = data)" + auto-load + /> + (companiesData = data)" + auto-load + /> + (accountBankData = data)" + auto-load + /> + - - + + {{ t('components.userPanel.settings') }} - + @{{ user.name }} - + + + + + + + + + + + + + + diff --git a/src/components/common/VnLog.vue b/src/components/common/VnLog.vue index eae391cc4..5c70b900d 100644 --- a/src/components/common/VnLog.vue +++ b/src/components/common/VnLog.vue @@ -819,7 +819,7 @@ setLogTree(); diff --git a/src/components/ui/CardDescriptor.vue b/src/components/ui/CardDescriptor.vue index 01048c6de..85e0a7857 100644 --- a/src/components/ui/CardDescriptor.vue +++ b/src/components/ui/CardDescriptor.vue @@ -175,7 +175,7 @@ const emit = defineEmits(['onFetch']); diff --git a/src/components/ui/VnSubToolbar.vue b/src/components/ui/VnSubToolbar.vue index 1a6549856..018447057 100644 --- a/src/components/ui/VnSubToolbar.vue +++ b/src/components/ui/VnSubToolbar.vue @@ -14,7 +14,7 @@ onUnmounted(() => { - + diff --git a/src/composables/downloadFile.js b/src/composables/downloadFile.js index 877d2a254..b26dec731 100644 --- a/src/composables/downloadFile.js +++ b/src/composables/downloadFile.js @@ -1,8 +1,8 @@ import { useSession } from 'src/composables/useSession'; import { getUrl } from './getUrl'; -const session = useSession(); -const token = session.getToken(); +const {getTokenMultimedia} = useSession(); +const token = getTokenMultimedia(); export async function downloadFile(dmsId) { let appUrl = await getUrl('', 'lilium'); diff --git a/src/composables/useSession.js b/src/composables/useSession.js index 008337b02..45d439b46 100644 --- a/src/composables/useSession.js +++ b/src/composables/useSession.js @@ -1,30 +1,56 @@ import { useState } from './useState'; import { useRole } from './useRole'; import { useUserConfig } from './useUserConfig'; - +import axios from 'axios'; +import useNotify from './useNotify'; export function useSession() { + const { notify } = useNotify(); + function getToken() { const localToken = localStorage.getItem('token'); const sessionToken = sessionStorage.getItem('token'); return localToken || sessionToken || ''; } + function getTokenMultimedia() { + const localTokenMultimedia = localStorage.getItem('tokenMultimedia'); + const sessionTokenMultimedia = sessionStorage.getItem('tokenMultimedia'); + + return localTokenMultimedia || sessionTokenMultimedia || ''; + } function setToken(data) { if (data.keepLogin) { localStorage.setItem('token', data.token); + localStorage.setItem('tokenMultimedia', data.tokenMultimedia); } else { sessionStorage.setItem('token', data.token); + sessionStorage.setItem('tokenMultimedia', data.tokenMultimedia); } } - - function destroy() { - if (localStorage.getItem('token')) - localStorage.removeItem('token') - - if (sessionStorage.getItem('token')) - sessionStorage.removeItem('token'); + async function destroyToken(url, storage, key) { + if (storage.getItem(key)) { + try { + await axios.post(url, null, { + headers: { Authorization: storage.getItem(key) }, + }); + } catch (error) { + notify('errors.statusUnauthorized', 'negative'); + } finally { + storage.removeItem(key); + } + } + } + async function destroy() { + const tokens = { + tokenMultimedia: 'Accounts/logout', + token: 'VnUsers/logout', + }; + for (const [key, url] of Object.entries(tokens)) { + await destroyToken(url, localStorage, key); + await destroyToken(url, sessionStorage, key); + } const { setUser } = useState(); @@ -37,8 +63,8 @@ export function useSession() { }); } - async function login(token, keepLogin) { - setToken({ token, keepLogin }); + async function login(token, tokenMultimedia, keepLogin) { + setToken({ token, tokenMultimedia, keepLogin }); await useRole().fetch(); await useUserConfig().fetch(); @@ -53,6 +79,7 @@ export function useSession() { return { getToken, + getTokenMultimedia, setToken, destroy, login, diff --git a/src/composables/useVnConfirm.js b/src/composables/useVnConfirm.js new file mode 100644 index 000000000..76c3f4f28 --- /dev/null +++ b/src/composables/useVnConfirm.js @@ -0,0 +1,23 @@ +import VnConfirm from 'components/ui/VnConfirm.vue'; +import { useQuasar } from 'quasar'; + +export function useVnConfirm() { + const quasar = useQuasar(); + + const openConfirmationModal = (title, message, promise, successFn) => { + quasar + .dialog({ + component: VnConfirm, + componentProps: { + title: title, + message: message, + promise: promise, + }, + }) + .onOk(async () => { + if (successFn) successFn(); + }); + }; + + return { openConfirmationModal }; +} diff --git a/src/css/app.scss b/src/css/app.scss index 67406128b..3baa60c9b 100644 --- a/src/css/app.scss +++ b/src/css/app.scss @@ -2,29 +2,33 @@ @import './icons.scss'; body.body--light { - --fount-color: black; - --vn-sectionColor: #ffffff; - --vn-pageColor: #e0e0e0; - background-color: var(--vn-pageColor); + --font-color: black; + --vn-section-color: #e0e0e0; + --vn-page-color: #ffffff; + --vn-text-color: var(--font-color); + --vn-label-color: #5f5f5f; + --vn-accent-color: #e7e3e3; + + background-color: var(--vn-page-color); + .q-header .q-toolbar { - color: var(--fount-color); + color: var(--font-color); + } + .q-card, + .q-table, + .q-table__bottom, + .q-drawer { + background-color: var(--vn-section-color); } - --vn-text: var(--fount-color); - --vn-gray: var(--vn-sectionColor); - --vn-label: #5f5f5f; - --vn-dark: var(--vn-sectionColor); - --vn-light-gray: #e7e3e3; } body.body--dark { - --vn-pageColor: #222; - --vn-SectionColor: #3c3b3b; - background-color: var(--vn-pageColor); - --vn-text: white; - --vn-gray: var(--vn-SectionColor); - --vn-label: #a8a8a8; - --vn-dark: var(--vn-SectionColor); - --vn-light-gray: #424242; + --vn-section-color: #403c3c; + --vn-text-color: white; + --vn-label-color: #a8a8a8; + --vn-accent-color: #424242; + + background-color: #222; } a { @@ -39,6 +43,9 @@ a { .tx-color-link { color: $color-link !important; } +.tx-color-font { + color: $color-link !important; +} .header-link { color: $color-link !important; @@ -59,19 +66,19 @@ a { // Removes chrome autofill background input:-webkit-autofill, select:-webkit-autofill { - color: var(--vn-text); + color: var(--vn-text-color); font-family: $typography-font-family; - -webkit-text-fill-color: var(--vn-text); + -webkit-text-fill-color: var(--vn-text-color); -webkit-background-clip: text !important; background-clip: text !important; } -.bg-vn-dark { - background-color: var(--vn-dark); +.bg-vn-section-color { + background-color: var(--vn-section-color); } .color-vn-text { - color: var(--vn-text); + color: var(--vn-text-color); } .color-vn-white { @@ -79,8 +86,8 @@ select:-webkit-autofill { } .vn-card { - background-color: var(--vn-gray); - color: var(--vn-text); + background-color: var(--vn-section-color); + color: var(--vn-text-color); border-radius: 8px; } @@ -90,16 +97,20 @@ select:-webkit-autofill { } .bg-vn-primary-row { - background-color: var(--vn-dark); + background-color: var(--vn-section-color); } .bg-vn-secondary-row { - background-color: var(--vn-light-gray); + background-color: var(--vn-accent-color); +} + +.fill-icon { + font-variation-settings: 'FILL' 1; } .vn-table-separation-row { height: 16px !important; - background-color: var(--vn-gray) !important; + background-color: var(--vn-section-color) !important; } /* Estilo para el asterisco en campos requeridos */ @@ -107,6 +118,10 @@ select:-webkit-autofill { content: ' *'; } +.q-chip { + color: black; +} + input[type='number'] { -moz-appearance: textfield; } diff --git a/src/css/quasar.variables.scss b/src/css/quasar.variables.scss index b70e3e8d0..8423a9a35 100644 --- a/src/css/quasar.variables.scss +++ b/src/css/quasar.variables.scss @@ -14,10 +14,10 @@ // Tip: to add new colors https://quasar.dev/style/color-palette/#adding-your-own-colors $primary: #ec8916; $secondary: $primary; -$positive: #21ba45; -$negative: #c10015; -$info: #31ccec; -$warning: #f2c037; +$positive: #c8e484; +$negative: #fb5252; +$info: #84d0e2; +$warning: #f4b974; // Pendiente de cuadrar con la base de datos $success: $positive; $alert: $negative; diff --git a/src/i18n/en/index.js b/src/i18n/en/index.js index 94d9e239b..577af7015 100644 --- a/src/i18n/en/index.js +++ b/src/i18n/en/index.js @@ -593,6 +593,7 @@ export default { company: 'Company', dued: 'Due date', shortDued: 'Due date', + amount: 'Amount', }, card: { issued: 'Issued', @@ -626,7 +627,7 @@ export default { fillDates: 'Invoice date and the max date should be filled', invoiceDateLessThanMaxDate: 'Invoice date can not be less than max date', invoiceWithFutureDate: 'Exists an invoice with a future date', - noTicketsToInvoice: 'There are not clients to invoice', + noTicketsToInvoice: 'There are not tickets to invoice', criticalInvoiceError: 'Critical invoicing error, process stopped', }, table: { @@ -838,6 +839,7 @@ export default { workerCreate: 'New worker', department: 'Department', pda: 'PDA', + log: 'Log', }, list: { name: 'Name', @@ -956,7 +958,7 @@ export default { roadmap: 'Roadmap', summary: 'Summary', basicData: 'Basic Data', - stops: 'Stops' + stops: 'Stops', }, }, roadmap: { @@ -964,7 +966,7 @@ export default { roadmap: 'Roadmap', summary: 'Summary', basicData: 'Basic Data', - stops: 'Stops' + stops: 'Stops', }, }, route: { @@ -1204,6 +1206,11 @@ export default { copyToken: 'Token copied to clipboard', settings: 'Settings', logOut: 'Log Out', + localWarehouse: 'Local warehouse', + localBank: 'Local bank', + localCompany: 'Local company', + userWarehouse: 'User warehouse', + userCompany: 'User company', }, smartCard: { downloadFile: 'Download file', diff --git a/src/i18n/es/index.js b/src/i18n/es/index.js index de0110d0f..2784ce1cc 100644 --- a/src/i18n/es/index.js +++ b/src/i18n/es/index.js @@ -593,6 +593,7 @@ export default { company: 'Empresa', dued: 'Fecha vencimineto', shortDued: 'F. vencimiento', + amount: 'Importe', }, card: { issued: 'Fecha emisión', @@ -628,7 +629,7 @@ export default { invoiceDateLessThanMaxDate: 'La fecha de la factura no puede ser menor que la fecha máxima', invoiceWithFutureDate: 'Existe una factura con una fecha futura', - noTicketsToInvoice: 'No hay clientes para facturar', + noTicketsToInvoice: 'No existen tickets para facturar', criticalInvoiceError: 'Error crítico en la facturación, proceso detenido', }, table: { @@ -838,6 +839,7 @@ export default { workerCreate: 'Nuevo trabajador', department: 'Departamentos', pda: 'PDA', + log: 'Historial', }, list: { name: 'Nombre', @@ -956,7 +958,7 @@ export default { roadmap: 'Troncales', summary: 'Resumen', basicData: 'Datos básicos', - stops: 'Paradas' + stops: 'Paradas', }, }, roadmap: { @@ -964,7 +966,7 @@ export default { roadmap: 'Troncales', summary: 'Resumen', basicData: 'Datos básicos', - stops: 'Paradas' + stops: 'Paradas', }, }, route: { @@ -1204,6 +1206,11 @@ export default { copyToken: 'Token copiado al portapapeles', settings: 'Configuración', logOut: 'Cerrar sesión', + localWarehouse: 'Almacén local', + localBank: 'Banco local', + localCompany: 'Empresa local', + userWarehouse: 'Almacén del usuario', + userCompany: 'Empresa del usuario', }, smartCard: { downloadFile: 'Descargar archivo', diff --git a/src/layouts/MainLayout.vue b/src/layouts/MainLayout.vue index 021ee685a..88c5ee293 100644 --- a/src/layouts/MainLayout.vue +++ b/src/layouts/MainLayout.vue @@ -11,5 +11,3 @@ const quasar = useQuasar(); - - diff --git a/src/layouts/OutLayout.vue b/src/layouts/OutLayout.vue index f66fcff1f..0eb1329a4 100644 --- a/src/layouts/OutLayout.vue +++ b/src/layouts/OutLayout.vue @@ -40,7 +40,7 @@ const langs = ['en', 'es']; - + { - + {{ entity.claimState.description }} diff --git a/src/pages/Claim/Card/ClaimLines.vue b/src/pages/Claim/Card/ClaimLines.vue index 90dd31199..70c257c69 100644 --- a/src/pages/Claim/Card/ClaimLines.vue +++ b/src/pages/Claim/Card/ClaimLines.vue @@ -161,7 +161,7 @@ function showImportDialog() { {{ t('Amount') }} - + {{ toCurrency(amount) }} diff --git a/src/pages/Claim/Card/ClaimPhoto.vue b/src/pages/Claim/Card/ClaimPhoto.vue index 6ac116ce0..dd97b60df 100644 --- a/src/pages/Claim/Card/ClaimPhoto.vue +++ b/src/pages/Claim/Card/ClaimPhoto.vue @@ -11,8 +11,8 @@ import FetchData from 'components/FetchData.vue'; const router = useRouter(); const quasar = useQuasar(); const { t } = useI18n(); -const session = useSession(); -const token = session.getToken(); +const { getTokenMultimedia } = useSession(); +const token = getTokenMultimedia(); const claimId = computed(() => router.currentRoute.value.params.id); diff --git a/src/pages/Claim/Card/ClaimSummary.vue b/src/pages/Claim/Card/ClaimSummary.vue index e14351286..612e0d755 100644 --- a/src/pages/Claim/Card/ClaimSummary.vue +++ b/src/pages/Claim/Card/ClaimSummary.vue @@ -11,11 +11,12 @@ import VnLv from 'src/components/ui/VnLv.vue'; import ClaimNotes from 'src/pages/Claim/Card/ClaimNotes.vue'; import VnUserLink from 'src/components/ui/VnUserLink.vue'; import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue'; +import VnTitle from 'src/components/common/VnTitle.vue'; const route = useRoute(); const { t } = useI18n(); -const session = useSession(); -const token = session.getToken(); +const { getTokenMultimedia } = useSession(); +const token = getTokenMultimedia(); const $props = defineProps({ id: { @@ -180,10 +181,10 @@ function openDialog(dmsId) { - - {{ t('claim.pageTitles.basicData') }} - - + - - {{ t('claim.summary.notes') }} - - + - - {{ t('claim.summary.details') }} - - + @@ -280,11 +281,10 @@ function openDialog(dmsId) { - - {{ t('claim.summary.development') }} - - - + - - {{ t('claim.summary.photos') }} - - + - - {{ t('claim.summary.actions') }} - - + - + {{ row.stateDescription }} @@ -118,7 +122,6 @@ function navigate(event, id) { diff --git a/src/pages/Customer/Card/CustomerBasicData.vue b/src/pages/Customer/Card/CustomerBasicData.vue index 458d50082..d23b08f17 100644 --- a/src/pages/Customer/Card/CustomerBasicData.vue +++ b/src/pages/Customer/Card/CustomerBasicData.vue @@ -11,8 +11,8 @@ import VnInput from 'src/components/common/VnInput.vue'; const route = useRoute(); const { t } = useI18n(); -const session = useSession(); -const token = session.getToken(); +const { getTokenMultimedia } = useSession(); +const token = getTokenMultimedia(); const workers = ref([]); const workersCopy = ref([]); diff --git a/src/pages/Customer/Card/CustomerConsignees.vue b/src/pages/Customer/Card/CustomerConsignees.vue index ad666ff32..6713d53a3 100644 --- a/src/pages/Customer/Card/CustomerConsignees.vue +++ b/src/pages/Customer/Card/CustomerConsignees.vue @@ -150,14 +150,14 @@ const toCustomerConsigneeEdit = (consigneeId) => { diff --git a/src/pages/Customer/Card/CustomerGreuges.vue b/src/pages/Customer/Card/CustomerGreuges.vue index d92d7b4ee..158f418ba 100644 --- a/src/pages/Customer/Card/CustomerGreuges.vue +++ b/src/pages/Customer/Card/CustomerGreuges.vue @@ -180,13 +180,13 @@ const toCustomerGreugeCreate = () => { diff --git a/src/pages/Customer/Card/CustomerNotes.vue b/src/pages/Customer/Card/CustomerNotes.vue index 781c57e50..9c1a07ca3 100644 --- a/src/pages/Customer/Card/CustomerNotes.vue +++ b/src/pages/Customer/Card/CustomerNotes.vue @@ -85,12 +85,12 @@ const toCustomerNoteCreate = () => { diff --git a/src/pages/Customer/Card/CustomerRecoveries.vue b/src/pages/Customer/Card/CustomerRecoveries.vue index 7247145f2..886968290 100644 --- a/src/pages/Customer/Card/CustomerRecoveries.vue +++ b/src/pages/Customer/Card/CustomerRecoveries.vue @@ -137,13 +137,13 @@ const toCustomerRecoverieCreate = () => { diff --git a/src/pages/Customer/Card/CustomerSummary.vue b/src/pages/Customer/Card/CustomerSummary.vue index 184b990b6..504404f5a 100644 --- a/src/pages/Customer/Card/CustomerSummary.vue +++ b/src/pages/Customer/Card/CustomerSummary.vue @@ -7,6 +7,7 @@ import CardSummary from 'components/ui/CardSummary.vue'; import { getUrl } from 'src/composables/getUrl'; import VnLv from 'src/components/ui/VnLv.vue'; import VnLinkPhone from 'src/components/ui/VnLinkPhone.vue'; +import VnTitle from 'src/components/common/VnTitle.vue'; const route = useRoute(); const { t } = useI18n(); @@ -62,10 +63,10 @@ const creditWarning = computed(() => { - - {{ t('customer.summary.basicData') }} - - + @@ -96,13 +97,10 @@ const creditWarning = computed(() => { /> - - {{ t('customer.summary.fiscalAddress') }} - - + { - - {{ t('customer.summary.fiscalData') }} - - + { /> - - {{ t('customer.summary.billingData') }} - - + { /> - - {{ t('customer.summary.consignee') }} - - + { /> - - {{ t('customer.summary.webAccess') }} - - + { /> - - {{ t('customer.summary.businessData') }} - + { /> - - {{ t('customer.summary.financialData') }} - - + { diff --git a/src/pages/Customer/Defaulter/CustomerDefaulter.vue b/src/pages/Customer/Defaulter/CustomerDefaulter.vue index 1dfd331e2..c685615c6 100644 --- a/src/pages/Customer/Defaulter/CustomerDefaulter.vue +++ b/src/pages/Customer/Defaulter/CustomerDefaulter.vue @@ -207,7 +207,7 @@ const refreshData = () => { - + diff --git a/src/pages/Customer/Payments/CustomerPayments.vue b/src/pages/Customer/Payments/CustomerPayments.vue index eedaaf137..5a0404eef 100644 --- a/src/pages/Customer/Payments/CustomerPayments.vue +++ b/src/pages/Customer/Payments/CustomerPayments.vue @@ -196,7 +196,7 @@ function stateColor(row) { - + {{ row.isConfirmed ? t('Confirmed') @@ -227,6 +227,7 @@ function stateColor(row) { v-if="col.name == 'state'" > navigation.getPinnedModules()); :width="256" :breakpoint="1000" > - + @@ -67,6 +67,10 @@ const pinnedModules = computed(() => navigation.getPinnedModules()); + es: Travel data: Datos envío diff --git a/src/pages/Entry/EntryLatestBuys.vue b/src/pages/Entry/EntryLatestBuys.vue index 217a25870..876fe6a9e 100644 --- a/src/pages/Entry/EntryLatestBuys.vue +++ b/src/pages/Entry/EntryLatestBuys.vue @@ -20,8 +20,8 @@ import { dashIfEmpty } from 'src/filters'; import { useArrayData } from 'composables/useArrayData'; const router = useRouter(); -const session = useSession(); -const token = session.getToken(); +const { getTokenMultimedia } = useSession(); +const token = getTokenMultimedia(); const stateStore = useStateStore(); const { t } = useI18n(); @@ -636,7 +636,7 @@ onUnmounted(() => (stateStore.rightDrawer = false)); auto-load @on-fetch="(data) => (intrastatOptions = data)" /> - + { width: 60px; height: 60px; font-size: 1.4rem; - background-color: var(--vn-light-gray); + background-color: var(--vn-accent-color); &.active { background-color: $primary; diff --git a/src/pages/InvoiceIn/Card/InvoiceInSummary.vue b/src/pages/InvoiceIn/Card/InvoiceInSummary.vue index a0b18f1fb..9eb306a12 100644 --- a/src/pages/InvoiceIn/Card/InvoiceInSummary.vue +++ b/src/pages/InvoiceIn/Card/InvoiceInSummary.vue @@ -9,6 +9,7 @@ import CardSummary from 'components/ui/CardSummary.vue'; import VnLv from 'src/components/ui/VnLv.vue'; import SupplierDescriptorProxy from 'src/pages/Supplier/Card/SupplierDescriptorProxy.vue'; import InvoiceIntoBook from '../InvoiceInToBook.vue'; +import VnTitle from 'src/components/common/VnTitle.vue'; onMounted(async () => { salixUrl.value = await getUrl(''); @@ -233,10 +234,10 @@ function getLink(param) { - - {{ t('invoiceIn.pageTitles.basicData') }} - - + - - {{ t('invoiceIn.pageTitles.basicData') }} - - + - - {{ t('invoiceIn.pageTitles.basicData') }} - - + - {{ t('Totals') }} + - - - {{ t('invoiceIn.card.vat') }} - - + + - - - {{ t('invoiceIn.card.dueDay') }} - - + + - - - {{ t('invoiceIn.card.intrastat') }} - - + + - + +es: + Download as CSV: Descargar como CSV + diff --git a/src/pages/Item/Card/ItemDescriptor.vue b/src/pages/Item/Card/ItemDescriptor.vue index 8c986e627..981de0632 100644 --- a/src/pages/Item/Card/ItemDescriptor.vue +++ b/src/pages/Item/Card/ItemDescriptor.vue @@ -41,7 +41,7 @@ const quasar = useQuasar(); const route = useRoute(); const router = useRouter(); const { t } = useI18n(); -const { getToken } = useSession(); +const { getTokenMultimedia } = useSession(); const state = useState(); const user = state.getUser(); @@ -79,7 +79,7 @@ onMounted(async () => { }); const getItemAvatar = async () => { - const token = getToken(); + const token = getTokenMultimedia(); const timeStamp = `timestamp=${Date.now()}`; image.value = `/api/Images/catalog/200x200/${entityId.value}/download?access_token=${token}&${timeStamp}`; }; diff --git a/src/pages/Login/LoginMain.vue b/src/pages/Login/LoginMain.vue index 9c469e611..f920854c6 100644 --- a/src/pages/Login/LoginMain.vue +++ b/src/pages/Login/LoginMain.vue @@ -30,8 +30,15 @@ async function onSubmit() { const { data } = await axios.post('Accounts/login', params); if (!data) return; + const { + data: { multimediaToken }, + } = await axios.get('VnUsers/ShareToken', { + headers: { Authorization: data.token }, + }); - await session.login(data.token, keepLogin.value); + if (!multimediaToken) return; + + await session.login(data.token, multimediaToken.id, keepLogin.value); quasar.notify({ message: t('login.loginSuccess'), diff --git a/src/pages/Login/VerifyEmail.vue b/src/pages/Login/VerifyEmail.vue index 4c02e5869..1febd0eaa 100644 --- a/src/pages/Login/VerifyEmail.vue +++ b/src/pages/Login/VerifyEmail.vue @@ -57,10 +57,13 @@ onMounted(async () => { :href="button.url" > - + - + {{ t(button.text) }} diff --git a/src/pages/Order/Card/OrderCatalogFilter.vue b/src/pages/Order/Card/OrderCatalogFilter.vue index 760c48726..402df1173 100644 --- a/src/pages/Order/Card/OrderCatalogFilter.vue +++ b/src/pages/Order/Card/OrderCatalogFilter.vue @@ -420,7 +420,7 @@ const getCategoryClass = (category, params) => { .category-icon { border-radius: 50%; - background-color: var(--vn-light-gray); + background-color: var(--vn-accent-color); font-size: 2.6rem; padding: 8px; cursor: pointer; diff --git a/src/pages/Order/Card/OrderCatalogItem.vue b/src/pages/Order/Card/OrderCatalogItem.vue index ee73bcffb..0e1005493 100644 --- a/src/pages/Order/Card/OrderCatalogItem.vue +++ b/src/pages/Order/Card/OrderCatalogItem.vue @@ -11,8 +11,8 @@ import toCurrency from '../../../filters/toCurrency'; const DEFAULT_PRICE_KG = 0; -const session = useSession(); -const token = session.getToken(); +const { getTokenMultimedia } = useSession(); +const token = getTokenMultimedia(); const { t } = useI18n(); defineProps({ @@ -88,11 +88,11 @@ const dialog = ref(null); font-size: 11px; .label { - color: var(--vn-label); + color: var(--vn-label-color); } .value { - color: var(--vn-text); + color: var(--vn-text-color); } } } @@ -125,7 +125,7 @@ const dialog = ref(null); gap: 4px; .subName { - color: var(--vn-label); + color: var(--vn-label-color); text-transform: uppercase; } @@ -163,7 +163,7 @@ const dialog = ref(null); position: absolute; bottom: 12px; right: 12px; - background: linear-gradient($dark, $primary); + background: linear-gradient(var(--vn-section-color), $primary); border-radius: 50%; width: 40px; height: 40px; diff --git a/src/pages/Order/Card/OrderSummary.vue b/src/pages/Order/Card/OrderSummary.vue index f9704a480..cba4723e8 100644 --- a/src/pages/Order/Card/OrderSummary.vue +++ b/src/pages/Order/Card/OrderSummary.vue @@ -248,7 +248,7 @@ const detailsColumns = ref([ .subName { text-transform: uppercase; - color: var(--vn-label); + color: var(--vn-label-color); } } } diff --git a/src/pages/Order/OrderCatalog.vue b/src/pages/Order/OrderCatalog.vue index 21442d10d..1ed03c47d 100644 --- a/src/pages/Order/OrderCatalog.vue +++ b/src/pages/Order/OrderCatalog.vue @@ -104,7 +104,7 @@ function extractTags(items) { .no-result { font-size: 24px; font-weight: bold; - color: var(--vn-label); + color: var(--vn-label-color); text-align: center; } diff --git a/src/pages/Order/OrderLines.vue b/src/pages/Order/OrderLines.vue index a2ee42481..5a31598e1 100644 --- a/src/pages/Order/OrderLines.vue +++ b/src/pages/Order/OrderLines.vue @@ -17,9 +17,9 @@ import axios from 'axios'; const route = useRoute(); const { t } = useI18n(); -const session = useSession(); +const { getTokenMultimedia } = useSession(); const quasar = useQuasar(); -const token = session.getToken(); +const token = getTokenMultimedia(); const orderSummary = ref({ total: null, vat: null, @@ -213,7 +213,7 @@ async function confirmOrder() { gap: 2%; .label { - color: var(--vn-label); + color: var(--vn-label-color); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; @@ -246,13 +246,13 @@ async function confirmOrder() { } .subname { - color: var(--vn-label); + color: var(--vn-label-color); } .no-result { font-size: 24px; font-weight: bold; - color: var(--vn-label); + color: var(--vn-label-color); text-align: center; } diff --git a/src/pages/Order/OrderList.vue b/src/pages/Order/OrderList.vue index b7b233a64..203eaccd1 100644 --- a/src/pages/Order/OrderList.vue +++ b/src/pages/Order/OrderList.vue @@ -104,7 +104,7 @@ function navigate(id) { /> - + {{ toDate(row?.landed) }} diff --git a/src/pages/Order/OrderVolume.vue b/src/pages/Order/OrderVolume.vue index 5bb106edc..67f409b45 100644 --- a/src/pages/Order/OrderVolume.vue +++ b/src/pages/Order/OrderVolume.vue @@ -106,7 +106,7 @@ const loadVolumes = async (rows) => { gap: 2%; .label { - color: var(--vn-label); + color: var(--vn-label-color); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; @@ -132,7 +132,7 @@ const loadVolumes = async (rows) => { .no-result { font-size: 24px; font-weight: bold; - color: var(--vn-label); + color: var(--vn-label-color); text-align: center; } diff --git a/src/pages/Route/Cmr/CmrList.vue b/src/pages/Route/Cmr/CmrList.vue index eb1901ab8..7ddfdbe24 100644 --- a/src/pages/Route/Cmr/CmrList.vue +++ b/src/pages/Route/Cmr/CmrList.vue @@ -12,8 +12,8 @@ import CustomerDescriptorProxy from 'pages/Customer/Card/CustomerDescriptorProxy const stateStore = useStateStore(); const { t } = useI18n(); -const session = useSession(); -const token = session.getToken(); +const { getTokenMultimedia } = useSession(); +const token = getTokenMultimedia(); const selected = ref([]); const columns = computed(() => [ @@ -141,6 +141,7 @@ function downloadPdfs() { - + {{ t('Total') }} @@ -213,6 +213,16 @@ function navigateToRouteSummary(event, row) { {{ toCurrency(total) }} + + + {{ t('Create invoiceIn') }} + + - - - - {{ t('Create invoiceIn') }} - - - { let url; if (selectedRows.value.length <= 1) { - url = `api/Routes/${idString}/driver-route-pdf?access_token=${session.getToken()}`; + url = `api/Routes/${idString}/driver-route-pdf?access_token=${session.getTokenMultimedia()}`; } else { const params = new URLSearchParams({ - access_token: session.getToken(), + access_token: session.getTokenMultimedia(), id: idString, }); url = `api/Routes/downloadZip?${params.toString()}`; @@ -224,7 +224,7 @@ const openTicketsDialog = (id) => { (agencyList = data)" auto-load /> (vehicleList = data)" auto-load /> - + @@ -182,7 +182,7 @@ function navigateToRoadmapSummary(event, row) { - + {{ t('Preview') }} diff --git a/src/pages/Route/RouteTickets.vue b/src/pages/Route/RouteTickets.vue index 8410232c5..c1ca5507e 100644 --- a/src/pages/Route/RouteTickets.vue +++ b/src/pages/Route/RouteTickets.vue @@ -15,8 +15,8 @@ import VnConfirm from 'components/ui/VnConfirm.vue'; import FetchData from 'components/FetchData.vue'; import { openBuscaman } from 'src/utils/buscaman'; import SendSmsDialog from 'components/common/SendSmsDialog.vue'; -import RouteSearchbar from "pages/Route/Card/RouteSearchbar.vue"; -import {useStateStore} from "stores/useStateStore"; +import RouteSearchbar from 'pages/Route/Card/RouteSearchbar.vue'; +import { useStateStore } from 'stores/useStateStore'; const { t } = useI18n(); const quasar = useQuasar(); @@ -257,7 +257,7 @@ const openSmsDialog = async () => { - + {{ t('Sort routes') }} diff --git a/src/pages/Shelving/Card/ShelvingDescriptorMenu.vue b/src/pages/Shelving/Card/ShelvingDescriptorMenu.vue index 684a46807..16351fdd4 100644 --- a/src/pages/Shelving/Card/ShelvingDescriptorMenu.vue +++ b/src/pages/Shelving/Card/ShelvingDescriptorMenu.vue @@ -17,15 +17,14 @@ const quasar = useQuasar(); const { t } = useI18n(); function confirmRemove() { - quasar - .dialog({ - component: VnConfirm, - componentProps: { - title: t('Confirm deletion'), - message: t('Are you sure you want to delete this shelving?'), - promise: remove - }, - }) + quasar.dialog({ + component: VnConfirm, + componentProps: { + title: t('Confirm deletion'), + message: t('Are you sure you want to delete this shelving?'), + promise: remove, + }, + }); } async function remove() { diff --git a/src/pages/Supplier/Card/SupplierConsumption.vue b/src/pages/Supplier/Card/SupplierConsumption.vue index 59dd2281c..86c5e586b 100644 --- a/src/pages/Supplier/Card/SupplierConsumption.vue +++ b/src/pages/Supplier/Card/SupplierConsumption.vue @@ -195,7 +195,7 @@ onMounted(async () => { diff --git a/src/pages/Supplier/Card/SupplierContacts.vue b/src/pages/Supplier/Card/SupplierContacts.vue index 3abe5a9cc..a78c376a9 100644 --- a/src/pages/Supplier/Card/SupplierContacts.vue +++ b/src/pages/Supplier/Card/SupplierContacts.vue @@ -117,7 +117,7 @@ onMounted(() => { diff --git a/src/pages/Supplier/Card/SupplierSummary.vue b/src/pages/Supplier/Card/SupplierSummary.vue index edc2c742b..9d00ba8f7 100644 --- a/src/pages/Supplier/Card/SupplierSummary.vue +++ b/src/pages/Supplier/Card/SupplierSummary.vue @@ -8,6 +8,7 @@ import { getUrl } from 'src/composables/getUrl'; import { useRole } from 'src/composables/useRole'; import { dashIfEmpty } from 'src/filters'; import VnUserLink from 'src/components/ui/VnUserLink.vue'; +import VnTitle from 'src/components/common/VnTitle.vue'; onUpdated(() => summaryRef.value.fetch()); diff --git a/src/pages/Ticket/Card/TicketDescriptor.vue b/src/pages/Ticket/Card/TicketDescriptor.vue index f0ded019b..dfbcfc106 100644 --- a/src/pages/Ticket/Card/TicketDescriptor.vue +++ b/src/pages/Ticket/Card/TicketDescriptor.vue @@ -98,7 +98,10 @@ const setData = (entity) => - + {{ entity.ticketState.state.name }} diff --git a/src/pages/Ticket/Card/TicketDescriptorMenu.vue b/src/pages/Ticket/Card/TicketDescriptorMenu.vue index 95f6a94d9..c7784bc2a 100644 --- a/src/pages/Ticket/Card/TicketDescriptorMenu.vue +++ b/src/pages/Ticket/Card/TicketDescriptorMenu.vue @@ -3,7 +3,7 @@ import axios from 'axios'; import { ref } from 'vue'; import { useQuasar } from 'quasar'; import { useI18n } from 'vue-i18n'; -import { useRouter, useRoute } from 'vue-router'; +import { useRouter } from 'vue-router'; import { usePrintService } from 'composables/usePrintService'; import SendEmailDialog from 'components/common/SendEmailDialog.vue'; import VnConfirm from 'components/ui/VnConfirm.vue'; @@ -17,13 +17,49 @@ const props = defineProps({ }, }); -const router = useRouter(); -const route = useRoute(); -const quasar = useQuasar(); +const { push, currentRoute } = useRouter(); +const { dialog, notify } = useQuasar(); const { t } = useI18n(); const { openReport, sendEmail } = usePrintService(); const ticket = ref(props.ticket); +const ticketId = currentRoute.value.params.id; +const actions = { + clone: async () => { + const opts = { message: t('Ticket cloned'), type: 'positive' }; + let clonedTicketId; + + try { + const { data } = await axios.post(`Tickets/${ticketId}/clone`, { + shipped: ticket.value.shipped, + }); + clonedTicketId = data; + } catch (e) { + opts.message = t('It was not able to clone the ticket'); + opts.type = 'negative'; + } finally { + notify(opts); + + if (clonedTicketId) + push({ name: 'TicketSummary', params: { id: clonedTicketId } }); + } + }, + remove: async () => { + try { + await axios.post(`Tickets/${ticketId}/setDeleted`); + + notify({ message: t('Ticket deleted'), type: 'positive' }); + notify({ + message: t('You can undo this action within the first hour'), + icon: 'info', + }); + + push({ name: 'TicketList' }); + } catch (e) { + notify({ message: e.message, type: 'negative' }); + } + }, +}; function openDeliveryNote(type = 'deliveryNote', documentType = 'pdf') { const path = `Tickets/${ticket.value.id}/delivery-note-${documentType}`; @@ -35,7 +71,7 @@ function openDeliveryNote(type = 'deliveryNote', documentType = 'pdf') { function sendDeliveryNoteConfirmation(type = 'deliveryNote', documentType = 'pdf') { const customer = ticket.value.client; - quasar.dialog({ + dialog({ component: SendEmailDialog, componentProps: { data: { @@ -67,7 +103,7 @@ function showSmsDialog(template, customData) { const address = ticket.value.address; const client = ticket.value.client; const phone = - route.params.phone || + currentRoute.value.params.phone || address.mobile || address.phone || client.mobile || @@ -82,7 +118,7 @@ function showSmsDialog(template, customData) { Object.assign(data, customData); } - quasar.dialog({ + dialog({ component: VnSmsDialog, componentProps: { phone: phone, @@ -95,42 +131,26 @@ function showSmsDialog(template, customData) { } async function showSmsDialogWithChanges() { - const query = `TicketLogs/${route.params.id}/getChanges`; + const query = `TicketLogs/${ticketId}/getChanges`; const response = await axios.get(query); showSmsDialog('orderChanges', { changes: response.data }); } async function sendSms(body) { - await axios.post(`Tickets/${route.params.id}/sendSms`, body); - quasar.notify({ + await axios.post(`Tickets/${ticketId}/sendSms`, body); + notify({ message: 'Notification sent', type: 'positive', }); } -function confirmDelete() { - quasar - .dialog({ - component: VnConfirm, - componentProps: { - promise: remove, - }, - }) - .onOk(async () => await router.push({ name: 'TicketList' })); -} - -async function remove() { - const id = route.params.id; - await axios.post(`Tickets/${id}/setDeleted`); - - quasar.notify({ - message: t('Ticket deleted'), - type: 'positive', - }); - quasar.notify({ - message: t('You can undo this action within the first hour'), - icon: 'info', +function openConfirmDialog(callback) { + dialog({ + component: VnConfirm, + componentProps: { + promise: actions[callback], + }, }); } @@ -227,9 +247,15 @@ async function remove() { + + + + + {{ t('To clone ticket') }} + - + @@ -253,4 +279,7 @@ es: Order changes: Cambios del pedido 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 diff --git a/src/pages/Ticket/Card/TicketSummary.vue b/src/pages/Ticket/Card/TicketSummary.vue index fbca21086..85d98f353 100644 --- a/src/pages/Ticket/Card/TicketSummary.vue +++ b/src/pages/Ticket/Card/TicketSummary.vue @@ -12,6 +12,7 @@ import VnLv from 'src/components/ui/VnLv.vue'; import VnLinkPhone from 'src/components/ui/VnLinkPhone.vue'; import { getUrl } from 'src/composables/getUrl'; import VnUserLink from 'src/components/ui/VnUserLink.vue'; +import VnTitle from 'src/components/common/VnTitle.vue'; onUpdated(() => summaryRef.value.fetch()); @@ -74,7 +75,7 @@ async function changeState(value) { code: value, }; - await axios.post(`TicketTrackings/changeState`, formData); + await axios.post(`Tickets/state`, formData); router.go(route.fullPath); } @@ -102,8 +103,8 @@ async function changeState(value) { @@ -147,10 +148,10 @@ async function changeState(value) { - - {{ t('globals.summary.basicData') }} - - + @@ -193,10 +194,10 @@ async function changeState(value) { /> - - {{ t('globals.summary.basicData') }} - - + - - {{ t('ticket.pageTitles.notes') }} - - + - - {{ t('ticket.summary.saleLines') }} - - + @@ -396,10 +397,7 @@ async function changeState(value) { class="vn-max" v-if="ticket.packagings.length > 0 || ticket.services.length > 0" > - - {{ t('globals.packages') }} - - + @@ -416,11 +414,10 @@ async function changeState(value) { - - - {{ t('ticket.summary.service') }} - - + diff --git a/src/pages/Ticket/TicketList.vue b/src/pages/Ticket/TicketList.vue index 72c2da57c..c5d25fed2 100644 --- a/src/pages/Ticket/TicketList.vue +++ b/src/pages/Ticket/TicketList.vue @@ -89,6 +89,7 @@ function navigate(id) { - - {{ t('travel.summary.entries') }} - + { /> - + { - - - - - { + + + + + { { { @@ -172,7 +182,9 @@ onMounted(async () => { en: addEntry: Add entry + searchByIdOrReference: Search by ID or reference es: addEntry: Añadir entrada + searchByIdOrReference: Buscar por ID o por referencia diff --git a/src/pages/Wagon/Type/WagonTypeList.vue b/src/pages/Wagon/Type/WagonTypeList.vue index a7c713039..23f56e4c3 100644 --- a/src/pages/Wagon/Type/WagonTypeList.vue +++ b/src/pages/Wagon/Type/WagonTypeList.vue @@ -61,7 +61,6 @@ async function remove(row) { { return $props.id || route.params.id; @@ -56,7 +56,7 @@ const filter = { const sip = computed(() => worker.value?.sip && worker.value.sip.extension); function getWorkerAvatar() { - const token = getToken(); + const token = getTokenMultimedia(); return `/api/Images/user/160x160/${entityId.value}/download?access_token=${token}`; } const data = ref(useCardDescription()); diff --git a/src/pages/Worker/Card/WorkerLog.vue b/src/pages/Worker/Card/WorkerLog.vue new file mode 100644 index 000000000..ef5a2e0d8 --- /dev/null +++ b/src/pages/Worker/Card/WorkerLog.vue @@ -0,0 +1,6 @@ + + + + diff --git a/src/pages/Worker/Card/WorkerSummary.vue b/src/pages/Worker/Card/WorkerSummary.vue index 9d0e18b15..dad21cda5 100644 --- a/src/pages/Worker/Card/WorkerSummary.vue +++ b/src/pages/Worker/Card/WorkerSummary.vue @@ -8,6 +8,7 @@ import VnLv from 'src/components/ui/VnLv.vue'; import VnLinkPhone from 'src/components/ui/VnLinkPhone.vue'; import CardSummary from 'components/ui/CardSummary.vue'; import VnUserLink from 'src/components/ui/VnUserLink.vue'; +import VnTitle from 'src/components/common/VnTitle.vue'; const route = useRoute(); const { t } = useI18n(); @@ -71,10 +72,10 @@ const filter = { - - {{ t('worker.summary.basicData') }} - - + - - {{ t('worker.summary.userData') }} - + diff --git a/src/pages/Worker/WorkerList.vue b/src/pages/Worker/WorkerList.vue index 5214a9066..b11d531dd 100644 --- a/src/pages/Worker/WorkerList.vue +++ b/src/pages/Worker/WorkerList.vue @@ -82,7 +82,6 @@ const redirectToCreateView = () => { import('src/pages/InvoiceOut/InvoiceOutNegativeBases.vue'), diff --git a/src/router/modules/worker.js b/src/router/modules/worker.js index 1c722afe8..448aab79c 100644 --- a/src/router/modules/worker.js +++ b/src/router/modules/worker.js @@ -12,7 +12,7 @@ export default { redirect: { name: 'WorkerMain' }, menus: { main: ['WorkerList', 'WorkerDepartment'], - card: ['WorkerNotificationsManager', 'WorkerPda'], + card: ['WorkerNotificationsManager', 'WorkerPda', 'WorkerLog'], departmentCard: ['BasicData'], }, children: [ @@ -85,6 +85,15 @@ export default { }, component: () => import('src/pages/Worker/Card/WorkerPda.vue'), }, + { + name: 'WorkerLog', + path: 'log', + meta: { + title: 'log', + icon: 'vn:History', + }, + component: () => import('src/pages/Worker/Card/WorkerLog.vue'), + }, ], }, ], diff --git a/src/stores/invoiceOutGlobal.js b/src/stores/invoiceOutGlobal.js index 7151aac5f..b1bcc0e7d 100644 --- a/src/stores/invoiceOutGlobal.js +++ b/src/stores/invoiceOutGlobal.js @@ -73,6 +73,9 @@ export const useInvoiceOutGlobalStore = defineStore({ const stringDate = data.issued.substring(0, 10); this.minInvoicingDate = stringDate; this.formInitialData.invoiceDate = stringDate; + + this.minInvoicingDate = new Date(data.issued); + this.formInitialData.invoiceDate = this.minInvoicingDate; } catch (err) { console.error('Error fetching invoice out global initial data'); throw new Error(); @@ -103,12 +106,8 @@ export const useInvoiceOutGlobalStore = defineStore({ if (clientsToInvoice == 'all') params.clientId = undefined; - const addressesResponse = await await axios.post( - 'InvoiceOuts/clientsToInvoice', - params - ); - - this.addresses = addressesResponse.data; + const { data } = await axios.post('InvoiceOuts/clientsToInvoice', params); + this.addresses = data; if (!this.addresses || !this.addresses.length > 0) { notify( @@ -118,9 +117,9 @@ export const useInvoiceOutGlobalStore = defineStore({ throw new Error("There aren't addresses to invoice"); } - this.addresses.forEach(async (address) => { + for (const address of this.addresses) { await this.invoiceClient(address, formData); - }); + } } catch (err) { this.handleError(err); } @@ -186,15 +185,10 @@ export const useInvoiceOutGlobalStore = defineStore({ this.status = 'invoicing'; this.invoicing = true; - const invoiceResponse = await axios.post( - 'InvoiceOuts/invoiceClient', - params - ); - - if (invoiceResponse.data) { - this.makePdfAndNotify(invoiceResponse.data, address); - } + const { data } = await axios.post('InvoiceOuts/invoiceClient', params); + if (data) await this.makePdfAndNotify(data, address); + this.addressIndex++; this.isInvoicing = false; } catch (err) { if ( @@ -203,8 +197,7 @@ export const useInvoiceOutGlobalStore = defineStore({ err.response.status >= 400 && err.response.status < 500 ) { - this.invoiceClientError(address, err.response); - this.addressIndex++; + this.invoiceClientError(address, err.response?.data?.error?.message); return; } else { this.invoicing = false; @@ -227,12 +220,11 @@ export const useInvoiceOutGlobalStore = defineStore({ this.nPdfs++; this.nRequests--; } catch (err) { - this.invoiceClientError(client, err, true); + this.invoiceClientError(client, err.response?.data?.error?.message, true); } }, - invoiceClientError(client, response, isWarning) { - const message = response.data?.error?.message || response.message; + invoiceClientError(client, message, isWarning) { this.errors.unshift({ client, message, isWarning }); }, diff --git a/test/cypress/integration/VnLocation.spec.js b/test/cypress/integration/VnLocation.spec.js index dc18a1a16..d561eef71 100644 --- a/test/cypress/integration/VnLocation.spec.js +++ b/test/cypress/integration/VnLocation.spec.js @@ -43,9 +43,9 @@ describe('VnLocation', () => { cy.waitForElement('.q-card'); }); - it('Show all options', function () { + it('Show locations options', function () { cy.get(inputLocation).click(); - cy.get(locationOptions).should('have.length', 1); + cy.get(locationOptions).should('have.length', 5); }); }); }); diff --git a/test/cypress/integration/invoiceIn/invoiceInList.spec.js b/test/cypress/integration/invoiceIn/invoiceInList.spec.js index ce79dc976..5e2a5aa4c 100644 --- a/test/cypress/integration/invoiceIn/invoiceInList.spec.js +++ b/test/cypress/integration/invoiceIn/invoiceInList.spec.js @@ -4,7 +4,7 @@ describe('InvoiceInList', () => { const firstChipId = ':nth-child(1) > :nth-child(1) > .justify-between > .flex > .q-chip > .q-chip__content'; const firstDetailBtn = '.q-card:nth-child(1) .q-btn:nth-child(2)'; - const summaryHeaders = '.summaryBody .header'; + const summaryHeaders = '.summaryBody .header-link'; const screen = '.q-page-container > .q-drawer-container > .fullscreen'; beforeEach(() => { @@ -17,7 +17,7 @@ describe('InvoiceInList', () => { cy.get(firstChipId) .invoke('text') .then((content) => { - const id = content.substring(4); + const id = content.replace(/\D/g, ''); cy.get(firstCard).click(); cy.url().should('include', `/invoice-in/${id}/summary`); }); diff --git a/test/cypress/integration/ticket/ticketDescriptor.spec.js b/test/cypress/integration/ticket/ticketDescriptor.spec.js new file mode 100644 index 000000000..c212d3b4a --- /dev/null +++ b/test/cypress/integration/ticket/ticketDescriptor.spec.js @@ -0,0 +1,27 @@ +/// +describe('Ticket descriptor', () => { + const toCloneOpt = '.q-list > :nth-child(5)'; + const warehouseValue = '.summaryBody > :nth-child(2) > :nth-child(6) > .value > span'; + const summaryHeader = '.summaryHeader > div'; + + beforeEach(() => { + const ticketId = 1; + + cy.login('developer'); + cy.visit(`/#/ticket/${ticketId}/summary`); + }); + + it('should clone the ticket without warehouse', () => { + cy.openLeftMenu(); + cy.openActionsDescriptor(); + cy.get(toCloneOpt).click(); + cy.clickConfirm(); + cy.get(warehouseValue).contains('-'); + cy.get(summaryHeader) + .invoke('text') + .then((text) => { + const [, owner] = text.split('-'); + cy.wrap(owner.trim()).should('eq', 'Bruce Wayne (1101)'); + }); + }); +}); diff --git a/test/cypress/integration/worker/workerList.spec.js b/test/cypress/integration/worker/workerList.spec.js index b5c57f920..c950f9fed 100644 --- a/test/cypress/integration/worker/workerList.spec.js +++ b/test/cypress/integration/worker/workerList.spec.js @@ -16,7 +16,10 @@ describe('WorkerList', () => { it('should open the worker summary', () => { cy.openListSummary(0); cy.get('.summaryHeader div').should('have.text', '1110 - Jessica Jones'); - cy.get('.summary .header').eq(0).invoke('text').should('include', 'Basic data'); - cy.get('.summary .header').eq(1).should('have.text', 'User data'); + cy.get('.summary .header-link') + .eq(0) + .invoke('text') + .should('include', 'Basic data'); + cy.get('.summary .header-link').eq(1).should('have.text', 'User data '); }); }); diff --git a/test/vitest/__tests__/components/Paginate.spec.js b/test/vitest/__tests__/components/Paginate.spec.js index 2a22ce438..cf5e5d2ea 100644 --- a/test/vitest/__tests__/components/Paginate.spec.js +++ b/test/vitest/__tests__/components/Paginate.spec.js @@ -49,6 +49,8 @@ describe('VnPaginate', () => { ], }); vm.arrayData.hasMoreData.value = true; + await vm.$nextTick(); + vm.store.data = [ { id: 1, name: 'Tony Stark' }, { id: 2, name: 'Jessica Jones' }, diff --git a/test/vitest/__tests__/composables/useSession.spec.js b/test/vitest/__tests__/composables/useSession.spec.js index 4f900aca6..f9f3dcb80 100644 --- a/test/vitest/__tests__/composables/useSession.spec.js +++ b/test/vitest/__tests__/composables/useSession.spec.js @@ -54,7 +54,8 @@ describe('session', () => { expect(localStorage.getItem('token')).toEqual('tokenToBeGone'); expect(user.value).toEqual(previousUser); - session.destroy(); + vi.spyOn(axios, 'post').mockResolvedValue({ data: true }); + await session.destroy(); user = state.getUser(); expect(localStorage.getItem('token')).toBeNull(); @@ -92,9 +93,10 @@ describe('session', () => { }); const expectedToken = 'mySessionToken'; + const expectedTokenMultimedia = 'mySessionTokenMultimedia'; const keepLogin = false; - await session.login(expectedToken, keepLogin); + await session.login(expectedToken,expectedTokenMultimedia, keepLogin); const roles = state.getRoles(); const localToken = localStorage.getItem('token'); @@ -104,7 +106,7 @@ describe('session', () => { expect(localToken).toBeNull(); expect(sessionToken).toEqual(expectedToken); - session.destroy(); // this clears token and user for any other test + await session.destroy(); // this clears token and user for any other test }); it('should fetch the user roles and then set token in the localStorage', async () => { @@ -114,9 +116,10 @@ describe('session', () => { }); const expectedToken = 'myLocalToken'; + const expectedTokenMultimedia = 'myLocalTokenMultimedia'; const keepLogin = true; - await session.login(expectedToken, keepLogin); + await session.login(expectedToken, expectedTokenMultimedia, keepLogin); const roles = state.getRoles(); const localToken = localStorage.getItem('token'); @@ -126,7 +129,7 @@ describe('session', () => { expect(localToken).toEqual(expectedToken); expect(sessionToken).toBeNull(); - session.destroy(); // this clears token and user for any other test + await session.destroy(); // this clears token and user for any other test }); }); }); diff --git a/test/vitest/__tests__/pages/Login/Login.spec.js b/test/vitest/__tests__/pages/Login/Login.spec.js index fadfc898f..6e2de9870 100644 --- a/test/vitest/__tests__/pages/Login/Login.spec.js +++ b/test/vitest/__tests__/pages/Login/Login.spec.js @@ -22,9 +22,9 @@ describe('Login', () => { darkMode: false, }, }; - vi.spyOn(axios, 'post').mockResolvedValue({ data: { token: 'token' } }); + vi.spyOn(axios, 'post').mockResolvedValueOnce({ data: { token: 'token' } }); vi.spyOn(axios, 'get').mockResolvedValue({ - data: { roles: [], user: expectedUser }, + data: { roles: [], user: expectedUser , multimediaToken: {id:'multimediaToken' }}, }); vi.spyOn(vm.quasar, 'notify'); @@ -36,7 +36,7 @@ describe('Login', () => { expect(vm.quasar.notify).toHaveBeenCalledWith( expect.objectContaining({ type: 'positive' }) ); - vm.session.destroy(); + await vm.session.destroy(); }); it('should not set the token into session if any error occurred', async () => {
{{ subtitle }}