3430-ticket_step-two ticket without negatives #823
|
@ -0,0 +1,43 @@
|
||||||
|
DROP PROCEDURE IF EXISTS `vn`.`ticket_getMovable`;
|
||||||
|
|
||||||
|
DELIMITER $$
|
||||||
|
$$
|
||||||
|
CREATE DEFINER=`root`@`%` PROCEDURE `vn`.`ticket_getMovable`(vTicketFk INT, vDatedNew DATETIME, vWarehouseFk INT)
|
||||||
|
BEGIN
|
||||||
|
/**
|
||||||
|
* Cálcula el stock movible para los artículos de un ticket
|
||||||
|
*
|
||||||
|
* @param vTicketFk -> Ticket
|
||||||
|
* @param vDatedNew -> Nueva fecha
|
||||||
|
* @return Sales con Movible
|
||||||
|
*/
|
||||||
|
DECLARE vDatedOld DATETIME;
|
||||||
|
|
||||||
|
SELECT t.shipped INTO vDatedOld
|
||||||
|
FROM ticket t
|
||||||
|
WHERE t.id = vTicketFk;
|
||||||
|
|
||||||
|
CALL itemStock(vWarehouseFk, DATE_SUB(vDatedNew, INTERVAL 1 DAY), NULL);
|
||||||
|
CALL item_getMinacum(vWarehouseFk, vDatedNew, DATEDIFF(vDatedOld, vDatedNew), NULL);
|
||||||
|
|
||||||
|
SELECT s.id,
|
||||||
|
s.itemFk,
|
||||||
|
s.quantity,
|
||||||
|
s.concept,
|
||||||
|
s.price,
|
||||||
|
s.reserved,
|
||||||
|
s.discount,
|
||||||
|
i.image,
|
||||||
|
i.subName,
|
||||||
|
il.stock + IFNULL(im.amount, 0) AS movable
|
||||||
|
FROM ticket t
|
||||||
|
JOIN sale s ON s.ticketFk = t.id
|
||||||
|
JOIN item i ON i.id = s.itemFk
|
||||||
|
LEFT JOIN tmp.itemMinacum im ON im.itemFk = s.itemFk AND im.warehouseFk = vWarehouseFk
|
||||||
|
LEFT JOIN tmp.itemList il ON il.itemFk = s.itemFk
|
||||||
|
WHERE t.id = vTicketFk;
|
||||||
|
|
||||||
|
DROP TEMPORARY TABLE IF EXISTS tmp.itemList;
|
||||||
|
DROP TEMPORARY TABLE IF EXISTS tmp.itemMinacum;
|
||||||
|
END$$
|
||||||
|
DELIMITER ;
|
|
@ -625,6 +625,7 @@ INSERT INTO `vn`.`ticket`(`id`, `priority`, `agencyModeFk`,`warehouseFk`,`routeF
|
||||||
(25 ,NULL, 8, 1, NULL, CURDATE(), CURDATE(), 1101, 'Bruce Wayne', 1, NULL, 0, 1, 5, 1, CURDATE()),
|
(25 ,NULL, 8, 1, NULL, CURDATE(), CURDATE(), 1101, 'Bruce Wayne', 1, NULL, 0, 1, 5, 1, CURDATE()),
|
||||||
(26 ,NULL, 8, 1, NULL, CURDATE(), CURDATE(), 1101, 'An incredibly long alias for testing purposes', 1, NULL, 0, 1, 5, 1, CURDATE()),
|
(26 ,NULL, 8, 1, NULL, CURDATE(), CURDATE(), 1101, 'An incredibly long alias for testing purposes', 1, NULL, 0, 1, 5, 1, CURDATE()),
|
||||||
(27 ,NULL, 8, 1, NULL, CURDATE(), CURDATE(), 1101, 'Wolverine', 1, NULL, 0, 1, 5, 1, CURDATE());
|
(27 ,NULL, 8, 1, NULL, CURDATE(), CURDATE(), 1101, 'Wolverine', 1, NULL, 0, 1, 5, 1, CURDATE());
|
||||||
|
|
||||||
INSERT INTO `vn`.`ticketObservation`(`id`, `ticketFk`, `observationTypeFk`, `description`)
|
INSERT INTO `vn`.`ticketObservation`(`id`, `ticketFk`, `observationTypeFk`, `description`)
|
||||||
VALUES
|
VALUES
|
||||||
(1, 11, 1, 'ready'),
|
(1, 11, 1, 'ready'),
|
||||||
|
@ -899,7 +900,8 @@ INSERT INTO `vn`.`sale`(`id`, `itemFk`, `ticketFk`, `concept`, `quantity`, `pric
|
||||||
(29, 4, 17, 'Melee weapon heavy shield 1x0.5m', 20, 1.72, 0, 0, 0, CURDATE()),
|
(29, 4, 17, 'Melee weapon heavy shield 1x0.5m', 20, 1.72, 0, 0, 0, CURDATE()),
|
||||||
(30, 4, 18, 'Melee weapon heavy shield 1x0.5m', 20, 1.72, 0, 0, 0, CURDATE()),
|
(30, 4, 18, 'Melee weapon heavy shield 1x0.5m', 20, 1.72, 0, 0, 0, CURDATE()),
|
||||||
(31, 2, 23, 'Melee weapon combat fist 15cm', -5, 7.08, 0, 0, 0, CURDATE()),
|
(31, 2, 23, 'Melee weapon combat fist 15cm', -5, 7.08, 0, 0, 0, CURDATE()),
|
||||||
(32, 1, 24, 'Ranged weapon longbow 2m', -1, 8.07, 0, 0, 0, CURDATE());
|
(32, 1, 24, 'Ranged weapon longbow 2m', -1, 8.07, 0, 0, 0, CURDATE()),
|
||||||
|
(33, 5, 14, 'Ranged weapon pistol 9mm', 50, 1.79, 0, 0, 0, CURDATE());
|
||||||
|
|
||||||
INSERT INTO `vn`.`saleChecked`(`saleFk`, `isChecked`)
|
INSERT INTO `vn`.`saleChecked`(`saleFk`, `isChecked`)
|
||||||
VALUES
|
VALUES
|
||||||
|
|
|
@ -526,6 +526,7 @@ export default {
|
||||||
acceptDialog: '.vn-dialog.shown button[response="accept"]',
|
acceptDialog: '.vn-dialog.shown button[response="accept"]',
|
||||||
acceptChangeHourButton: '.vn-dialog.shown button[response="accept"]',
|
acceptChangeHourButton: '.vn-dialog.shown button[response="accept"]',
|
||||||
descriptorDeliveryDate: 'vn-ticket-descriptor slot-body > .attributes > vn-label-value:nth-child(4) > section > span',
|
descriptorDeliveryDate: 'vn-ticket-descriptor slot-body > .attributes > vn-label-value:nth-child(4) > section > span',
|
||||||
|
descriptorDeliveryAgency: 'vn-ticket-descriptor slot-body > .attributes > vn-label-value:nth-child(5) > section > span',
|
||||||
acceptInvoiceOutButton: '.vn-confirm.shown button[response="accept"]',
|
acceptInvoiceOutButton: '.vn-confirm.shown button[response="accept"]',
|
||||||
acceptDeleteStowawayButton: '.vn-dialog.shown button[response="accept"]'
|
acceptDeleteStowawayButton: '.vn-dialog.shown button[response="accept"]'
|
||||||
},
|
},
|
||||||
|
@ -603,10 +604,12 @@ export default {
|
||||||
ticketBasicData: {
|
ticketBasicData: {
|
||||||
agency: 'vn-autocomplete[ng-model="$ctrl.agencyModeId"]',
|
agency: 'vn-autocomplete[ng-model="$ctrl.agencyModeId"]',
|
||||||
zone: 'vn-autocomplete[ng-model="$ctrl.zoneId"]',
|
zone: 'vn-autocomplete[ng-model="$ctrl.zoneId"]',
|
||||||
|
shipped: 'vn-date-picker[ng-model="$ctrl.shipped"]',
|
||||||
nextStepButton: 'vn-step-control .buttons > section:last-child vn-button',
|
nextStepButton: 'vn-step-control .buttons > section:last-child vn-button',
|
||||||
finalizeButton: 'vn-step-control .buttons > section:last-child button[type=submit]',
|
finalizeButton: 'vn-step-control .buttons > section:last-child button[type=submit]',
|
||||||
stepTwoTotalPriceDif: 'vn-ticket-basic-data-step-two > vn-side-menu div:nth-child(4)',
|
stepTwoTotalPriceDif: 'vn-ticket-basic-data-step-two > vn-side-menu div:nth-child(4)',
|
||||||
chargesReason: 'vn-ticket-basic-data-step-two div:nth-child(3) > vn-radio',
|
chargesReason: 'vn-ticket-basic-data-step-two div:nth-child(3) > vn-radio',
|
||||||
|
withoutNegatives: 'vn-check[ng-model="$ctrl.ticket.withoutNegatives"]',
|
||||||
},
|
},
|
||||||
ticketComponents: {
|
ticketComponents: {
|
||||||
base: 'vn-ticket-components > vn-side-menu div:nth-child(1) > div:nth-child(2)'
|
base: 'vn-ticket-components > vn-side-menu div:nth-child(1) > div:nth-child(2)'
|
||||||
|
|
|
@ -83,4 +83,62 @@ describe('Ticket Edit basic data path', () => {
|
||||||
await page.waitToClick(selectors.ticketBasicData.finalizeButton);
|
await page.waitToClick(selectors.ticketBasicData.finalizeButton);
|
||||||
await page.waitForState('ticket.card.summary');
|
await page.waitForState('ticket.card.summary');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it(`should not find ticket`, async() => {
|
||||||
|
await page.doSearch('29');
|
||||||
|
const count = await page.countElement(selectors.ticketsIndex.searchResult);
|
||||||
|
|
||||||
|
expect(count).toEqual(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should split ticket without negatives`, async() => {
|
||||||
|
const newAgency = 'Silla247';
|
||||||
|
const newDate = new Date();
|
||||||
|
newDate.setDate(newDate.getDate() + 1);
|
||||||
|
|
||||||
|
await page.accessToSearchResult('14');
|
||||||
|
await page.accessToSection('ticket.card.basicData.stepOne');
|
||||||
|
|
||||||
|
await page.autocompleteSearch(selectors.ticketBasicData.agency, newAgency);
|
||||||
|
await page.pickDate(selectors.ticketBasicData.shipped, newDate);
|
||||||
|
|
||||||
|
await page.waitToClick(selectors.ticketBasicData.nextStepButton);
|
||||||
|
|
||||||
|
await page.waitToClick(selectors.ticketBasicData.withoutNegatives);
|
||||||
|
await page.waitToClick(selectors.ticketBasicData.finalizeButton);
|
||||||
|
|
||||||
|
await page.waitForState('ticket.card.summary');
|
||||||
|
|
||||||
|
const newTicketAgency = await page
|
||||||
|
.waitToGetProperty(selectors.ticketDescriptor.descriptorDeliveryAgency, 'innerText');
|
||||||
|
const newTicketDate = await page
|
||||||
|
.waitToGetProperty(selectors.ticketDescriptor.descriptorDeliveryDate, 'innerText');
|
||||||
|
|
||||||
|
expect(newAgency).toEqual(newTicketAgency);
|
||||||
|
expect(newTicketDate).toContain(newDate.getDate());
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should new ticket have sale of old ticket`, async() => {
|
||||||
|
await page.accessToSection('ticket.card.sale');
|
||||||
|
await page.waitForState('ticket.card.sale');
|
||||||
|
|
||||||
|
const item = await page.waitToGetProperty(selectors.ticketSales.firstSaleId, 'innerText');
|
||||||
|
|
||||||
|
expect(item).toEqual('4');
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should old ticket have old date and agency`, async() => {
|
||||||
|
const oldDate = new Date();
|
||||||
|
const oldAgency = 'Super-Man delivery';
|
||||||
|
|
||||||
|
await page.accessToSearchResult('14');
|
||||||
|
|
||||||
|
const oldTicketAgency = await page
|
||||||
|
.waitToGetProperty(selectors.ticketDescriptor.descriptorDeliveryAgency, 'innerText');
|
||||||
|
const oldTicketDate = await page
|
||||||
|
.waitToGetProperty(selectors.ticketDescriptor.descriptorDeliveryDate, 'innerText');
|
||||||
|
|
||||||
|
expect(oldTicketAgency).toEqual(oldAgency);
|
||||||
|
expect(oldTicketDate).toContain(oldDate.getDate());
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -77,6 +77,12 @@ module.exports = Self => {
|
||||||
type: 'number',
|
type: 'number',
|
||||||
description: 'Action id',
|
description: 'Action id',
|
||||||
required: true
|
required: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
arg: 'isWithoutNegatives',
|
||||||
|
type: 'boolean',
|
||||||
|
description: 'Is whithout negatives',
|
||||||
|
required: true
|
||||||
}],
|
}],
|
||||||
returns: {
|
returns: {
|
||||||
type: ['object'],
|
type: ['object'],
|
||||||
|
@ -127,6 +133,18 @@ module.exports = Self => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (args.isWithoutNegatives) {
|
||||||
|
const query = `CALL ticket_getMovable(?,?,?)`;
|
||||||
|
const params = [args.id, args.shipped, args.warehouseFk];
|
||||||
|
const [salesMovable] = await Self.rawSql(query, params, myOptions);
|
||||||
|
|
||||||
|
const salesNewTicket = salesMovable.filter(sale => (sale.movable ?? 0) >= sale.quantity);
|
||||||
|
if (salesNewTicket.length) {
|
||||||
|
const newTicket = await models.Ticket.transferSales(ctx, args.id, null, salesNewTicket, myOptions);
|
||||||
|
args.id = newTicket.id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const originalTicket = await models.Ticket.findOne({
|
const originalTicket = await models.Ticket.findOne({
|
||||||
where: {id: args.id},
|
where: {id: args.id},
|
||||||
fields: [
|
fields: [
|
||||||
|
@ -230,6 +248,7 @@ module.exports = Self => {
|
||||||
await models.Chat.sendCheckingPresence(ctx, salesPersonId, message);
|
await models.Chat.sendCheckingPresence(ctx, salesPersonId, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
res.id = args.id;
|
||||||
if (tx) await tx.commit();
|
if (tx) await tx.commit();
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
|
|
|
@ -40,6 +40,12 @@ module.exports = Self => {
|
||||||
type: 'number',
|
type: 'number',
|
||||||
description: 'The warehouse id',
|
description: 'The warehouse id',
|
||||||
required: true
|
required: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
arg: 'shipped',
|
||||||
|
type: 'date',
|
||||||
|
description: 'shipped',
|
||||||
|
required: true
|
||||||
}],
|
}],
|
||||||
returns: {
|
returns: {
|
||||||
type: ['object'],
|
type: ['object'],
|
||||||
|
@ -104,19 +110,32 @@ module.exports = Self => {
|
||||||
totalDifference: 0.00,
|
totalDifference: 0.00,
|
||||||
};
|
};
|
||||||
|
|
||||||
const query = `CALL vn.ticket_priceDifference(?, ?, ?, ?, ?)`;
|
// Get items movable
|
||||||
const params = [args.id, args.landed, args.addressId, args.zoneId, args.warehouseId];
|
const ticketOrigin = await models.Ticket.findById(args.id, null, myOptions);
|
||||||
|
const differenceShipped = ticketOrigin.shipped.getTime() != args.shipped.getTime();
|
||||||
|
const differenceWarehouse = ticketOrigin.warehouseFk != args.warehouseId;
|
||||||
|
|
||||||
|
salesObj.haveDifferences = differenceShipped || differenceWarehouse;
|
||||||
|
|
||||||
|
let query = `CALL ticket_getMovable(?,?,?)`;
|
||||||
|
let params = [args.id, args.shipped, args.warehouseId];
|
||||||
|
const [salesMovable] = await Self.rawSql(query, params, myOptions);
|
||||||
|
|
||||||
|
const itemMovable = new Map();
|
||||||
|
for (sale of salesMovable)
|
||||||
|
itemMovable.set(sale.id, sale.movable ?? 0);
|
||||||
|
|
||||||
|
// Sale price component, one per sale
|
||||||
|
query = `CALL vn.ticket_priceDifference(?, ?, ?, ?, ?)`;
|
||||||
|
params = [args.id, args.landed, args.addressId, args.zoneId, args.warehouseId];
|
||||||
const [difComponents] = await Self.rawSql(query, params, myOptions);
|
const [difComponents] = await Self.rawSql(query, params, myOptions);
|
||||||
|
|
||||||
const map = new Map();
|
const map = new Map();
|
||||||
|
|
||||||
// Sale price component, one per sale
|
|
||||||
for (difComponent of difComponents)
|
for (difComponent of difComponents)
|
||||||
map.set(difComponent.saleFk, difComponent);
|
map.set(difComponent.saleFk, difComponent);
|
||||||
|
|
||||||
for (sale of salesObj.items) {
|
for (sale of salesObj.items) {
|
||||||
const difComponent = map.get(sale.id);
|
const difComponent = map.get(sale.id);
|
||||||
|
|
||||||
if (difComponent) {
|
if (difComponent) {
|
||||||
sale.component = difComponent;
|
sale.component = difComponent;
|
||||||
|
|
||||||
|
@ -129,6 +148,7 @@ module.exports = Self => {
|
||||||
|
|
||||||
salesObj.totalUnitPrice += sale.price;
|
salesObj.totalUnitPrice += sale.price;
|
||||||
salesObj.totalUnitPrice = round(salesObj.totalUnitPrice);
|
salesObj.totalUnitPrice = round(salesObj.totalUnitPrice);
|
||||||
|
sale.movable = itemMovable.get(sale.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tx) await tx.commit();
|
if (tx) await tx.commit();
|
||||||
|
|
|
@ -45,7 +45,8 @@ describe('ticket componentUpdate()', () => {
|
||||||
shipped: today,
|
shipped: today,
|
||||||
landed: tomorrow,
|
landed: tomorrow,
|
||||||
isDeleted: false,
|
isDeleted: false,
|
||||||
option: 1
|
option: 1,
|
||||||
|
isWithoutNegatives: false
|
||||||
};
|
};
|
||||||
|
|
||||||
let ctx = {
|
let ctx = {
|
||||||
|
@ -94,7 +95,8 @@ describe('ticket componentUpdate()', () => {
|
||||||
shipped: today,
|
shipped: today,
|
||||||
landed: tomorrow,
|
landed: tomorrow,
|
||||||
isDeleted: false,
|
isDeleted: false,
|
||||||
option: 1
|
option: 1,
|
||||||
|
isWithoutNegatives: false
|
||||||
};
|
};
|
||||||
|
|
||||||
const ctx = {
|
const ctx = {
|
||||||
|
@ -134,4 +136,60 @@ describe('ticket componentUpdate()', () => {
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should change warehouse and without negatives', async() => {
|
||||||
|
const tx = await models.SaleComponent.beginTransaction({});
|
||||||
|
|
||||||
|
try {
|
||||||
|
const options = {transaction: tx};
|
||||||
|
|
||||||
|
const saleToTransfer = 27;
|
||||||
|
const originDate = today;
|
||||||
|
const newDate = tomorrow;
|
||||||
|
const ticketID = 14;
|
||||||
|
newDate.setHours(0, 0, 0, 0, 0);
|
||||||
|
originDate.setHours(0, 0, 0, 0, 0);
|
||||||
|
|
||||||
|
const args = {
|
||||||
|
id: ticketID,
|
||||||
|
clientFk: 1104,
|
||||||
|
agencyModeFk: 2,
|
||||||
|
addressFk: 4,
|
||||||
|
zoneFk: 9,
|
||||||
|
warehouseFk: 1,
|
||||||
|
companyFk: 442,
|
||||||
|
shipped: newDate,
|
||||||
|
landed: tomorrow,
|
||||||
|
isDeleted: false,
|
||||||
|
option: 1,
|
||||||
|
isWithoutNegatives: true
|
||||||
|
};
|
||||||
|
|
||||||
|
const ctx = {
|
||||||
|
args: args,
|
||||||
|
req: {
|
||||||
|
accessToken: {userId: 9},
|
||||||
|
headers: {origin: 'http://localhost'},
|
||||||
|
__: value => {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
await models.Ticket.componentUpdate(ctx, options);
|
||||||
|
|
||||||
|
const [newTicketID] = await models.Ticket.rawSql('SELECT MAX(id) as id FROM ticket', null, options);
|
||||||
|
const oldTicket = await models.Ticket.findById(ticketID, null, options);
|
||||||
|
const newTicket = await models.Ticket.findById(newTicketID.id, null, options);
|
||||||
|
const newTicketSale = await models.Sale.findOne({where: {ticketFk: args.id}}, options);
|
||||||
|
|
||||||
|
expect(oldTicket.shipped).toEqual(originDate);
|
||||||
|
expect(newTicket.shipped).toEqual(newDate);
|
||||||
|
expect(newTicketSale.id).toEqual(saleToTransfer);
|
||||||
|
|
||||||
|
await tx.rollback();
|
||||||
|
} catch (e) {
|
||||||
|
await tx.rollback();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -15,6 +15,7 @@ describe('sale priceDifference()', () => {
|
||||||
ctx.args = {
|
ctx.args = {
|
||||||
id: 16,
|
id: 16,
|
||||||
landed: tomorrow,
|
landed: tomorrow,
|
||||||
|
shipped: tomorrow,
|
||||||
addressId: 126,
|
addressId: 126,
|
||||||
agencyModeId: 7,
|
agencyModeId: 7,
|
||||||
zoneId: 3,
|
zoneId: 3,
|
||||||
|
@ -45,6 +46,7 @@ describe('sale priceDifference()', () => {
|
||||||
ctx.args = {
|
ctx.args = {
|
||||||
id: 1,
|
id: 1,
|
||||||
landed: new Date(),
|
landed: new Date(),
|
||||||
|
shipped: new Date(),
|
||||||
addressId: 121,
|
addressId: 121,
|
||||||
zoneId: 3,
|
zoneId: 3,
|
||||||
warehouseId: 1
|
warehouseId: 1
|
||||||
|
@ -59,4 +61,38 @@ describe('sale priceDifference()', () => {
|
||||||
|
|
||||||
expect(error).toEqual(new UserError(`The sales of this ticket can't be modified`));
|
expect(error).toEqual(new UserError(`The sales of this ticket can't be modified`));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should return ticket movable', async() => {
|
||||||
|
const tx = await models.Ticket.beginTransaction({});
|
||||||
|
|
||||||
|
try {
|
||||||
|
const options = {transaction: tx};
|
||||||
|
|
||||||
|
const tomorrow = new Date();
|
||||||
|
tomorrow.setDate(tomorrow.getDate() + 1);
|
||||||
|
|
||||||
|
const ctx = {req: {accessToken: {userId: 1106}}};
|
||||||
|
ctx.args = {
|
||||||
|
id: 11,
|
||||||
|
shipped: tomorrow,
|
||||||
|
landed: tomorrow,
|
||||||
|
addressId: 122,
|
||||||
|
agencyModeId: 7,
|
||||||
|
zoneId: 3,
|
||||||
|
warehouseId: 1
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = await models.Ticket.priceDifference(ctx, options);
|
||||||
|
const firstItem = result.items[0];
|
||||||
|
const secondtItem = result.items[1];
|
||||||
|
|
||||||
|
expect(firstItem.movable).toEqual(440);
|
||||||
|
expect(secondtItem.movable).toEqual(1980);
|
||||||
|
|
||||||
|
await tx.rollback();
|
||||||
|
} catch (e) {
|
||||||
|
await tx.rollback();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -201,7 +201,8 @@ class Controller extends Component {
|
||||||
addressId: this.ticket.addressFk,
|
addressId: this.ticket.addressFk,
|
||||||
agencyModeId: this.ticket.agencyModeFk,
|
agencyModeId: this.ticket.agencyModeFk,
|
||||||
zoneId: this.ticket.zoneFk,
|
zoneId: this.ticket.zoneFk,
|
||||||
warehouseId: this.ticket.warehouseFk
|
warehouseId: this.ticket.warehouseFk,
|
||||||
|
shipped: this.ticket.shipped
|
||||||
};
|
};
|
||||||
|
|
||||||
return this.$http.post(query, params).then(res => {
|
return this.$http.post(query, params).then(res => {
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
<vn-tr>
|
<vn-tr>
|
||||||
<vn-th number>Item</vn-th>
|
<vn-th number>Item</vn-th>
|
||||||
<vn-th class="align-center">Description</vn-th>
|
<vn-th class="align-center">Description</vn-th>
|
||||||
|
<vn-th ng-if="$ctrl.ticket.sale.haveDifferences" number>Movable</vn-th>
|
||||||
<vn-th number>Quantity</vn-th>
|
<vn-th number>Quantity</vn-th>
|
||||||
<vn-th number>Price (PPU)</vn-th>
|
<vn-th number>Price (PPU)</vn-th>
|
||||||
<vn-th number>New (PPU)</vn-th>
|
<vn-th number>New (PPU)</vn-th>
|
||||||
|
@ -31,6 +32,13 @@
|
||||||
tabindex="-1">
|
tabindex="-1">
|
||||||
</vn-fetched-tags>
|
</vn-fetched-tags>
|
||||||
</vn-td>
|
</vn-td>
|
||||||
|
<vn-td ng-if="$ctrl.ticket.sale.haveDifferences" number>
|
||||||
|
<span
|
||||||
|
class="chip"
|
||||||
|
ng-class="{'alert': sale.quantity>sale.movable}">
|
||||||
|
{{::sale.movable}}
|
||||||
|
</span>
|
||||||
|
</vn-td>
|
||||||
<vn-td number>{{::sale.quantity}}</vn-td>
|
<vn-td number>{{::sale.quantity}}</vn-td>
|
||||||
<vn-td number>{{::sale.price | currency: 'EUR': 2}}</vn-td>
|
<vn-td number>{{::sale.price | currency: 'EUR': 2}}</vn-td>
|
||||||
<vn-td number>{{::sale.component.newPrice | currency: 'EUR': 2}}</vn-td>
|
<vn-td number>{{::sale.component.newPrice | currency: 'EUR': 2}}</vn-td>
|
||||||
|
@ -66,6 +74,13 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</vn-card>
|
</vn-card>
|
||||||
|
<div class="totalBox align-left" ng-show="::$ctrl.haveNegatives">
|
||||||
|
<vn-check
|
||||||
|
ng-model="$ctrl.ticket.withoutNegatives"
|
||||||
|
label="Create without negatives"
|
||||||
|
info="Clone this ticket with the changes and only sales availables">
|
||||||
|
</vn-check>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</vn-side-menu>
|
</vn-side-menu>
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ class Controller extends Component {
|
||||||
this.getTotalNewPrice();
|
this.getTotalNewPrice();
|
||||||
this.getTotalDifferenceOfPrice();
|
this.getTotalDifferenceOfPrice();
|
||||||
this.loadDefaultTicketAction();
|
this.loadDefaultTicketAction();
|
||||||
|
this.ticketHaveNegatives();
|
||||||
}
|
}
|
||||||
|
|
||||||
loadDefaultTicketAction() {
|
loadDefaultTicketAction() {
|
||||||
|
@ -63,6 +64,22 @@ class Controller extends Component {
|
||||||
this.totalPriceDifference = totalPriceDifference;
|
this.totalPriceDifference = totalPriceDifference;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ticketHaveNegatives() {
|
||||||
|
let haveNegatives = false;
|
||||||
|
let haveNotNegatives = false;
|
||||||
|
const haveDifferences = this.ticket.sale.haveDifferences;
|
||||||
|
|
||||||
|
this.ticket.sale.items.forEach(item => {
|
||||||
|
if (item.quantity > item.movable)
|
||||||
|
haveNegatives = true;
|
||||||
|
else
|
||||||
|
haveNotNegatives = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.ticket.withoutNegatives = false;
|
||||||
|
this.haveNegatives = (haveNegatives && haveNotNegatives && haveDifferences);
|
||||||
|
}
|
||||||
|
|
||||||
onSubmit() {
|
onSubmit() {
|
||||||
if (!this.ticket.option) {
|
if (!this.ticket.option) {
|
||||||
return this.vnApp.showError(
|
return this.vnApp.showError(
|
||||||
|
@ -70,8 +87,8 @@ class Controller extends Component {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let query = `tickets/${this.ticket.id}/componentUpdate`;
|
const query = `tickets/${this.ticket.id}/componentUpdate`;
|
||||||
let params = {
|
const params = {
|
||||||
clientFk: this.ticket.clientFk,
|
clientFk: this.ticket.clientFk,
|
||||||
nickname: this.ticket.nickname,
|
nickname: this.ticket.nickname,
|
||||||
agencyModeFk: this.ticket.agencyModeFk,
|
agencyModeFk: this.ticket.agencyModeFk,
|
||||||
|
@ -82,15 +99,19 @@ class Controller extends Component {
|
||||||
shipped: this.ticket.shipped,
|
shipped: this.ticket.shipped,
|
||||||
landed: this.ticket.landed,
|
landed: this.ticket.landed,
|
||||||
isDeleted: this.ticket.isDeleted,
|
isDeleted: this.ticket.isDeleted,
|
||||||
option: parseInt(this.ticket.option)
|
option: parseInt(this.ticket.option),
|
||||||
|
isWithoutNegatives: this.ticket.withoutNegatives
|
||||||
};
|
};
|
||||||
|
|
||||||
this.$http.post(query, params).then(res => {
|
this.$http.post(query, params)
|
||||||
|
.then(res => {
|
||||||
|
this.ticketToMove = res.data.id;
|
||||||
this.vnApp.showMessage(
|
this.vnApp.showMessage(
|
||||||
this.$t(`The ticket has been unrouted`)
|
this.$t(`The ticket has been unrouted`)
|
||||||
);
|
);
|
||||||
this.card.reload();
|
})
|
||||||
this.$state.go('ticket.card.summary', {id: this.$params.id});
|
.finally(() => {
|
||||||
|
this.$state.go('ticket.card.summary', {id: this.ticketToMove});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,5 +64,103 @@ describe('Ticket', () => {
|
||||||
expect(controller.totalPriceDifference).toEqual(0.3);
|
expect(controller.totalPriceDifference).toEqual(0.3);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('ticketHaveNegatives()', () => {
|
||||||
|
it('should show if ticket have any negative, have differences, but not all sale are negative', () => {
|
||||||
|
controller.ticket = {
|
||||||
|
sale: {
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
item: 1,
|
||||||
|
quantity: 2,
|
||||||
|
movable: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
item: 2,
|
||||||
|
quantity: 1,
|
||||||
|
movable: 5
|
||||||
|
}
|
||||||
|
],
|
||||||
|
haveDifferences: true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
controller.ticketHaveNegatives();
|
||||||
|
|
||||||
|
expect(controller.haveNegatives).toEqual(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not show if ticket not have any negative', () => {
|
||||||
|
controller.ticket = {
|
||||||
|
sale: {
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
item: 1,
|
||||||
|
quantity: 2,
|
||||||
|
movable: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
item: 2,
|
||||||
|
quantity: 2,
|
||||||
|
movable: 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
haveDifferences: true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
controller.ticketHaveNegatives();
|
||||||
|
|
||||||
|
expect(controller.haveNegatives).toEqual(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not show if all sale are negative', () => {
|
||||||
|
controller.ticket = {
|
||||||
|
sale: {
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
item: 1,
|
||||||
|
quantity: 2,
|
||||||
|
movable: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
item: 2,
|
||||||
|
quantity: 2,
|
||||||
|
movable: 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
haveDifferences: true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
controller.ticketHaveNegatives();
|
||||||
|
|
||||||
|
expect(controller.haveNegatives).toEqual(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not show if ticket not have differences', () => {
|
||||||
|
controller.ticket = {
|
||||||
|
sale: {
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
item: 1,
|
||||||
|
quantity: 2,
|
||||||
|
movable: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
item: 2,
|
||||||
|
quantity: 1,
|
||||||
|
movable: 2
|
||||||
|
}
|
||||||
|
],
|
||||||
|
haveDifferences: false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
controller.ticketHaveNegatives();
|
||||||
|
|
||||||
|
expect(controller.haveNegatives).toEqual(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -6,3 +6,6 @@ The ticket has been unrouted: El ticket ha sido desenrutado
|
||||||
Price: Precio
|
Price: Precio
|
||||||
New price: Nuevo precio
|
New price: Nuevo precio
|
||||||
Price difference: Diferencia de precio
|
Price difference: Diferencia de precio
|
||||||
|
Create without negatives: Crear sin negativos
|
||||||
|
Clone this ticket with the changes and only sales availables: Clona este ticket con los cambios y solo las ventas disponibles.
|
||||||
|
Movable: Movible
|
Loading…
Reference in New Issue