Merge pull request 'refs #6199 feat(sale_updateQuantity): can upload' (!1804) from 6199-saleUploadQuantity into test
gitea/salix/pipeline/head This commit looks good
Details
gitea/salix/pipeline/head This commit looks good
Details
Reviewed-on: #1804 Reviewed-by: Javi Gallego <jgallego@verdnatura.es>
This commit is contained in:
commit
2b3fb4f89e
|
@ -18,7 +18,14 @@ describe('setSaleQuantity()', () => {
|
|||
|
||||
it('should change quantity sale', async() => {
|
||||
const tx = await models.Ticket.beginTransaction({});
|
||||
spyOn(models.Item, 'getVisibleAvailable').and.returnValue((new Promise(resolve => resolve({available: 100}))));
|
||||
spyOn(models.Sale, 'rawSql').and.callFake((sqlStatement, params, options) => {
|
||||
if (sqlStatement.includes('catalog_calcFromItem')) {
|
||||
sqlStatement = `CREATE OR REPLACE TEMPORARY TABLE tmp.ticketCalculateItem ENGINE = MEMORY
|
||||
SELECT 100 as available;`;
|
||||
params = null;
|
||||
}
|
||||
return models.Ticket.rawSql(sqlStatement, params, options);
|
||||
});
|
||||
|
||||
try {
|
||||
const options = {transaction: tx};
|
||||
|
|
|
@ -134,14 +134,6 @@ describe('Ticket Edit sale path', () => {
|
|||
await page.accessToSection('ticket.card.sale');
|
||||
});
|
||||
|
||||
it('should try to add a higher quantity value and then receive an error', async() => {
|
||||
await page.waitToClick(selectors.ticketSales.firstSaleQuantityCell);
|
||||
await page.type(selectors.ticketSales.firstSaleQuantity, '11\u000d');
|
||||
const message = await page.waitForSnackbar();
|
||||
|
||||
expect(message.text).toContain('The new quantity should be smaller than the old one');
|
||||
});
|
||||
|
||||
it('should remove 1 from the first sale quantity', async() => {
|
||||
await page.waitToClick(selectors.ticketSales.firstSaleQuantityCell);
|
||||
await page.waitForSelector(selectors.ticketSales.firstSaleQuantity);
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
"The default consignee can not be unchecked": "The default consignee can not be unchecked",
|
||||
"Enter an integer different to zero": "Enter an integer different to zero",
|
||||
"Package cannot be blank": "Package cannot be blank",
|
||||
"The new quantity should be smaller than the old one": "The new quantity should be smaller than the old one",
|
||||
"The price of the item changed": "The price of the item changed",
|
||||
"The sales of this ticket can't be modified": "The sales of this ticket can't be modified",
|
||||
"Cannot check Equalization Tax in this NIF/CIF": "Cannot check Equalization Tax in this NIF/CIF",
|
||||
"You can't create an order for a frozen client": "You can't create an order for a frozen client",
|
||||
|
@ -191,4 +191,4 @@
|
|||
"Booking completed": "Booking complete",
|
||||
"The ticket is in preparation": "The ticket [{{ticketId}}]({{{ticketUrl}}}) of the sales person {{salesPersonId}} is in preparation",
|
||||
"You can only add negative amounts in refund tickets": "You can only add negative amounts in refund tickets"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
"The grade must be an integer greater than or equal to zero": "El grade debe ser un entero mayor o igual a cero",
|
||||
"Sample type cannot be blank": "El tipo de plantilla no puede quedar en blanco",
|
||||
"Description cannot be blank": "Se debe rellenar el campo de texto",
|
||||
"The new quantity should be smaller than the old one": "La nueva cantidad debe de ser menor que la anterior",
|
||||
"The price of the item changed": "El precio del artículo cambió",
|
||||
"The value should not be greater than 100%": "El valor no debe de ser mayor de 100%",
|
||||
"The value should be a number": "El valor debe ser un numero",
|
||||
"This order is not editable": "Esta orden no se puede modificar",
|
||||
|
|
|
@ -24,34 +24,6 @@ describe('sale updateQuantity()', () => {
|
|||
};
|
||||
}
|
||||
|
||||
it('should throw an error if the quantity is greater than it should be', async() => {
|
||||
const ctx = {
|
||||
req: {
|
||||
accessToken: {userId: 1},
|
||||
headers: {origin: 'localhost:5000'},
|
||||
__: () => {}
|
||||
}
|
||||
};
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getActiveCtx(1));
|
||||
spyOn(models.Item, 'getVisibleAvailable').and.returnValue((new Promise(resolve => resolve({available: 100}))));
|
||||
|
||||
const tx = await models.Sale.beginTransaction({});
|
||||
|
||||
let error;
|
||||
try {
|
||||
const options = {transaction: tx};
|
||||
|
||||
await models.Sale.updateQuantity(ctx, 17, 31, options);
|
||||
|
||||
await tx.rollback();
|
||||
} catch (e) {
|
||||
await tx.rollback();
|
||||
error = e;
|
||||
}
|
||||
|
||||
expect(error).toEqual(new Error('The new quantity should be smaller than the old one'));
|
||||
});
|
||||
|
||||
it('should add quantity if the quantity is greater than it should be and is role advanced', async() => {
|
||||
const saleId = 17;
|
||||
const buyerId = 35;
|
||||
|
@ -64,7 +36,14 @@ describe('sale updateQuantity()', () => {
|
|||
};
|
||||
const tx = await models.Sale.beginTransaction({});
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getActiveCtx(buyerId));
|
||||
spyOn(models.Item, 'getVisibleAvailable').and.returnValue((new Promise(resolve => resolve({available: 100}))));
|
||||
spyOn(models.Sale, 'rawSql').and.callFake((sqlStatement, params, options) => {
|
||||
if (sqlStatement.includes('catalog_calcFromItem')) {
|
||||
sqlStatement = `CREATE OR REPLACE TEMPORARY TABLE tmp.ticketCalculateItem ENGINE = MEMORY
|
||||
SELECT 100 as available;`;
|
||||
params = null;
|
||||
}
|
||||
return models.Ticket.rawSql(sqlStatement, params, options);
|
||||
});
|
||||
|
||||
try {
|
||||
const options = {transaction: tx};
|
||||
|
@ -193,6 +172,14 @@ describe('sale updateQuantity()', () => {
|
|||
|
||||
const item = await models.Item.findById(itemId, null, options);
|
||||
await item.updateAttribute('minQuantity', minQuantity, options);
|
||||
spyOn(models.Sale, 'rawSql').and.callFake((sqlStatement, params, options) => {
|
||||
if (sqlStatement.includes('catalog_calcFromItem')) {
|
||||
sqlStatement = `CREATE OR REPLACE TEMPORARY TABLE tmp.ticketCalculateItem ENGINE = MEMORY
|
||||
SELECT 100 as available;`;
|
||||
params = null;
|
||||
}
|
||||
return models.Ticket.rawSql(sqlStatement, params, options);
|
||||
});
|
||||
|
||||
await models.Sale.updateQuantity(ctx, saleId, newQuantity, options);
|
||||
|
||||
|
@ -226,7 +213,15 @@ describe('sale updateQuantity()', () => {
|
|||
|
||||
const item = await models.Item.findById(itemId, null, options);
|
||||
await item.updateAttribute('minQuantity', minQuantity, options);
|
||||
spyOn(models.Item, 'getVisibleAvailable').and.returnValue((new Promise(resolve => resolve({available: newQuantity}))));
|
||||
|
||||
spyOn(models.Sale, 'rawSql').and.callFake((sqlStatement, params, options) => {
|
||||
if (sqlStatement.includes('catalog_calcFromItem')) {
|
||||
sqlStatement = `CREATE OR REPLACE TEMPORARY TABLE tmp.ticketCalculateItem ENGINE = MEMORY
|
||||
SELECT ${newQuantity} as available;`;
|
||||
params = null;
|
||||
}
|
||||
return models.Ticket.rawSql(sqlStatement, params, options);
|
||||
});
|
||||
|
||||
await models.Sale.updateQuantity(ctx, saleId, newQuantity, options);
|
||||
|
||||
|
@ -236,4 +231,87 @@ describe('sale updateQuantity()', () => {
|
|||
throw e;
|
||||
}
|
||||
});
|
||||
|
||||
it('should increase quantity if you have enough available and the new price is the same as the previous one', async() => {
|
||||
const ctx = {
|
||||
req: {
|
||||
accessToken: {userId: 1},
|
||||
headers: {origin: 'localhost:5000'},
|
||||
__: () => {}
|
||||
}
|
||||
};
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getActiveCtx(1));
|
||||
|
||||
const tx = await models.Sale.beginTransaction({});
|
||||
const itemId = 2;
|
||||
const saleId = 17;
|
||||
const minQuantity = 30;
|
||||
const newQuantity = 31;
|
||||
|
||||
try {
|
||||
const options = {transaction: tx};
|
||||
|
||||
const item = await models.Item.findById(itemId, null, options);
|
||||
await item.updateAttribute('minQuantity', minQuantity, options);
|
||||
spyOn(models.Sale, 'rawSql').and.callFake((sqlStatement, params, options) => {
|
||||
if (sqlStatement.includes('catalog_calcFromItem')) {
|
||||
sqlStatement = `
|
||||
CREATE OR REPLACE TEMPORARY TABLE tmp.ticketCalculateItem ENGINE = MEMORY SELECT ${newQuantity} as available;
|
||||
CREATE OR REPLACE TEMPORARY TABLE tmp.ticketComponentPrice ENGINE = MEMORY SELECT 1 as grouping, 8 as price;`;
|
||||
params = null;
|
||||
}
|
||||
return models.Ticket.rawSql(sqlStatement, params, options);
|
||||
});
|
||||
|
||||
await models.Sale.updateQuantity(ctx, saleId, newQuantity, options);
|
||||
|
||||
await tx.rollback();
|
||||
} catch (e) {
|
||||
await tx.rollback();
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
|
||||
it('should throw error when increase quantity and the new price is lower than the previous one', async() => {
|
||||
const ctx = {
|
||||
req: {
|
||||
accessToken: {userId: 1},
|
||||
headers: {origin: 'localhost:5000'},
|
||||
__: () => {}
|
||||
}
|
||||
};
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getActiveCtx(1));
|
||||
|
||||
const tx = await models.Sale.beginTransaction({});
|
||||
const itemId = 2;
|
||||
const saleId = 17;
|
||||
const minQuantity = 30;
|
||||
const newQuantity = 31;
|
||||
|
||||
let error;
|
||||
try {
|
||||
const options = {transaction: tx};
|
||||
|
||||
const item = await models.Item.findById(itemId, null, options);
|
||||
await item.updateAttribute('minQuantity', minQuantity, options);
|
||||
spyOn(models.Sale, 'rawSql').and.callFake((sqlStatement, params, options) => {
|
||||
if (sqlStatement.includes('catalog_calcFromItem')) {
|
||||
sqlStatement = `
|
||||
CREATE OR REPLACE TEMPORARY TABLE tmp.ticketCalculateItem ENGINE = MEMORY SELECT ${newQuantity} as available;
|
||||
CREATE OR REPLACE TEMPORARY TABLE tmp.ticketComponentPrice ENGINE = MEMORY SELECT 1 as grouping, 1 as price;`;
|
||||
params = null;
|
||||
}
|
||||
return models.Ticket.rawSql(sqlStatement, params, options);
|
||||
});
|
||||
|
||||
await models.Sale.updateQuantity(ctx, saleId, newQuantity, options);
|
||||
|
||||
await tx.rollback();
|
||||
} catch (e) {
|
||||
await tx.rollback();
|
||||
error = e;
|
||||
}
|
||||
|
||||
expect(error).toEqual(new Error('The price of the item changed'));
|
||||
});
|
||||
});
|
||||
|
|
|
@ -31,11 +31,13 @@ module.exports = Self => {
|
|||
|
||||
const ticketId = changes?.ticketFk || instance?.ticketFk;
|
||||
const itemId = changes?.itemFk || instance?.itemFk;
|
||||
const oldQuantity = instance?.quantity ?? null;
|
||||
const quantityAdded = newQuantity - oldQuantity;
|
||||
|
||||
const ticket = await models.Ticket.findById(
|
||||
ticketId,
|
||||
{
|
||||
fields: ['id', 'clientFk', 'warehouseFk', 'shipped'],
|
||||
fields: ['id', 'clientFk', 'warehouseFk', 'addressFk', 'agencyModeFk', 'shipped', 'landed'],
|
||||
include: {
|
||||
relation: 'client',
|
||||
scope: {
|
||||
|
@ -65,28 +67,46 @@ module.exports = Self => {
|
|||
fields: ['family', 'minQuantity'],
|
||||
where: {id: itemId},
|
||||
}, ctx.options);
|
||||
|
||||
if (item.family == 'EMB') return;
|
||||
|
||||
const itemInfo = await models.Item.getVisibleAvailable(
|
||||
itemId,
|
||||
ticket.warehouseFk,
|
||||
ticket.shipped,
|
||||
ctx.options
|
||||
);
|
||||
await models.Sale.rawSql(`CALL catalog_calcFromItem(?,?,?,?)`, [
|
||||
ticket.landed,
|
||||
ticket.addressFk,
|
||||
ticket.agencyModeFk,
|
||||
itemId
|
||||
],
|
||||
ctx.options);
|
||||
|
||||
const oldQuantity = instance?.quantity ?? null;
|
||||
const quantityAdded = newQuantity - oldQuantity;
|
||||
if (itemInfo.available < quantityAdded)
|
||||
const [itemInfo] = await models.Sale.rawSql(`SELECT available FROM tmp.ticketCalculateItem`, null, ctx.options);
|
||||
|
||||
if (!itemInfo?.available || itemInfo.available < quantityAdded)
|
||||
throw new UserError(`This item is not available`);
|
||||
|
||||
if (await models.ACL.checkAccessAcl(ctx, 'Ticket', 'isRoleAdvanced', '*')) return;
|
||||
|
||||
if (newQuantity < item.minQuantity && itemInfo.available != newQuantity)
|
||||
if (newQuantity < item.minQuantity && newQuantity != itemInfo?.available)
|
||||
throw new UserError('The amount cannot be less than the minimum');
|
||||
|
||||
if (!ctx.isNewInstance && newQuantity > oldQuantity)
|
||||
throw new UserError('The new quantity should be smaller than the old one');
|
||||
if (ctx.isNewInstance || newQuantity <= oldQuantity) return;
|
||||
|
||||
const [saleGrouping] = await models.Sale.rawSql(`
|
||||
SELECT MAX(t.grouping), t.price newPrice
|
||||
FROM tmp.ticketComponentPrice t
|
||||
WHERE t.grouping <= ?`,
|
||||
[quantityAdded],
|
||||
ctx.options);
|
||||
|
||||
await models.Sale.rawSql(`
|
||||
DROP TEMPORARY TABLE IF EXISTS
|
||||
tmp.ticketCalculateItem,
|
||||
tmp.ticketComponentPrice,
|
||||
tmp.ticketComponent,
|
||||
tmp.ticketLot,
|
||||
tmp.zoneGetShipped;
|
||||
`, null, ctx.options);
|
||||
|
||||
if (!saleGrouping?.newPrice || saleGrouping.newPrice < instance.price)
|
||||
throw new UserError('The price of the item changed');
|
||||
});
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue