diff --git a/src/pages/Item/components/ItemProposal.vue b/src/pages/Item/components/ItemProposal.vue index d59a18400..30f050097 100644 --- a/src/pages/Item/components/ItemProposal.vue +++ b/src/pages/Item/components/ItemProposal.vue @@ -8,10 +8,11 @@ import VnTable from 'src/components/VnTable/VnTable.vue'; import axios from 'axios'; import { displayResults } from 'src/pages/Ticket/Negative/composables/notifyResults'; import FetchData from 'components/FetchData.vue'; -import { useState } from 'src/composables/useState'; +import useNotify from 'src/composables/useNotify.js'; const MATCH = 'match'; const { notifyResults } = displayResults(); +const { notify } = useNotify(); const { t } = useI18n(); const $props = defineProps({ @@ -233,54 +234,42 @@ const statusConditionalValue = (row) => { const isSelectionAvailable = (itemProposal) => { const { price2, available } = itemProposal; - const originalPrice = sale.value?.price; - const lackQuantity = $props.itemLack?.lack; - - if ( - !originalPrice || - !lackQuantity || - !ticketConfig.value || - typeof ticketConfig.value.lackAlertPrice !== 'number' - ) { - return false; - } - - const priceIncreasePercentage = ((price2 - originalPrice) / originalPrice) * 100; - const isPriceTooHigh = priceIncreasePercentage > ticketConfig.value.lackAlertPrice; - + const salePrice = sale.value.price; + const { lackAlertPrice } = ticketConfig.value; + const isPriceTooHigh = (100 * price2) / salePrice > lackAlertPrice; if (isPriceTooHigh) { - return false; + return isPriceTooHigh; } - - const availablePercentage = (available / Math.abs(lackQuantity)) * 100; - const hasEnoughQuantity = availablePercentage >= ticketConfig.value.lackAlertPrice; - + const hasEnoughQuantity = + (100 * available) / Math.abs($props.itemLack.lack) < lackAlertPrice; return hasEnoughQuantity; }; -async function change({ itemFk: substitutionFk }) { - try { - let body; - const promises = $props.sales.map(({ saleFk, quantity }) => { - body = { - saleFk, - substitutionFk, - quantity, - }; - return axios.post('Sales/replaceItem', body); - }); - const results = await Promise.allSettled(promises); - - notifyResults(results, 'saleFk'); - emit('itemReplaced', { - ...body, - type: 'refresh', - itemProposal: proposalSelected.value[0], - }); - proposalSelected.value = []; - } catch (error) { - console.error(error); +async function change(itemSubstitution) { + if (!isSelectionAvailable(itemSubstitution)) { + notify(t('notAvailable'), 'warning'); + return; } + const { itemFk: substitutionFk } = itemSubstitution; + let body; + const promises = $props.sales.map(({ saleFk, quantity, ticketFk }) => { + body = { + saleFk, + substitutionFk, + quantity, + ticketFk, + }; + return axios.post('Sales/replaceItem', body); + }); + const results = await Promise.allSettled(promises); + + notifyResults(results, 'ticketFk'); + emit('itemReplaced', { + ...body, + type: 'refresh', + itemProposal: proposalSelected.value[0], + }); + proposalSelected.value = []; } async function handleTicketConfig(data) { @@ -299,7 +288,8 @@ function filterRows(data) { url="TicketConfigs" :filter="{ fields: ['lackAlertPrice'] }" @on-fetch="handleTicketConfig" - > + auto-load + /> + +en: + notAvailable: 'Not available for replacement' +es: + notAvailable: 'No disponible para reemplazo' + diff --git a/src/pages/Ticket/Negative/TicketLackTable.vue b/src/pages/Ticket/Negative/TicketLackTable.vue index 67758191f..8ce3291a2 100644 --- a/src/pages/Ticket/Negative/TicketLackTable.vue +++ b/src/pages/Ticket/Negative/TicketLackTable.vue @@ -139,7 +139,6 @@ const saveChange = async (field, { row }) => { const { id: code } = editableStates.value.find( ({ name }) => name === row.code, ); - debugger; await axios.post(`Tickets/state`, { ticketFk: row.ticketFk, code, diff --git a/src/pages/Ticket/Negative/components/ChangeItemDialog.vue b/src/pages/Ticket/Negative/components/ChangeItemDialog.vue index 4238bcc37..f34a13c26 100644 --- a/src/pages/Ticket/Negative/components/ChangeItemDialog.vue +++ b/src/pages/Ticket/Negative/components/ChangeItemDialog.vue @@ -19,18 +19,18 @@ const $props = defineProps({ const updateItem = async () => { try { showChangeItemDialog.value = true; - const rowsToUpdate = $props.selectedRows.map(({ saleFk, quantity }) => + const rowsToUpdate = $props.selectedRows.map(({ saleFk, ticketFk, quantity }) => axios.post(`Sales/replaceItem`, { saleFk, + ticketFk, substitutionFk: newItem.value, quantity, }), ); const result = await Promise.allSettled(rowsToUpdate); - notifyResults(result, 'saleFk'); + notifyResults(result, 'ticketFk'); emit('update-item', newItem.value); } catch (err) { - console.error('Error updating item:', err); return err; } }; diff --git a/src/pages/Ticket/Negative/components/ChangeStateDialog.vue b/src/pages/Ticket/Negative/components/ChangeStateDialog.vue index 8aac08fe3..b615a0d2f 100644 --- a/src/pages/Ticket/Negative/components/ChangeStateDialog.vue +++ b/src/pages/Ticket/Negative/components/ChangeStateDialog.vue @@ -18,7 +18,6 @@ const $props = defineProps({ }); const updateState = async () => { try { - debugger; showChangeStateDialog.value = true; const rowsToUpdate = $props.selectedRows.map(({ ticketFk }) => axios.post(`Tickets/state`, { diff --git a/test/cypress/integration/ticket/negative/TicketLackDetail.spec.js b/test/cypress/integration/ticket/negative/TicketLackDetail.spec.js index 948b1fc08..0aa4b4fc2 100644 --- a/test/cypress/integration/ticket/negative/TicketLackDetail.spec.js +++ b/test/cypress/integration/ticket/negative/TicketLackDetail.spec.js @@ -5,8 +5,13 @@ const clickNotificationAction = () => { const notification = '.q-notification'; cy.waitForElement(notification); cy.get(notification).should('be.visible'); - cy.get(notification).find('.q-btn').click(); - cy.get(notification).should('not.be.visible'); + cy.get('.q-notification__actions > .q-btn').click(); + cy.get('@open').should((openStub) => { + expect(openStub).to.be.called; + const firstArg = openStub.args[0][0]; + expect(firstArg).to.match(/\/ticket\/\d+\/sale/); + expect(firstArg).to.include(`/ticket/${ticketId}/sale`); + }); }; describe('Ticket Lack detail', { testIsolation: true }, () => { beforeEach(() => { @@ -14,7 +19,9 @@ describe('Ticket Lack detail', { testIsolation: true }, () => { cy.login('developer'); cy.intercept('GET', /\/api\/Tickets\/itemLack\/88.*$/).as('getItemLack'); cy.visit('/#/ticket/negative/88'); - + cy.window().then((win) => { + cy.stub(win, 'open').as('open'); + }); cy.wait('@getItemLack').then((interception) => { const { query } = interception.request; const filter = JSON.parse(query.filter); @@ -96,10 +103,9 @@ describe('Ticket Lack detail', { testIsolation: true }, () => { }); it('by popup', () => { cy.dataCy('New item_select').should('be.visible'); - cy.selectOption('[data-cy="New item_select"]', 'Palito rojo'); cy.get('.q-btn--unelevated > .q-btn__content > .block').click(); - cy.checkNotification('Ticket 43: price retrieval failed'); + cy.checkNotification('Ticket 1000000: price retrieval failed'); cy.dataCy('changeItem').click(); cy.selectOption('[data-cy="New item_select"]', 'Ranged weapon longbow 200cm'); cy.get('.q-btn--unelevated > .q-btn__content > .block').click(); @@ -109,16 +115,18 @@ describe('Ticket Lack detail', { testIsolation: true }, () => { after(() => { cy.visit(`/#/ticket/${ticketId}/sale`); const quantity = Math.floor(Math.random() * 100) + 1; - + const rowIndex = 1; cy.dataCy('ticketSaleQuantityInput') .find('input') - .eq(1) + .eq(rowIndex) + .clear() .type(quantity) .trigger('tab'); cy.get('.q-page > :nth-child(6)').click(); - cy.get('[data-cy="ticketSaleQuantityInput"]') + cy.dataCy('ticketSaleQuantityInput') .find('input') + .eq(rowIndex) .should('have.value', `${quantity}`); }); }); @@ -129,25 +137,26 @@ describe('Ticket Lack detail', { testIsolation: true }, () => { cy.dataCy('itemProposal').click(); }); describe('Replace item if', () => { - it.skip('Quantity is less than available', () => { - cy.get(':nth-child(1) > .text-right > .q-btn').click(); + it('Quantity is less than available', () => { + const index = 2; + cy.colField('tag7', index).click(); + cy.checkNotification('Not available for replacement'); }); it('item proposal cells', () => { - cy.get('[data-col-field="longName"] .link').first().click(); - - cy.dataCy('ItemDescriptor').should('be.visible'); - - cy.colField('longName', 2) + const index = 1; + cy.colField('longName', index) .find('.no-padding > .q-td > .middle') .should('have.class', 'proposal-primary'); - cy.colField('tag5', 2) + cy.colField('tag5', index) .find('.no-padding > .match') .should('have.class', 'match'); - cy.colField('tag6', 2) + cy.colField('tag6', index) .find('.no-padding > .match') .should('have.class', 'match'); - cy.colField('tag7', 2).click(); + cy.colField('tag7', index).click(); + + clickNotificationAction(); }); }); });