test: fix test ticketLackDetail

This commit is contained in:
Javier Segarra 2025-05-19 11:22:55 +02:00
parent e6e4588d7c
commit a677abf35b
5 changed files with 76 additions and 84 deletions

View File

@ -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 {
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 }) => {
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, 'saleFk');
notifyResults(results, 'ticketFk');
emit('itemReplaced', {
...body,
type: 'refresh',
itemProposal: proposalSelected.value[0],
});
proposalSelected.value = [];
} catch (error) {
console.error(error);
}
}
async function handleTicketConfig(data) {
@ -299,7 +288,8 @@ function filterRows(data) {
url="TicketConfigs"
:filter="{ fields: ['lackAlertPrice'] }"
@on-fetch="handleTicketConfig"
></FetchData>
auto-load
/>
<QInnerLoading
:showing="isLoading"
:label="t && t('globals.pleaseWait')"
@ -403,30 +393,19 @@ function filterRows(data) {
margin-right: 2px;
flex: 2 0 5px;
}
/* Removed old .match / .not-match specific to price */
/* .match {
color: $negative;
}
.not-match {
color: inherit;
} */
/* Added classes for price status */
.price-alert {
color: $negative; /* Alert text color */
color: $negative;
&.q-tooltip {
background-color: $negative; /* Alert tooltip background */
color: white; /* Ensure tooltip text is readable */
background-color: $negative;
color: white;
}
}
.price-ok {
color: inherit; /* Default text color */
color: inherit;
&.q-tooltip {
/* Keep default tooltip background or set a specific 'ok' color */
background-color: $positive; /* Example: green background for OK price */
color: white; /* Ensure tooltip text is readable */
background-color: $positive;
color: white;
}
}
@ -453,3 +432,9 @@ function filterRows(data) {
font-size: smaller;
}
</style>
<i18n>
en:
notAvailable: 'Not available for replacement'
es:
notAvailable: 'No disponible para reemplazo'
</i18n>

View File

@ -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,

View File

@ -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;
}
};

View File

@ -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`, {

View File

@ -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();
});
});
});