diff --git a/src/boot/vnDate.js b/src/boot/vnDate.js index 33d5ac27f..8f18e2400 100644 --- a/src/boot/vnDate.js +++ b/src/boot/vnDate.js @@ -1,4 +1,6 @@ import { boot } from 'quasar/wrappers'; +import { date as quasarDate } from 'quasar'; +const { formatDate } = quasarDate; export default boot(() => { Date.vnUTC = () => { @@ -25,4 +27,34 @@ export default boot(() => { const date = new Date(Date.vnUTC()); return new Date(date.getFullYear(), date.getMonth() + 1, 0); }; + + Date.getCurrentDateTimeFormatted = ( + options = { + startOfDay: false, + endOfDay: true, + iso: true, + mask: 'DD-MM-YYYY HH:mm', + }, + ) => { + const date = Date.vnUTC(); + if (options.startOfDay) { + date.setHours(0, 0, 0); + } + if (options.endOfDay) { + date.setHours(23, 59, 0); + } + if (options.iso) { + return date.toISOString(); + } + return formatDate(date, options.mask); + }; + + Date.convertToISODateTime = (dateTimeStr) => { + const [datePart, timePart] = dateTimeStr.split(' '); + const [day, month, year] = datePart.split('-'); + const [hours, minutes] = timePart.split(':'); + + const isoDate = new Date(year, month - 1, day, hours, minutes); + return isoDate.toISOString(); + }; }); diff --git a/src/components/EditPictureForm.vue b/src/components/EditPictureForm.vue index 1f158e785..29377b559 100644 --- a/src/components/EditPictureForm.vue +++ b/src/components/EditPictureForm.vue @@ -140,7 +140,7 @@ const updatePhotoPreview = (value) => { img.onerror = () => { notify( t("This photo provider doesn't allow remote downloads"), - 'negative' + 'negative', ); }; } @@ -219,11 +219,7 @@ const makeRequest = async () => { color="primary" class="cursor-pointer" @click="rotateLeft()" - > - - + />
@@ -233,11 +229,7 @@ const makeRequest = async () => { color="primary" class="cursor-pointer" @click="rotateRight()" - > - - + />
@@ -265,7 +257,6 @@ const makeRequest = async () => { class="cursor-pointer q-mr-sm" @click="openInputFile()" > - {{ diff --git a/src/components/common/VnAccountNumber.vue b/src/components/common/VnAccountNumber.vue index 8bff3e261..5bce49459 100644 --- a/src/components/common/VnAccountNumber.vue +++ b/src/components/common/VnAccountNumber.vue @@ -8,7 +8,8 @@ const model = defineModel({ prop: 'modelValue' }); diff --git a/src/components/common/VnInputDateTime.vue b/src/components/common/VnInputDateTime.vue new file mode 100644 index 000000000..b239d528a --- /dev/null +++ b/src/components/common/VnInputDateTime.vue @@ -0,0 +1,79 @@ + + + + + es: + Open date: Abrir fecha + diff --git a/src/components/common/__tests__/VnInputDateTime.spec.js b/src/components/common/__tests__/VnInputDateTime.spec.js new file mode 100644 index 000000000..23132d77d --- /dev/null +++ b/src/components/common/__tests__/VnInputDateTime.spec.js @@ -0,0 +1,81 @@ +import { createWrapper } from 'app/test/vitest/helper.js'; +import { describe, it, expect, beforeAll } from 'vitest'; +import VnInputDateTime from 'components/common/VnInputDateTime.vue'; +import vnDateBoot from 'src/boot/vnDate'; + +let vm; +let wrapper; + +beforeAll(() => { + // Initialize the vnDate boot + vnDateBoot(); +}); +function generateWrapper(date, outlined, showEvent) { + wrapper = createWrapper(VnInputDateTime, { + props: { + modelValue: date, + isOutlined: outlined, + showEvent: showEvent, + }, + }); + wrapper = wrapper.wrapper; + vm = wrapper.vm; +} + +describe('VnInputDateTime', () => { + describe('selectedDate', () => { + it('formats a valid datetime correctly', async () => { + generateWrapper('2023-12-25T10:30:00', false, true); + await vm.$nextTick(); + expect(vm.selectedDate).toBe('25-12-2023 10:30'); + }); + + it('handles null date value', async () => { + generateWrapper(null, false, true); + await vm.$nextTick(); + expect(vm.selectedDate).toBeInstanceOf(Date); + }); + + it('updates the model value when a new datetime is set', async () => { + vm.selectedDate = '31-12-2023 15:45'; + await vm.$nextTick(); + expect(wrapper.emitted()['update:modelValue']).toBeTruthy(); + }); + }); + + describe('styleAttrs', () => { + it('should return empty styleAttrs when isOutlined is false', async () => { + generateWrapper('2023-12-25T10:30:00', false, true); + await vm.$nextTick(); + expect(vm.styleAttrs).toEqual({}); + }); + + it('should set styleAttrs when isOutlined is true', async () => { + generateWrapper('2023-12-25T10:30:00', true, true); + await vm.$nextTick(); + expect(vm.styleAttrs).toEqual({ + dense: true, + outlined: true, + rounded: true, + }); + }); + }); + + describe('component rendering', () => { + it('should render date and time icons', async () => { + generateWrapper('2023-12-25T10:30:00', false, true); + await vm.$nextTick(); + const icons = wrapper.findAllComponents({ name: 'QIcon' }); + expect(icons.length).toBe(2); + expect(icons[0].props('name')).toBe('today'); + expect(icons[1].props('name')).toBe('access_time'); + }); + + it('should render popup proxies for date and time', async () => { + generateWrapper('2023-12-25T10:30:00', false, true); + await vm.$nextTick(); + const popups = wrapper.findAllComponents({ name: 'QPopupProxy' }); + expect(popups.length).toBe(2); + }); + }); +}); diff --git a/src/components/ui/EntityDescriptor.vue b/src/components/ui/EntityDescriptor.vue index a5dced551..e6adaa5f7 100644 --- a/src/components/ui/EntityDescriptor.vue +++ b/src/components/ui/EntityDescriptor.vue @@ -44,7 +44,8 @@ onBeforeMount(async () => { }); // It enables to load data only once if the module is the same as the dataKey - if (!isSameDataKey.value || !route.params.id) await getData(); + if (!isSameDataKey.value || !route.params.id || $props.id !== route.params.id) + await getData(); watch( () => [$props.url, $props.filter], async () => { @@ -58,7 +59,8 @@ async function getData() { store.filter = $props.filter ?? {}; isLoading.value = true; try { - const { data } = await arrayData.fetch({ append: false, updateRouter: false }); + await arrayData.fetch({ append: false, updateRouter: false }); + const { data } = store; state.set($props.dataKey, data); emit('onFetch', data); } finally { diff --git a/src/i18n/locale/en.yml b/src/i18n/locale/en.yml index 8d18cf648..de5a27ff2 100644 --- a/src/i18n/locale/en.yml +++ b/src/i18n/locale/en.yml @@ -20,6 +20,7 @@ globals: logOut: Log out date: Date dataSaved: Data saved + openDetail: Open detail dataDeleted: Data deleted delete: Delete search: Search diff --git a/src/i18n/locale/es.yml b/src/i18n/locale/es.yml index 7822d8b80..84ba150c4 100644 --- a/src/i18n/locale/es.yml +++ b/src/i18n/locale/es.yml @@ -21,10 +21,11 @@ globals: date: Fecha dataSaved: Datos guardados dataDeleted: Datos eliminados + dataCreated: Datos creados + openDetail: Ver detalle delete: Eliminar search: Buscar changes: Cambios - dataCreated: Datos creados add: Añadir create: Crear edit: Modificar diff --git a/src/pages/Item/components/ItemProposal.vue b/src/pages/Item/components/ItemProposal.vue index edff4f394..bd0fdc0c2 100644 --- a/src/pages/Item/components/ItemProposal.vue +++ b/src/pages/Item/components/ItemProposal.vue @@ -6,10 +6,12 @@ import { toCurrency } from 'filters/index'; import VnStockValueDisplay from 'src/components/ui/VnStockValueDisplay.vue'; import VnTable from 'src/components/VnTable/VnTable.vue'; import axios from 'axios'; -import notifyResults from 'src/utils/notifyResults'; +import { displayResults } from 'src/pages/Ticket/Negative/composables/notifyResults'; import FetchData from 'components/FetchData.vue'; +import { useState } from 'src/composables/useState'; const MATCH = 'match'; +const { notifyResults } = displayResults(); const { t } = useI18n(); const $props = defineProps({ @@ -18,14 +20,20 @@ const $props = defineProps({ required: true, default: () => {}, }, + filter: { + type: Object, + required: true, + default: () => {}, + }, replaceAction: { type: Boolean, - required: false, + required: true, default: false, }, + sales: { type: Array, - required: false, + required: true, default: () => [], }, }); @@ -36,6 +44,8 @@ const proposalTableRef = ref(null); const sale = computed(() => $props.sales[0]); const saleFk = computed(() => sale.value.saleFk); const filter = computed(() => ({ + where: $props.filter, + itemFk: $props.itemLack.itemFk, sales: saleFk.value, })); diff --git a/src/pages/Item/components/ItemProposalProxy.vue b/src/pages/Item/components/ItemProposalProxy.vue index 7da0ce398..27edd3670 100644 --- a/src/pages/Item/components/ItemProposalProxy.vue +++ b/src/pages/Item/components/ItemProposalProxy.vue @@ -1,13 +1,17 @@ diff --git a/src/pages/Ticket/Card/TicketDescriptorMenu.vue b/src/pages/Ticket/Card/TicketDescriptorMenu.vue index f7389b592..30024fb26 100644 --- a/src/pages/Ticket/Card/TicketDescriptorMenu.vue +++ b/src/pages/Ticket/Card/TicketDescriptorMenu.vue @@ -28,6 +28,7 @@ const props = defineProps({ onMounted(() => { restoreTicket(); + hasDocuware(); }); watch( diff --git a/src/pages/Ticket/Card/TicketDescriptorProxy.vue b/src/pages/Ticket/Card/TicketDescriptorProxy.vue index ba8367e81..8b872733d 100644 --- a/src/pages/Ticket/Card/TicketDescriptorProxy.vue +++ b/src/pages/Ticket/Card/TicketDescriptorProxy.vue @@ -1,7 +1,6 @@