diff --git a/package.json b/package.json index c638b6c32..9d14e8727 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "axios": "^1.4.0", "chromium": "^3.0.3", "croppie": "^2.6.5", + "moment": "^2.30.1", "pinia": "^2.1.3", "quasar": "^2.14.5", "validator": "^13.9.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 83dfa0469..7bf640347 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -20,6 +20,9 @@ dependencies: croppie: specifier: ^2.6.5 version: 2.6.5 + moment: + specifier: ^2.30.1 + version: 2.30.1 pinia: specifier: ^2.1.3 version: 2.1.7(typescript@5.5.4)(vue@3.4.19) @@ -832,8 +835,8 @@ packages: vue-i18n: optional: true dependencies: - '@intlify/message-compiler': 10.0.0 - '@intlify/shared': 10.0.0 + '@intlify/message-compiler': 11.0.0-rc.1 + '@intlify/shared': 11.0.0-rc.1 jsonc-eslint-parser: 1.4.1 source-map: 0.6.1 vue-i18n: 9.9.1(vue@3.4.19) @@ -847,11 +850,11 @@ packages: '@intlify/message-compiler': 9.9.1 '@intlify/shared': 9.9.1 - /@intlify/message-compiler@10.0.0: - resolution: {integrity: sha512-OcaWc63NC/9p1cMdgoNKBj4d61BH8sUW1Hfs6YijTd9656ZR4rNqXAlRnBrfS5ABq0vjQjpa8VnyvH9hK49yBw==} + /@intlify/message-compiler@11.0.0-rc.1: + resolution: {integrity: sha512-TGw2uBfuTFTegZf/BHtUQBEKxl7Q/dVGLoqRIdw8lFsp9g/53sYn5iD+0HxIzdYjbWL6BTJMXCPUHp9PxDTRPw==} engines: {node: '>= 16'} dependencies: - '@intlify/shared': 10.0.0 + '@intlify/shared': 11.0.0-rc.1 source-map-js: 1.0.2 dev: true @@ -862,8 +865,8 @@ packages: '@intlify/shared': 9.9.1 source-map-js: 1.0.2 - /@intlify/shared@10.0.0: - resolution: {integrity: sha512-6ngLfI7DOTew2dcF9WMJx+NnMWghMBhIiHbGg+wRvngpzD5KZJZiJVuzMsUQE1a5YebEmtpTEfUrDp/NqVGdiw==} + /@intlify/shared@11.0.0-rc.1: + resolution: {integrity: sha512-8tR1xe7ZEbkabTuE/tNhzpolygUn9OaYp9yuYAF4MgDNZg06C3Qny80bes2/e9/Wm3aVkPUlCw6WgU7mQd0yEg==} engines: {node: '>= 16'} dev: true @@ -887,7 +890,7 @@ packages: optional: true dependencies: '@intlify/bundle-utils': 4.0.0(vue-i18n@9.9.1) - '@intlify/shared': 10.0.0 + '@intlify/shared': 11.0.0-rc.1 '@rollup/pluginutils': 4.2.1 '@vue/compiler-sfc': 3.4.19 debug: 4.3.4(supports-color@8.1.1) @@ -4960,6 +4963,10 @@ packages: uuid: 8.3.2 dev: true + /moment@2.30.1: + resolution: {integrity: sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==} + dev: false + /ms@2.0.0: resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} diff --git a/src/components/common/VnChangePassword.vue b/src/components/common/VnChangePassword.vue index 79784f3c5..d8374498f 100644 --- a/src/components/common/VnChangePassword.vue +++ b/src/components/common/VnChangePassword.vue @@ -2,9 +2,9 @@ import { ref } from 'vue'; import { useI18n } from 'vue-i18n'; import VnRow from '../ui/VnRow.vue'; -import VnInput from './VnInput.vue'; import FetchData from '../FetchData.vue'; import useNotify from 'src/composables/useNotify'; +import VnInputPassword from 'src/components/common/VnInputPassword.vue'; const props = defineProps({ submitFn: { type: Function, default: () => {} }, @@ -70,19 +70,19 @@ defineExpose({ show: () => changePassDialog.value.show() }); </QCardSection> <QForm ref="form"> <QCardSection> - <VnInput + <VnInputPassword v-if="props.askOldPass" :label="t('Old password')" v-model="passwords.oldPassword" - type="password" :required="true" + :toggle-visibility="true" autofocus /> - <VnInput + <VnInputPassword :label="t('New password')" v-model="passwords.newPassword" - type="password" :required="true" + :toggle-visibility="true" :info=" t('passwordRequirements', { length: requirements.length, @@ -95,10 +95,10 @@ defineExpose({ show: () => changePassDialog.value.show() }); autofocus /> - <VnInput + <VnInputPassword :label="t('Repeat password')" v-model="passwords.repeatPassword" - type="password" + :toggle-visibility="true" /> </QCardSection> </QForm> diff --git a/src/components/common/VnInput.vue b/src/components/common/VnInput.vue index 3cecf760a..4c7445aab 100644 --- a/src/components/common/VnInput.vue +++ b/src/components/common/VnInput.vue @@ -45,6 +45,7 @@ const $props = defineProps({ }); const vnInputRef = ref(null); +const showPassword = ref(false); const value = computed({ get() { return $props.modelValue; @@ -134,7 +135,7 @@ const handleInsertMode = (e) => { hide-bottom-space :data-cy="$attrs.dataCy ?? $attrs.label + '_input'" > - <template v-if="$slots.prepend" #prepend> + <template #prepend> <slot name="prepend" /> </template> <template #append> @@ -158,7 +159,7 @@ const handleInsertMode = (e) => { emit('remove'); } " - ></QIcon> + /> <slot name="append" v-if="$slots.append && !$attrs.disabled" /> <QIcon v-if="info" name="info"> <QTooltip max-width="350px"> @@ -169,18 +170,3 @@ const handleInsertMode = (e) => { </QInput> </div> </template> -<i18n> - en: - inputMin: Must be more than {value} - maxLength: The value exceeds {value} characters - inputMax: Must be less than {value} - es: - inputMin: Debe ser mayor a {value} - maxLength: El valor excede los {value} carácteres - inputMax: Debe ser menor a {value} -</i18n> -<style lang="scss"> -.q-field__append { - padding-inline: 0; -} -</style> diff --git a/src/components/common/VnInputPassword.vue b/src/components/common/VnInputPassword.vue new file mode 100644 index 000000000..56981c0c3 --- /dev/null +++ b/src/components/common/VnInputPassword.vue @@ -0,0 +1,31 @@ +<script setup> +import VnInput from 'src/components/common/VnInput.vue'; +import { ref } from 'vue'; + +const model = defineModel({ type: [Number, String] }); +const $props = defineProps({ + toggleVisibility: { + type: Boolean, + default: false, + }, +}); + +const showPassword = ref(false); +</script> +<template> + <VnInput + v-bind="{ ...$attrs }" + v-model="model" + :type=" + $props.toggleVisibility ? (showPassword ? 'text' : 'password') : $attrs.type + " + > + <template #append v-if="toggleVisibility"> + <QIcon + :name="showPassword ? 'visibility_off' : 'visibility'" + class="cursor-pointer" + @click="showPassword = !showPassword" + /> + </template> + </VnInput> +</template> diff --git a/src/components/ui/__tests__/FetchedTags.spec.js b/src/components/ui/__tests__/FetchedTags.spec.js new file mode 100644 index 000000000..3c658a80e --- /dev/null +++ b/src/components/ui/__tests__/FetchedTags.spec.js @@ -0,0 +1,81 @@ +import { describe, expect, it } from 'vitest'; +import { createWrapper } from 'app/test/vitest/helper'; +import FetchedTags from 'src/components/ui/FetchedTags.vue'; + +describe('tags computed property', () => { + it('returns an object with the correct keys and values', () => { + const vm = createWrapper(FetchedTags, { + props: { + item: { + tag1: 'JavaScript', + value1: 'Programming Language', + tag2: 'Vue', + value2: 'Framework', + tag3: 'EmptyTag', + }, + tag: 'tag', + value: 'value', + columns: 2, + }, + }).vm; + expect(vm.tags).toEqual({ + JavaScript: 'Programming Language', + Vue: 'Framework', + EmptyTag: '', + }); + }); + + it('returns an empty object if the item prop is an empty object', () => { + const vm = createWrapper(FetchedTags, { + props: { + item: {}, + tag: 'tag', + value: 'value', + }, + }).vm; + expect(vm.tags).toEqual({}); + }); + + it('should calculate the correct columnStyle when columns prop is defined', () => { + const vm = createWrapper(FetchedTags, { + props: { + item: { + tag1: 'JavaScript', + value1: 'Programming Language', + tag2: 'Vue', + value2: 'Framework', + tag3: 'EmptyTag', + }, + tag: 'tag', + value: 'value', + columns: 2, + }, + }).vm; + + const expectedStyle = { + 'grid-template-columns': 'repeat(2, 1fr)', + 'max-width': '8rem', + }; + + expect(vm.columnStyle).toEqual(expectedStyle); + }); + + it('should return an empty object for columnStyle when columns prop is not defined', () => { + const vm = createWrapper(FetchedTags, { + props: { + item: { + tag1: 'JavaScript', + value1: 'Programming Language', + tag2: 'Vue', + value2: 'Framework', + tag3: 'EmptyTag', + }, + tag: 'tag', + value: 'value', + columns: null, + }, + }).vm; + + expect(vm.columnStyle).toEqual({}); + }); +}); diff --git a/src/composables/useArrayData.js b/src/composables/useArrayData.js index 1f4234a00..c13c4f9a6 100644 --- a/src/composables/useArrayData.js +++ b/src/composables/useArrayData.js @@ -104,12 +104,14 @@ export function useArrayData(key = useRoute().meta.moduleName, userOptions) { store.hasMoreData = limit && response.data.length >= limit; - processData(response.data, { map: !!store.mapKey, append }); - if (!append && !isDialogOpened()) updateRouter && updateStateParams(); - + if (!append && !isDialogOpened() && updateRouter) { + if (updateStateParams(response.data)?.redirect) return; + } store.isLoading = false; canceller = null; + processData(response.data, { map: !!store.mapKey, append }); + return response; } @@ -239,7 +241,7 @@ export function useArrayData(key = useRoute().meta.moduleName, userOptions) { if (Object.values(store.userParams).length) await fetch({}); } - function updateStateParams() { + function updateStateParams(data) { if (!route?.path) return; const newUrl = { path: route.path, query: { ...(route.query ?? {}) } }; if (store?.searchUrl) @@ -256,15 +258,15 @@ export function useArrayData(key = useRoute().meta.moduleName, userOptions) { const { path } = matches.at(-1); const to = - store?.data?.length === 1 - ? path.replace(/\/(list|:id)|-list/, `/${store.data[0].id}`) + data?.length === 1 + ? path.replace(/\/(list|:id)|-list/, `/${data[0].id}`) : path.replace(/:id.*/, ''); if (route.path != to) { const pushUrl = { path: to }; if (to.endsWith('/list') || to.endsWith('/')) pushUrl.query = newUrl.query; - return router.push(pushUrl); + return router.push(pushUrl) && { redirect: true }; } } diff --git a/src/filters/toDateHourMin.js b/src/filters/toDateHourMin.js index 2b6995c01..c813840cb 100644 --- a/src/filters/toDateHourMin.js +++ b/src/filters/toDateHourMin.js @@ -1,5 +1,6 @@ export default function toDateHourMin(date) { - const dateHour = new Date(date).toLocaleDateString('es-ES', { + if (!date) return date; + return new Date(date).toLocaleDateString('es-ES', { timeZone: 'Europe/Madrid', year: 'numeric', month: '2-digit', @@ -7,5 +8,4 @@ export default function toDateHourMin(date) { hour: '2-digit', minute: '2-digit', }); - return dateHour; } diff --git a/src/filters/toDateHourMinSec.js b/src/filters/toDateHourMinSec.js index cfc9506fb..51df725e4 100644 --- a/src/filters/toDateHourMinSec.js +++ b/src/filters/toDateHourMinSec.js @@ -1,5 +1,6 @@ export default function toDateHourMinSec(date) { - const dateHour = new Date(date).toLocaleDateString('es-ES', { + if (!date) return date; + return new Date(date).toLocaleDateString('es-ES', { timeZone: 'Europe/Madrid', year: 'numeric', month: '2-digit', @@ -8,5 +9,4 @@ export default function toDateHourMinSec(date) { minute: '2-digit', second: '2-digit', }); - return dateHour; } diff --git a/src/i18n/locale/en.yml b/src/i18n/locale/en.yml index 038167281..71440760b 100644 --- a/src/i18n/locale/en.yml +++ b/src/i18n/locale/en.yml @@ -456,12 +456,26 @@ entry: packingOut: Package out landing: Landing isExcludedFromAvailable: Es inventory + params: + toShipped: To + fromShipped: From + warehouseiNFk: Warehouse + daysOnward: Days onward + daysAgo: Days ago + warehouseInFk: Warehouse in ticket: params: ticketFk: Ticket ID weekDay: Weekday agencyModeFk: Agency id: Worker + state: State + created: Created + externalId: External ID + counter: Counter + freightItemName: Freight item name + packageItemName: Package item name + longName: Long name card: customerId: Customer ID customerCard: Customer card diff --git a/src/i18n/locale/es.yml b/src/i18n/locale/es.yml index 6a066cb15..3f0830f33 100644 --- a/src/i18n/locale/es.yml +++ b/src/i18n/locale/es.yml @@ -457,12 +457,25 @@ entry: packingOut: Embalaje envíos landing: Llegada isExcludedFromAvailable: Es inventario + params: + toShipped: Hasta + fromShipped: Desde + warehouseInFk: Alm. entrada + daysOnward: Días adelante + daysAgo: Días atras ticket: params: ticketFk: ID de ticket weekDay: Salida agencyModeFk: Agencia id: Comercial + created: Creado + state: Estado + externalId: ID externo + counter: Contador + freightItemName: Nombre + packageItemName: Embalaje + longName: Descripción card: customerId: ID cliente customerCard: Ficha del cliente diff --git a/src/pages/Account/AccountCreate.vue b/src/pages/Account/AccountCreate.vue index 6b7c049c8..b925ff06a 100644 --- a/src/pages/Account/AccountCreate.vue +++ b/src/pages/Account/AccountCreate.vue @@ -6,6 +6,7 @@ import FormModelPopup from 'components/FormModelPopup.vue'; import VnSelect from 'src/components/common/VnSelect.vue'; import FetchData from 'components/FetchData.vue'; import VnInput from 'src/components/common/VnInput.vue'; +import VnInputPassword from 'src/components/common/VnInputPassword.vue'; const { t } = useI18n(); const router = useRouter(); @@ -61,10 +62,10 @@ const redirectToAccountBasicData = (_, { id }) => { hide-selected :rules="validate('VnUser.roleFk')" /> - <VnInput + <VnInputPassword v-model="data.password" :label="t('ldap.password')" - type="password" + :toggle-visibility="true" :rules="validate('VnUser.password')" /> <QCheckbox diff --git a/src/pages/Account/AccountLdap.vue b/src/pages/Account/AccountLdap.vue index bb220aa2e..4710f961b 100644 --- a/src/pages/Account/AccountLdap.vue +++ b/src/pages/Account/AccountLdap.vue @@ -8,6 +8,7 @@ import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue'; import { useArrayData } from 'src/composables/useArrayData'; import useNotify from 'src/composables/useNotify.js'; import axios from 'axios'; +import VnInputPassword from 'src/components/common/VnInputPassword.vue'; const { t } = useI18n(); const { notify } = useNotify(); @@ -128,10 +129,9 @@ onMounted(async () => await getInitialLdapConfig()); :required="true" :rules="validate('LdapConfig.rdn')" /> - <VnInput + <VnInputPassword :label="t('ldap.password')" clearable - type="password" v-model="data.password" :required="true" :rules="validate('LdapConfig.password')" diff --git a/src/pages/Account/AccountList.vue b/src/pages/Account/AccountList.vue index c1c75fcee..ea8daba0d 100644 --- a/src/pages/Account/AccountList.vue +++ b/src/pages/Account/AccountList.vue @@ -4,9 +4,9 @@ import { computed, ref } from 'vue'; import VnTable from 'components/VnTable/VnTable.vue'; import AccountSummary from './Card/AccountSummary.vue'; import { useSummaryDialog } from 'src/composables/useSummaryDialog'; -import VnInput from 'src/components/common/VnInput.vue'; import VnSection from 'src/components/common/VnSection.vue'; import FetchData from 'src/components/FetchData.vue'; +import VnInputPassword from 'src/components/common/VnInputPassword.vue'; const { t } = useI18n(); const { viewSummary } = useSummaryDialog(); @@ -168,10 +168,9 @@ function exprBuilder(param, value) { > <template #more-create-dialog="{ data }"> <QCardSection> - <VnInput + <VnInputPassword :label="t('Password')" v-model="data.password" - type="password" :required="true" autocomplete="new-password" /> diff --git a/src/pages/Account/AccountSamba.vue b/src/pages/Account/AccountSamba.vue index 699a638eb..7b36de85f 100644 --- a/src/pages/Account/AccountSamba.vue +++ b/src/pages/Account/AccountSamba.vue @@ -8,6 +8,7 @@ import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue'; import { useArrayData } from 'src/composables/useArrayData'; import useNotify from 'src/composables/useNotify.js'; import axios from 'axios'; +import VnInputPassword from 'src/components/common/VnInputPassword.vue'; const { t } = useI18n(); const { notify } = useNotify(); @@ -143,10 +144,9 @@ onMounted(async () => await getInitialSambaConfig()); v-model="data.adUser" :rules="validate('SambaConfigs.adUser')" /> - <VnInput + <VnInputPassword :label="t('samba.passwordAD')" clearable - type="password" v-model="data.adPassword" /> <VnInput diff --git a/src/pages/Account/Card/AccountDescriptorMenu.vue b/src/pages/Account/Card/AccountDescriptorMenu.vue index 1780b4247..c091962fc 100644 --- a/src/pages/Account/Card/AccountDescriptorMenu.vue +++ b/src/pages/Account/Card/AccountDescriptorMenu.vue @@ -9,6 +9,7 @@ import { useArrayData } from 'src/composables/useArrayData'; import VnConfirm from 'src/components/ui/VnConfirm.vue'; import VnChangePassword from 'src/components/common/VnChangePassword.vue'; import { useQuasar } from 'quasar'; +import VnInputPassword from 'src/components/common/VnInputPassword.vue'; const $props = defineProps({ hasAccount: { @@ -97,14 +98,13 @@ async function sync() { <QTooltip>{{ t('account.card.actions.sync.tooltip') }}</QTooltip> </QIcon></QCheckbox > - <QInput + <VnInputPassword v-if="shouldSyncPassword" :label="t('login.password')" v-model="syncPassword" class="full-width" clearable clear-icon="close" - type="password" /> </template> </VnConfirm> diff --git a/src/pages/Customer/locale/en.yml b/src/pages/Customer/locale/en.yml index 1d2497ded..1918838b7 100644 --- a/src/pages/Customer/locale/en.yml +++ b/src/pages/Customer/locale/en.yml @@ -95,6 +95,7 @@ customer: isToBeMailed: Mailing hasSepaVnl: VNL B2B received params: + id: Id isWorker: Is Worker payMethod: Payment Method workerFk: Author @@ -102,4 +103,15 @@ customer: created: Last Update Date creditInsurance: Credit Insurance defaulterSinced: Defaulted Since - hasRecovery: Has Recovery \ No newline at end of file + hasRecovery: Has Recovery + socialName: Social name + city: City + phone: Phone + postcode: Postcode + campaign: Campaign + grouped: Grouped + search: Contains + itemId: Item Id + ticketFk: Ticket Id + description: Description + quantity: Quantity diff --git a/src/pages/Customer/locale/es.yml b/src/pages/Customer/locale/es.yml index 1b56f6805..d5db3df1b 100644 --- a/src/pages/Customer/locale/es.yml +++ b/src/pages/Customer/locale/es.yml @@ -97,6 +97,7 @@ customer: isToBeMailed: Env. emails hasSepaVnl: Recibido B2B VNL params: + id: ID isWorker: Es trabajador payMethod: F. Pago workerFk: Autor @@ -104,4 +105,15 @@ customer: created: Fecha Ú. O. creditInsurance: Crédito A. defaulterSinced: Desde - hasRecovery: Tiene recobro \ No newline at end of file + hasRecovery: Tiene recobro + socialName: Razón social + campaign: Campaña + city: Ciudad + phone: Teléfono + postcode: Código postal + grouped: Agrupado + search: Contiene + itemId: Id Artículo + ticketFk: Id Ticket + description: Descripción + quantity: Cantidad diff --git a/src/pages/Entry/EntryBuysTableDialog.vue b/src/pages/Entry/EntryBuysTableDialog.vue index 3975bff19..a2d8c9117 100644 --- a/src/pages/Entry/EntryBuysTableDialog.vue +++ b/src/pages/Entry/EntryBuysTableDialog.vue @@ -1,24 +1,24 @@ <script setup> -import { computed } from 'vue'; +import { computed, ref } from 'vue'; import { useRoute } from 'vue-router'; import { useI18n } from 'vue-i18n'; import { QBtn } from 'quasar'; import VnPaginate from 'src/components/ui/VnPaginate.vue'; import { usePrintService } from 'composables/usePrintService'; -const { openReport } = usePrintService(); +const { openReport } = usePrintService(); +const buyRows = ref([]); const route = useRoute(); const { t } = useI18n(); const $props = defineProps({ id: { - type: String, + type: Number, required: false, default: null, }, }); const entityId = computed(() => $props.id || route.params.id); - const entriesTableColumns = computed(() => [ { align: 'left', @@ -63,34 +63,39 @@ const entriesTableColumns = computed(() => [ field: 'grouping', }, ]); -</script> +function downloadCSV(rows) { + const headers = ['id', 'itemFk', 'name', 'stickers', 'packing', 'comment']; + + const csvRows = rows.map((row) => { + const buy = row; + const item = buy.item || {}; + + return [ + buy.id, + buy.itemFk, + item.name || '', + buy.stickers, + buy.packing, + item.comment || '', + ].join(','); + }); + + const csvContent = [headers.join(','), ...csvRows].join('\n'); + + const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' }); + const url = URL.createObjectURL(blob); + const link = document.createElement('a'); + link.href = url; + link.setAttribute('download', `${entityId.value}data.csv`); + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); +} +</script> <template> <QDialog ref="dialogRef"> <QCard style="min-width: 800px"> - <QCardSection class="row items-center q-pb-none"> - <QAvatar - :icon="icon" - color="primary" - text-color="white" - size="xl" - v-if="icon" - /> - <span class="text-h6 text-grey">{{ title }}</span> - <QSpace /> - <QBtn icon="close" :disable="isLoading" flat round dense v-close-popup /> - </QCardSection> - <QCardActions align="right"> - <QBtn - :label="t('myEntries.printLabels')" - color="primary" - icon="print" - :loading="isLoading" - @click="openReport(`Entries/${entityId}/labelSupplier`)" - unelevated - autofocus - /> - </QCardActions> <QCardSection class="row items-center"> <VnPaginate ref="entryBuysPaginateRef" @@ -101,6 +106,7 @@ const entriesTableColumns = computed(() => [ > <template #body="{ rows }"> <QTable + ref="buyRows" :rows="rows" :columns="entriesTableColumns" row-key="id" @@ -110,6 +116,26 @@ const entriesTableColumns = computed(() => [ :grid="$q.screen.lt.md" :no-data-label="t('globals.noResults')" > + <template #top-left> + <QBtn + :label="t('myEntries.downloadCsv')" + color="primary" + icon="csv" + @click="downloadCSV(rows)" + unelevated + /> + </template> + <template #top-right> + <QBtn + class="q-mr-lg" + :label="t('myEntries.printLabels')" + color="primary" + icon="print" + @click=" + openReport(`Entries/${entityId}/labelSupplier`) + " + /> + </template> <template #body="props"> <QTr> <QTd v-for="col in props.cols" :key="col.name"> @@ -118,7 +144,6 @@ const entriesTableColumns = computed(() => [ <QBtn icon="visibility" v-if="props.row.stickers > 0" - :loading="isLoading" @click=" openReport( `Entries/${props.row.id}/buy-label-supplier` diff --git a/src/pages/Entry/MyEntries.vue b/src/pages/Entry/MyEntries.vue index 91a29b190..dbe05eb88 100644 --- a/src/pages/Entry/MyEntries.vue +++ b/src/pages/Entry/MyEntries.vue @@ -102,7 +102,7 @@ const columns = computed(() => [ actions: [ { title: t('myEntries.printLabels'), - icon: 'print', + icon: 'move_item', isPrimary: true, action: (row) => printBuys(row.id), }, diff --git a/src/pages/Entry/locale/en.yml b/src/pages/Entry/locale/en.yml index 68cc9caa7..6e41566d0 100644 --- a/src/pages/Entry/locale/en.yml +++ b/src/pages/Entry/locale/en.yml @@ -17,13 +17,6 @@ myEntries: warehouseInFk: Warehouse in daysOnward: Days onward daysAgo: Days ago + downloadCsv: Download CSV wasteRecalc: recalcOk: The wastes were successfully recalculated -entry: - params: - toShipped: To - fromShipped: From - warehouseiNFk: Warehouse - daysOnward: Days onward - daysAgo: Days ago - \ No newline at end of file diff --git a/src/pages/Entry/locale/es.yml b/src/pages/Entry/locale/es.yml index cc9a4ff7b..7e627b09f 100644 --- a/src/pages/Entry/locale/es.yml +++ b/src/pages/Entry/locale/es.yml @@ -20,13 +20,6 @@ myEntries: warehouseInFk: Alm. entrada daysOnward: Días adelante daysAgo: Días atras + downloadCsv: Descargar CSV wasteRecalc: recalcOk: Se han recalculado las mermas correctamente -entry: - params: - toShipped: Hasta - fromShipped: Desde - warehouseInFk: Alm. entrada - daysOnward: Días adelante - daysAgo: Días atras - \ No newline at end of file diff --git a/src/pages/Login/LoginMain.vue b/src/pages/Login/LoginMain.vue index 44b868ebd..a4c3566a9 100644 --- a/src/pages/Login/LoginMain.vue +++ b/src/pages/Login/LoginMain.vue @@ -3,7 +3,7 @@ import { ref } from 'vue'; import { Notify } from 'quasar'; import { useI18n } from 'vue-i18n'; import { useRouter } from 'vue-router'; - +import VnInputPassword from 'src/components/common/VnInputPassword.vue'; import { useSession } from 'src/composables/useSession'; import { useLogin } from 'src/composables/useLogin'; @@ -63,11 +63,10 @@ async function onSubmit() { :rules="[(val) => (val && val.length > 0) || t('login.fieldRequired')]" color="primary" /> - <VnInput - type="password" + <VnInputPassword v-model="password" :label="t('login.password')" - lazy-rules + :toggle-visibility="true" :rules="[(val) => (val && val.length > 0) || t('login.fieldRequired')]" class="red" /> diff --git a/src/pages/Login/ResetPassword.vue b/src/pages/Login/ResetPassword.vue index 2751f1ceb..081801e0e 100644 --- a/src/pages/Login/ResetPassword.vue +++ b/src/pages/Login/ResetPassword.vue @@ -7,6 +7,7 @@ import axios from 'axios'; import VnInput from 'components/common/VnInput.vue'; import VnOutForm from 'components/ui/VnOutForm.vue'; +import VnInputPassword from 'src/components/common/VnInputPassword.vue'; const quasar = useQuasar(); const router = useRouter(); @@ -54,8 +55,7 @@ async function onSubmit() { <template> <VnOutForm @submit="onSubmit" :title="t('globals.pageTitles.resetPassword')"> <template #default> - <VnInput - type="password" + <VnInputPassword :label="t('login.password')" v-model="newPassword" :info=" @@ -72,9 +72,8 @@ async function onSubmit() { <template #prepend> <QIcon name="password" /> </template> - </VnInput> - <VnInput - type="password" + </VnInputPassword> + <VnInputPassword :label="t('resetPassword.repeatPassword')" v-model="repeatPassword" required @@ -82,7 +81,7 @@ async function onSubmit() { <template #prepend> <QIcon name="password" /> </template> - </VnInput> + </VnInputPassword> </template> <template #buttons> <QBtn diff --git a/src/pages/Route/locale/en.yml b/src/pages/Route/locale/en.yml index 420d18dfe..7a1f9e1c0 100644 --- a/src/pages/Route/locale/en.yml +++ b/src/pages/Route/locale/en.yml @@ -1,4 +1,18 @@ route: + params: + etd: ETD + tractorPlate: Plate + price: Price + observations: Observations + id: ID + name: Name + cmrFk: CMR id + hasCmrDms: Attached in gestdoc + ticketFk: Ticketd id + routeFk: Route id + shipped: Shipped + agencyAgreement: Agency agreement + agencyModeName: Agency route Worker: Worker Agency: Agency Vehicle: Vehicle diff --git a/src/pages/Supplier/Card/SupplierSummary.vue b/src/pages/Supplier/Card/SupplierSummary.vue index 5892811e6..b658ca5fb 100644 --- a/src/pages/Supplier/Card/SupplierSummary.vue +++ b/src/pages/Supplier/Card/SupplierSummary.vue @@ -39,6 +39,7 @@ const getUrl = (section) => `#/supplier/${entityId.value}/${section}`; :url="`Suppliers/${entityId}/getSummary`" @on-fetch="(data) => setData(data)" data-key="SupplierSummary" + module-name="Supplier" > <template #header> <span>{{ supplier.id }} - {{ supplier.name }}</span> diff --git a/src/pages/Ticket/Card/TicketExpedition.vue b/src/pages/Ticket/Card/TicketExpedition.vue index c6fd2b7fa..166e86978 100644 --- a/src/pages/Ticket/Card/TicketExpedition.vue +++ b/src/pages/Ticket/Card/TicketExpedition.vue @@ -201,7 +201,7 @@ const getExpeditionState = async (expedition) => { const openGrafana = (expeditionFk) => { useOpenURL( - `https://grafana.verdnatura.es/d/d552ab74-85b4-4e7f-a279-fab7cd9c6124/control-de-expediciones?orgId=1&var-expeditionFk=${expeditionFk}` + `https://grafana.verdnatura.es/d/de1njb6p5answd/control-de-expediciones?orgId=1&var-expeditionFk=${expeditionFk}` ); }; diff --git a/src/pages/Travel/ExtraCommunity.vue b/src/pages/Travel/ExtraCommunity.vue index 7d7c5f07d..dee9d923a 100644 --- a/src/pages/Travel/ExtraCommunity.vue +++ b/src/pages/Travel/ExtraCommunity.vue @@ -597,7 +597,7 @@ const getColor = (percentage) => { v-if="entry.isCustomInspectionRequired" name="warning" color="negative" - size="xs" + size="md" :title="t('requiresInspection')" > </QIcon> @@ -627,7 +627,7 @@ const getColor = (percentage) => { <QBtn v-if="entry.evaNotes" icon="comment" - size="sm" + size="md" flat color="primary" > diff --git a/src/pages/Worker/Card/WorkerTimeControl.vue b/src/pages/Worker/Card/WorkerTimeControl.vue index 8d54cb810..65fbf4b43 100644 --- a/src/pages/Worker/Card/WorkerTimeControl.vue +++ b/src/pages/Worker/Card/WorkerTimeControl.vue @@ -22,6 +22,7 @@ import { useVnConfirm } from 'composables/useVnConfirm'; import { useArrayData } from 'composables/useArrayData'; import { toTimeFormat, secondsToHoursMinutes } from 'filters/date.js'; import toDateString from 'filters/toDateString.js'; +import moment from 'moment'; import { date } from 'quasar'; const route = useRoute(); @@ -64,6 +65,7 @@ const selectedDateFormatted = ref(toDateString(defaultDate.value)); const arrayData = useArrayData('workerData'); const acl = useAcl(); +const selectedDateYear = computed(() => moment(selectedDate.value).isoWeekYear()); const worker = computed(() => arrayData.store?.data); const canSend = computed(() => acl.hasAny([{ model: 'WorkerTimeControl', props: 'sendMail', accessType: 'WRITE' }]) @@ -278,7 +280,7 @@ const fetchHours = async () => { const fetchWeekData = async () => { const where = { - year: selectedDate.value.getFullYear(), + year: selectedDateYear.value, week: selectedWeekNumber.value, }; const mail = ( @@ -370,7 +372,7 @@ const showReasonForm = () => { const updateWorkerTimeControlMail = async (state, reason) => { const params = { - year: selectedDate.value.getFullYear(), + year: selectedDateYear.value, week: selectedWeekNumber.value, state, }; @@ -400,7 +402,7 @@ const resendEmail = async () => { const params = { recipient: worker.value[0]?.user?.emailUser?.email, week: selectedWeekNumber.value, - year: selectedDate.value.getFullYear(), + year: selectedDateYear.value, workerId: Number(route.params.id), state: 'SENDED', }; diff --git a/src/pages/Worker/Card/WorkerTimeControlCalendar.vue b/src/pages/Worker/Card/WorkerTimeControlCalendar.vue index 2717a71f4..46ae4b698 100644 --- a/src/pages/Worker/Card/WorkerTimeControlCalendar.vue +++ b/src/pages/Worker/Card/WorkerTimeControlCalendar.vue @@ -102,8 +102,7 @@ const getWorkWeekElements = () => { }; const paintWorkWeeks = async () => { - for (var i = 0; i < workWeeksElements.value.length; i++) { - const element = workWeeksElements.value[i]; + for (const element of workWeeksElements.value) { const week = Number(element.innerHTML); const weekState = workerTimeControlMailsMap.value.get(week); const { className, title } = stateClasses[weekState] || {}; diff --git a/test/cypress/integration/outLogin/login.spec.js b/test/cypress/integration/outLogin/login.spec.js index 3db223cdb..2bd5a8c3b 100755 --- a/test/cypress/integration/outLogin/login.spec.js +++ b/test/cypress/integration/outLogin/login.spec.js @@ -19,6 +19,7 @@ describe('Login', () => { it('should fail to log in using wrong password', () => { cy.get('input[aria-label="Username"]').type('employee'); cy.get('input[aria-label="Password"]').type('wrongPassword'); + cy.get('.q-field__append > .q-icon'); cy.get('button[type="submit"]').click(); cy.get('.q-notification__message').should( 'have.text',