diff --git a/CHANGELOG.md b/CHANGELOG.md index 6908d764a..a7797f810 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,82 @@ +# Version 25.00 - 2025-01-14 + +### Added 🆕 + +- chore: refs #7056 move test by:jorgep +- feat: refs #7050 7050 add object check by:Jtubau +- feat: refs #7050 7050 add test to isEmpty() by:Jtubau +- feat: refs #7056 add tests in FormModel by:jorgep +- feat: refs #7056 update route meta information and add FormModel tests by:jorgep +- feat: refs #7074 tests for fns setData(), parseDms() and showFormDialog() (7074-makeFrontTestToVnDmsList) by:Jtubau +- feat: refs #7079 created VnLocation front test by:provira +- feat: refs #7189 add Accept-Language header to axios requests by:jorgep +- feat: refs #7924 add custom inspection checkbox and localization support by:jgallego +- feat: refs #7924 update custom inspection label for clarity in English and Spanish locales by:jgallego +- feat: refs #8004 enhance FetchedTags component with column support and styling updates by:pablone +- feat: refs #8004 hide rightFilter by:pablone +- feat: refs #8246 added new field in list by:Jon +- feat: refs #8266 added descriptor to item name by:jtubau +- feat: refs #8293 add zone filter by:Jtubau +- feat: refs #8293 include zone data in each record by:Jtubau +- fix: refs #8004 more list style issues by:pablone +- fix: refs #8004 some style issues on all list by:pablone +- style: refs #8004 update layout and styling in FetchedTags and ItemList components by:pablone +- style: update CustomerBalance.vue to set label color by:jgallego + +### Changed 📦 + +- perf: order by:alexm +- perf: redirect transition list to card by:alexm +- perf: refs #8201 onDataSaved fetch by:Jon +- perf: revert processData by:alexm +- perf: simplify if by:alexm +- perf: simplify if (perf_redirectTransition) by:alexm +- refactor: item fixedPrice by:Jon +- refactor: refs #7050 refactorize by:jtubau +- refactor: refs #7050 removed blank spaces by:jtubau +- refactor: refs #7052 move EditTableCellValueForm tests to a new location and enhance test coverage by:jgallego +- refactor: refs #7052 remove unnecessary console logs from EditTableCellValueForm tests by:jgallego +- refactor: refs #7074 move dms constant to global scope by:Jtubau +- refactor: refs #7079 removed useless code by:provira +- refactor: refs #7924 simplify custom inspection icon rendering in ExtraCommunity.vue by:jgallego +- refactor: refs #8004 remove console log from CardSummary component on mount by:pablone +- refactor: refs #8004 remove consoleLogs by:pablone +- refactor: refs #8004 remove unused stateStore import in InvoiceInList.vue by:pablone +- refactor: refs #8004 remove unused travelFilterRef and chip definition in TravelList.vue by:pablone +- refactor: refs #8004 replace VnSelect with VnSelectWorker in CustomerList component by:pablone +- refactor: refs #8201 added onMounted to stablish the value to show icons by:Jon +- refactor: refs #8201 deleted condition by:Jon +- refactor: refs #8201 deleted log by:Jon +- refactor: refs #8201 deleted logs by:Jon +- refactor: refs #8266 8266 change expedition item name by:Jtubau +- refactor: refs #8266 change expedition label by:Jtubau +- refactor: refs #8293 remove redundant attributes by:Jtubau +- refactor: refs #8320 changed folder names from "specs" to "**tests**" by:provira +- refactor: refs #8320 moved front tests to their respective sections by:provira +- refactor: refs #8813 removed unused class property by:provira + +### Fixed 🛠️ + +- fix: discount class by:PAU ROVIRA ROSALENY +- fix: duplicate transalation after test to dev by:alexm +- fix: fix translations by:carlossa +- fix: redirect to sales when confirming lines by:Jon +- fix: refs #7050 delete import added by mistake by:Jtubau +- fix: refs #7133 handleSalesModelValue function to handle empty input by:jorgep +- fix: refs #7189 update user language on sessionStorage by:jorgep +- fix: refs #7935 remove unused 'companyFk' column from InvoiceInList component by:jorgep +- fix: refs #8004 more list style issues by:pablone +- fix: refs #8004 some style issues on all list by:pablone +- fix: refs #8004 update label for daysOnward in TravelFilter component and add translations by:pablone +- fix: refs #8004 vnTable card with and add permanent labels by:pablone +- fix: refs #8201 added onDataSaved emi to refetch when cahnges are made by:Jon +- fix: refs #8201 use arrayData to fix the error by:Jon +- fix: refs #8314 space between label and value by:jtubau +- fix: refs #8813 fixed ClaimLines format by:provira +- fix: update button sizes in ExtraCommunity.vue for better visibility by:jgallego +- perf: revert processData by:alexm +- refactor: item fixedPrice by:Jon + # Version 24.52 - 2024-01-07 ### Added 🆕 diff --git a/src/boot/qformMixin.js b/src/boot/qformMixin.js index 187ca6dbc..97d80c670 100644 --- a/src/boot/qformMixin.js +++ b/src/boot/qformMixin.js @@ -31,7 +31,7 @@ export default { console.error(error); } form.addEventListener('keyup', function (evt) { - if (evt.key === 'Enter') { + if (evt.key === 'Enter' && !that.$attrs['prevent-submit']) { const input = evt.target; if (input.type == 'textarea' && evt.shiftKey) { evt.preventDefault(); diff --git a/src/components/__tests__/FilterItemForm.spec.js b/src/components/__tests__/FilterItemForm.spec.js new file mode 100644 index 000000000..210d6bf02 --- /dev/null +++ b/src/components/__tests__/FilterItemForm.spec.js @@ -0,0 +1,82 @@ +import { createWrapper, axios } from 'app/test/vitest/helper'; +import FilterItemForm from 'src/components/FilterItemForm.vue'; +import { vi, beforeAll, describe, expect, it } from 'vitest'; + +describe('FilterItemForm', () => { + let vm; + let wrapper; + + beforeAll(() => { + wrapper = createWrapper(FilterItemForm, { + props: { + url: 'Items/withName', + }, + }); + vm = wrapper.vm; + wrapper = wrapper.wrapper; + + vi.spyOn(axios, 'get').mockResolvedValue({ + data: [ + { + id: 999996, + name: 'bolas de madera', + size: 2, + inkFk: null, + producerFk: null, + }, + ], + }); + }); + + it('should filter data and populate tableRows for table display', async () => { + vm.itemFilterParams.name = 'bolas de madera'; + + await vm.onSubmit(); + + const expectedFilter = { + include: [ + { relation: 'producer', scope: { fields: ['name'] } }, + { relation: 'ink', scope: { fields: ['name'] } }, + ], + where: {"name":{"like":"%bolas de madera%"}}, + }; + + expect(axios.get).toHaveBeenCalledWith('Items/withName', { + params: { filter: JSON.stringify(expectedFilter) }, + }); + + expect(vm.tableRows).toEqual([ + { + id: 999996, + name: 'bolas de madera', + size: 2, + inkFk: null, + producerFk: null, + }, + ]); + }); + + it('should handle an empty itemFilterParams correctly', async () => { + vm.itemFilterParams.name = null; + vm.itemFilterParams = {}; + + await vm.onSubmit(); + + const expectedFilter = { + include: [ + { relation: 'producer', scope: { fields: ['name'] } }, + { relation: 'ink', scope: { fields: ['name'] } }, + ], + where: {}, + }; + + expect(axios.get).toHaveBeenCalledWith('Items/withName', { + params: { filter: JSON.stringify(expectedFilter) }, + }); + }); + + it('should emit "itemSelected" with the correct id and close the form', () => { + vm.selectItem({ id: 12345 }); + expect(wrapper.emitted('itemSelected')[0]).toEqual([12345]); + }); +}); \ No newline at end of file diff --git a/src/components/common/VnLocation.vue b/src/components/common/VnLocation.vue index f58222187..3ede24274 100644 --- a/src/components/common/VnLocation.vue +++ b/src/components/common/VnLocation.vue @@ -2,7 +2,7 @@ import CreateNewPostcode from 'src/components/CreateNewPostcodeForm.vue'; import VnSelectDialog from 'components/common/VnSelectDialog.vue'; import { useI18n } from 'vue-i18n'; -import { computed } from 'vue'; +import { ref, watch } from 'vue'; import { useAttrs } from 'vue'; import { useRequired } from 'src/composables/useRequired'; const { t } = useI18n(); @@ -16,6 +16,14 @@ const props = defineProps({ }, }); +watch( + () => props.location, + (newValue) => { + if (!modelValue.value) return; + modelValue.value = formatLocation(newValue) ?? null; + } +); + const mixinRules = [requiredFieldRule]; const locationProperties = [ 'postcode', @@ -43,9 +51,7 @@ const formatLocation = (obj, properties = locationProperties) => { return filteredParts.join(', '); }; -const modelValue = computed(() => - props.location ? formatLocation(props.location, locationProperties) : null -); +const modelValue = ref(props.location ? formatLocation(props.location) : null); function showLabel(data) { const dataProperties = [ diff --git a/src/components/common/__tests__/VnInputDate.spec.js b/src/components/common/__tests__/VnInputDate.spec.js new file mode 100644 index 000000000..21ca91e96 --- /dev/null +++ b/src/components/common/__tests__/VnInputDate.spec.js @@ -0,0 +1,72 @@ +import { createWrapper } from 'app/test/vitest/helper.js'; +import { describe, it, expect } from 'vitest'; +import VnInputDate from 'components/common/VnInputDate.vue'; + +let vm; +let wrapper; + +function generateWrapper(date, outlined, required) { + wrapper = createWrapper(VnInputDate, { + props: { + modelValue: date, + }, + attrs: { + isOutlined: outlined, + required: required + }, + }); + wrapper = wrapper.wrapper; + vm = wrapper.vm; +}; + +describe('VnInputDate', () => { + + describe('formattedDate', () => { + it('formats a valid date correctly', async () => { + generateWrapper('2023-12-25', false, false); + await vm.$nextTick(); + expect(vm.formattedDate).toBe('25/12/2023'); + }); + + it('updates the model value when a new date is set', async () => { + const input = wrapper.find('input'); + await input.setValue('31/12/2023'); + expect(wrapper.emitted()['update:modelValue']).toBeTruthy(); + expect(wrapper.emitted()['update:modelValue'][0][0]).toBe('2023-12-31T00:00:00.000Z'); + }); + + it('should not update the model value when an invalid date is set', async () => { + const input = wrapper.find('input'); + await input.setValue('invalid-date'); + expect(wrapper.emitted()['update:modelValue'][0][0]).toBe('2023-12-31T00:00:00.000Z'); + }); + }); + + describe('styleAttrs', () => { + it('should return empty styleAttrs when isOutlined is false', async () => { + generateWrapper('2023-12-25', false, false); + await vm.$nextTick(); + expect(vm.styleAttrs).toEqual({}); + }); + + it('should set styleAttrs when isOutlined is true', async () => { + generateWrapper('2023-12-25', true, false); + await vm.$nextTick(); + expect(vm.styleAttrs.outlined).toBe(true); + }); + }); + + describe('required', () => { + it('should not applies required class when isRequired is false', async () => { + generateWrapper('2023-12-25', false, false); + await vm.$nextTick(); + expect(wrapper.find('.vn-input-date').classes()).not.toContain('required'); + }); + + it('should applies required class when isRequired is true', async () => { + generateWrapper('2023-12-25', false, true); + await vm.$nextTick(); + expect(wrapper.find('.vn-input-date').classes()).toContain('required'); + }); + }); +}); \ No newline at end of file diff --git a/src/components/ui/CardSummary.vue b/src/components/ui/CardSummary.vue index 52427f3fe..a1de3eee3 100644 --- a/src/components/ui/CardSummary.vue +++ b/src/components/ui/CardSummary.vue @@ -82,7 +82,7 @@ async function fetch() { - + {{ entity.id + ' - ' + entity.name }} diff --git a/src/components/ui/VnLinkPhone.vue b/src/components/ui/VnLinkPhone.vue index c5d5df394..a9e9bc0fc 100644 --- a/src/components/ui/VnLinkPhone.vue +++ b/src/components/ui/VnLinkPhone.vue @@ -30,7 +30,7 @@ onBeforeMount(async () => { .data; if (!channel) channel = defaultChannel; - phone.value = await parsePhone(props.phoneNumber, props.country.toLowerCase()); + phone.value = await parsePhone(props.phoneNumber, props.country?.toLowerCase()); config[ type ].url = `${url}?customerIdentity=%2B${phone.value}&channelId=${channel}`; diff --git a/src/pages/Customer/Card/CustomerDescriptor.vue b/src/pages/Customer/Card/CustomerDescriptor.vue index dc5f08d37..cb49109d0 100644 --- a/src/pages/Customer/Card/CustomerDescriptor.vue +++ b/src/pages/Customer/Card/CustomerDescriptor.vue @@ -1,5 +1,5 @@ @@ -97,26 +92,21 @@ const debtWarning = computed(() => { :value="entity.businessType.description" /> - diff --git a/src/pages/InvoiceIn/locale/en.yml b/src/pages/InvoiceIn/locale/en.yml index 2d1458290..94db50066 100644 --- a/src/pages/InvoiceIn/locale/en.yml +++ b/src/pages/InvoiceIn/locale/en.yml @@ -1,4 +1,4 @@ -InvoiceIn: +invoicein: serial: Serial isBooked: Is booked list: @@ -66,7 +66,6 @@ InvoiceIn: search: Id or supplier name correctedFk: Corrected isBooked: Is booked -invoicein: - params: account: Ledger account correctingFk: Rectificative + \ No newline at end of file diff --git a/src/pages/InvoiceIn/locale/es.yml b/src/pages/InvoiceIn/locale/es.yml index e6b323a73..bcb9c0551 100644 --- a/src/pages/InvoiceIn/locale/es.yml +++ b/src/pages/InvoiceIn/locale/es.yml @@ -1,4 +1,4 @@ -InvoiceIn: +invoicein: serial: Serie isBooked: Contabilizada list: @@ -63,7 +63,6 @@ InvoiceIn: params: search: Id o nombre proveedor correctedFk: Rectificada -invoicein: - params: account: Cuenta contable correctingFk: Rectificativa + diff --git a/src/pages/InvoiceOut/InvoiceOutList.vue b/src/pages/InvoiceOut/InvoiceOutList.vue index 48d61201c..09873642d 100644 --- a/src/pages/InvoiceOut/InvoiceOutList.vue +++ b/src/pages/InvoiceOut/InvoiceOutList.vue @@ -355,7 +355,7 @@ watchEffect(selectedRows); ({ @@ -23,16 +30,11 @@ export const useInvoiceOutGlobalStore = defineStore({ addresses: [], minInvoicingDate: null, parallelism: null, - invoicing: false, - isInvoicing: false, status: null, - addressIndex: 0, - errors: [], + printer: null, - nRequests: 0, - nPdfs: 0, - totalPdfs: 0, formData: null, + ...initInvoicing, }), actions: { async init() { @@ -117,12 +119,13 @@ export const useInvoiceOutGlobalStore = defineStore({ ); throw new Error("There aren't addresses to invoice"); } - this.invoicing = false; - this.status = 'invoicing'; this.formData = formData; - this.addressIndex = 0; - this.errors = []; - await this.invoiceClient(); + this.status = 'invoicing'; + //reset data + for (const key in initInvoicing) { + this[key] = initInvoicing[key]; + } + this.invoiceClient(); } catch (err) { this.handleError(err); } @@ -184,7 +187,6 @@ export const useInvoiceOutGlobalStore = defineStore({ async invoiceClient() { if (this.invoicing || this.nRequests >= this.parallelism) return; const address = this.addresses[this.addressIndex]; - if (!address || !this.status || this.status == 'stopping') { this.status = 'stopping'; this.invoicing = false; @@ -192,6 +194,7 @@ export const useInvoiceOutGlobalStore = defineStore({ } try { this.invoicing = true; + this.nRequests++; const params = { clientId: address.clientId, addressId: address.id, @@ -215,6 +218,7 @@ export const useInvoiceOutGlobalStore = defineStore({ } } finally { this.invoicing = false; + this.nRequests--; this.addressIndex++; this.invoiceClient(); }