Merge pull request '3256-order_transactions' (#778) from 3256-order_transactions into dev
gitea/salix/pipeline/head This commit looks good Details

Reviewed-on: #778
Reviewed-by: Joan Sanchez <joan@verdnatura.es>
This commit is contained in:
Joan Sanchez 2021-12-20 09:25:04 +00:00
commit c2f3d35a07
43 changed files with 1376 additions and 601 deletions

View File

@ -52,8 +52,6 @@
"Agency cannot be blank": "La agencia no puede quedar en blanco", "Agency cannot be blank": "La agencia no puede quedar en blanco",
"You can't make changes on a client with verified data": "No puedes hacer cambios en un cliente con datos comprobados", "You can't make changes on a client with verified data": "No puedes hacer cambios en un cliente con datos comprobados",
"This address doesn't exist": "Este consignatario no existe", "This address doesn't exist": "Este consignatario no existe",
"You can't create an order for a inactive client": "You can't create an order for a inactive client",
"You can't create an order for a client that doesn't has tax data verified": "You can't create an order for a client that doesn't has tax data verified",
"You must delete the claim id %d first": "Antes debes borrar la reclamación %d", "You must delete the claim id %d first": "Antes debes borrar la reclamación %d",
"You don't have enough privileges": "No tienes suficientes permisos", "You don't have enough privileges": "No tienes suficientes permisos",
"Cannot check Equalization Tax in this NIF/CIF": "No se puede marcar RE en este NIF/CIF", "Cannot check Equalization Tax in this NIF/CIF": "No se puede marcar RE en este NIF/CIF",

View File

@ -1,4 +1,4 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
const LoopBackContext = require('loopback-context'); const LoopBackContext = require('loopback-context');
describe('entry addBuy()', () => { describe('entry addBuy()', () => {
@ -25,11 +25,11 @@ describe('entry addBuy()', () => {
packageFk: 3 packageFk: 3
}; };
const tx = await app.models.Entry.beginTransaction({}); const tx = await models.Entry.beginTransaction({});
const options = {transaction: tx}; const options = {transaction: tx};
try { try {
const newBuy = await app.models.Entry.addBuy(ctx, options); const newBuy = await models.Entry.addBuy(ctx, options);
expect(newBuy.itemFk).toEqual(itemId); expect(newBuy.itemFk).toEqual(itemId);

View File

@ -1,4 +1,4 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
const LoopBackContext = require('loopback-context'); const LoopBackContext = require('loopback-context');
describe('sale deleteBuys()', () => { describe('sale deleteBuys()', () => {
@ -15,13 +15,13 @@ describe('sale deleteBuys()', () => {
active: activeCtx active: activeCtx
}); });
const tx = await app.models.Entry.beginTransaction({}); const tx = await models.Entry.beginTransaction({});
const options = {transaction: tx}; const options = {transaction: tx};
ctx.args = {buys: [{id: 1}]}; ctx.args = {buys: [{id: 1}]};
try { try {
const result = await app.models.Buy.deleteBuys(ctx, options); const result = await models.Buy.deleteBuys(ctx, options);
expect(result).toEqual([{count: 1}]); expect(result).toEqual([{count: 1}]);
await tx.rollback(); await tx.rollback();

View File

@ -1,9 +1,8 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
const model = app.models.Buy;
describe('Buy editLatestsBuys()', () => { describe('Buy editLatestsBuys()', () => {
it('should change the value of a given column for the selected buys', async() => { it('should change the value of a given column for the selected buys', async() => {
const tx = await app.models.Entry.beginTransaction({}); const tx = await models.Buy.beginTransaction({});
const options = {transaction: tx}; const options = {transaction: tx};
try { try {
@ -13,15 +12,15 @@ describe('Buy editLatestsBuys()', () => {
} }
}; };
const [original] = await model.latestBuysFilter(ctx, null, options); const [original] = await models.Buy.latestBuysFilter(ctx, null, options);
const field = 'size'; const field = 'size';
const newValue = 99; const newValue = 99;
const lines = [{itemFk: original.itemFk, id: original.id}]; const lines = [{itemFk: original.itemFk, id: original.id}];
await model.editLatestBuys(field, newValue, lines, options); await models.Buy.editLatestBuys(field, newValue, lines, options);
const [result] = await model.latestBuysFilter(ctx, null, options); const [result] = await models.Buy.latestBuysFilter(ctx, null, options);
expect(result[field]).toEqual(newValue); expect(result[field]).toEqual(newValue);

View File

@ -1,77 +1,137 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
describe('Entry filter()', () => { describe('Entry filter()', () => {
it('should return the entry matching "search"', async() => { it('should return the entry matching "search"', async() => {
let ctx = { const tx = await models.Entry.beginTransaction({});
const options = {transaction: tx};
try {
const ctx = {
args: { args: {
search: 1 search: 1
} }
}; };
let result = await app.models.Entry.filter(ctx); const result = await models.Entry.filter(ctx, options);
expect(result.length).toEqual(1); expect(result.length).toEqual(1);
expect(result[0].id).toEqual(1); expect(result[0].id).toEqual(1);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should return the entry matching the currency', async() => { it('should return the entry matching the currency', async() => {
let ctx = { const tx = await models.Entry.beginTransaction({});
const options = {transaction: tx};
try {
const ctx = {
args: { args: {
currencyFk: 1 currencyFk: 1
} }
}; };
let result = await app.models.Entry.filter(ctx); const result = await models.Entry.filter(ctx, options);
expect(result.length).toEqual(8); expect(result.length).toEqual(8);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should return the entry matching the supplier', async() => { it('should return the entry matching the supplier', async() => {
let ctx = { const tx = await models.Entry.beginTransaction({});
const options = {transaction: tx};
try {
const ctx = {
args: { args: {
supplierFk: 2 supplierFk: 2
} }
}; };
let result = await app.models.Entry.filter(ctx); const result = await models.Entry.filter(ctx, options);
expect(result.length).toEqual(6); expect(result.length).toEqual(6);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should return the entry matching the company', async() => { it('should return the entry matching the company', async() => {
let ctx = { const tx = await models.Entry.beginTransaction({});
const options = {transaction: tx};
try {
const ctx = {
args: { args: {
companyFk: 442 companyFk: 442
} }
}; };
let result = await app.models.Entry.filter(ctx); const result = await models.Entry.filter(ctx, options);
expect(result.length).toEqual(7); expect(result.length).toEqual(7);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should return the entries matching isBooked', async() => { it('should return the entries matching isBooked', async() => {
let ctx = { const tx = await models.Entry.beginTransaction({});
const options = {transaction: tx};
try {
const ctx = {
args: { args: {
isBooked: true, isBooked: true,
} }
}; };
let result = await app.models.Entry.filter(ctx); const result = await models.Entry.filter(ctx, options);
expect(result.length).toEqual(0); expect(result.length).toEqual(0);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should return the routes matching the reference and travel', async() => { it('should return the routes matching the reference and travel', async() => {
let ctx = { const tx = await models.Entry.beginTransaction({});
const options = {transaction: tx};
try {
const ctx = {
args: { args: {
reference: 'movement', reference: 'movement',
travelFk: '2' travelFk: '2'
} }
}; };
let result = await app.models.Entry.filter(ctx); const result = await models.Entry.filter(ctx, options);
expect(result.length).toEqual(2); expect(result.length).toEqual(2);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
}); });

View File

@ -1,14 +1,24 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
describe('entry getBuys()', () => { describe('entry getBuys()', () => {
const entryId = 4; const entryId = 4;
it('should get the buys and items of an entry', async() => { it('should get the buys and items of an entry', async() => {
const result = await app.models.Entry.getBuys(entryId); const tx = await models.Entry.beginTransaction({});
const options = {transaction: tx};
try {
const result = await models.Entry.getBuys(entryId, options);
const length = result.length; const length = result.length;
const anyResult = result[Math.floor(Math.random() * Math.floor(length))]; const anyResult = result[Math.floor(Math.random() * Math.floor(length))];
expect(result.length).toEqual(4); expect(result.length).toEqual(4);
expect(anyResult.item).toBeDefined(); expect(anyResult.item).toBeDefined();
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
}); });

View File

@ -1,31 +1,71 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
describe('travel getEntry()', () => { describe('travel getEntry()', () => {
const entryId = 1; const entryId = 1;
it('should check the entry contains the id', async() => { it('should check the entry contains the id', async() => {
const entry = await app.models.Entry.getEntry(entryId); const tx = await models.Entry.beginTransaction({});
const options = {transaction: tx};
try {
const entry = await models.Entry.getEntry(entryId, options);
expect(entry.id).toEqual(entryId); expect(entry.id).toEqual(entryId);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should check the entry contains the supplier name', async() => { it('should check the entry contains the supplier name', async() => {
const entry = await app.models.Entry.getEntry(entryId); const tx = await models.Entry.beginTransaction({});
const options = {transaction: tx};
try {
const entry = await models.Entry.getEntry(entryId, options);
const supplierName = entry.supplier().nickname; const supplierName = entry.supplier().nickname;
expect(supplierName).toEqual('Plants nick'); expect(supplierName).toEqual('Plants nick');
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should check the entry contains the receiver warehouse name', async() => { it('should check the entry contains the receiver warehouse name', async() => {
const entry = await app.models.Entry.getEntry(entryId); const tx = await models.Entry.beginTransaction({});
const options = {transaction: tx};
try {
const entry = await models.Entry.getEntry(entryId, options);
const receiverWarehouseName = entry.travel().warehouseIn().name; const receiverWarehouseName = entry.travel().warehouseIn().name;
expect(receiverWarehouseName).toEqual('Warehouse One'); expect(receiverWarehouseName).toEqual('Warehouse One');
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should check the entry contains the company code', async() => { it('should check the entry contains the company code', async() => {
const entry = await app.models.Entry.getEntry(entryId); const tx = await models.Entry.beginTransaction({});
const options = {transaction: tx};
try {
const entry = await models.Entry.getEntry(entryId, options);
const companyCode = entry.company().code; const companyCode = entry.company().code;
expect(companyCode).toEqual('VNL'); expect(companyCode).toEqual('VNL');
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
}); });

View File

@ -1,4 +1,4 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
const LoopBackContext = require('loopback-context'); const LoopBackContext = require('loopback-context');
describe('entry import()', () => { describe('entry import()', () => {
@ -48,10 +48,10 @@ describe('entry import()', () => {
] ]
} }
}; };
const tx = await app.models.Entry.beginTransaction({}); const tx = await models.Entry.beginTransaction({});
try { try {
const options = {transaction: tx}; const options = {transaction: tx};
const newEntry = await app.models.Entry.create({ const newEntry = await models.Entry.create({
dated: new Date(), dated: new Date(),
supplierFk: supplierId, supplierFk: supplierId,
travelFk: travelId, travelFk: travelId,
@ -60,10 +60,10 @@ describe('entry import()', () => {
ref: 'Entry ref' ref: 'Entry ref'
}, options); }, options);
await app.models.Entry.importBuys(ctx, newEntry.id, options); await models.Entry.importBuys(ctx, newEntry.id, options);
const updatedEntry = await app.models.Entry.findById(newEntry.id, null, options); const updatedEntry = await models.Entry.findById(newEntry.id, null, options);
const entryBuys = await app.models.Buy.find({ const entryBuys = await models.Buy.find({
where: {entryFk: newEntry.id} where: {entryFk: newEntry.id}
}, options); }, options);

View File

@ -1,4 +1,4 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
const LoopBackContext = require('loopback-context'); const LoopBackContext = require('loopback-context');
describe('entry importBuysPreview()', () => { describe('entry importBuysPreview()', () => {
@ -10,6 +10,10 @@ describe('entry importBuysPreview()', () => {
}); });
it('should return the buys with the calculated packageFk', async() => { it('should return the buys with the calculated packageFk', async() => {
const tx = await models.Entry.beginTransaction({});
const options = {transaction: tx};
try {
const expectedPackageFk = '3'; const expectedPackageFk = '3';
const buys = [ const buys = [
{ {
@ -30,10 +34,16 @@ describe('entry importBuysPreview()', () => {
} }
]; ];
const result = await app.models.Entry.importBuysPreview(entryId, buys); const result = await models.Entry.importBuysPreview(entryId, buys, options);
const randomIndex = Math.floor(Math.random() * result.length); const randomIndex = Math.floor(Math.random() * result.length);
const buy = result[randomIndex]; const buy = result[randomIndex];
expect(buy.packageFk).toEqual(expectedPackageFk); expect(buy.packageFk).toEqual(expectedPackageFk);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
}); });

View File

@ -1,34 +1,58 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
describe('Buy latests buys filter()', () => { describe('Buy latests buys filter()', () => {
it('should return the entry matching "search"', async() => { it('should return the entry matching "search"', async() => {
let ctx = { const tx = await models.Buy.beginTransaction({});
const options = {transaction: tx};
try {
const ctx = {
args: { args: {
search: 'Ranged weapon longbow 2m' search: 'Ranged weapon longbow 2m'
} }
}; };
let results = await app.models.Buy.latestBuysFilter(ctx); const results = await models.Buy.latestBuysFilter(ctx);
let firstBuy = results[0]; const firstBuy = results[0];
expect(results.length).toEqual(1); expect(results.length).toEqual(1);
expect(firstBuy.size).toEqual(70); expect(firstBuy.size).toEqual(70);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should return the entry matching "id"', async() => { it('should return the entry matching "id"', async() => {
let ctx = { const tx = await models.Buy.beginTransaction({});
const options = {transaction: tx};
try {
const ctx = {
args: { args: {
id: 1 id: 1
} }
}; };
let results = await app.models.Buy.latestBuysFilter(ctx); const results = await models.Buy.latestBuysFilter(ctx, options);
expect(results.length).toEqual(1); expect(results.length).toEqual(1);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should return results matching "tags"', async() => { it('should return results matching "tags"', async() => {
let ctx = { const tx = await models.Buy.beginTransaction({});
const options = {transaction: tx};
try {
const ctx = {
args: { args: {
tags: [ tags: [
{tagFk: 27, value: '2m'} {tagFk: 27, value: '2m'}
@ -36,160 +60,286 @@ describe('Buy latests buys filter()', () => {
} }
}; };
let results = await app.models.Buy.latestBuysFilter(ctx); const results = await models.Buy.latestBuysFilter(ctx, options);
expect(results.length).toBe(2); expect(results.length).toBe(2);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should return results matching "categoryFk"', async() => { it('should return results matching "categoryFk"', async() => {
let ctx = { const tx = await models.Buy.beginTransaction({});
const options = {transaction: tx};
try {
const ctx = {
args: { args: {
categoryFk: 1 categoryFk: 1
} }
}; };
let results = await app.models.Buy.latestBuysFilter(ctx); const results = await models.Buy.latestBuysFilter(ctx, options);
expect(results.length).toBe(4); expect(results.length).toBe(4);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should return results matching "typeFk"', async() => { it('should return results matching "typeFk"', async() => {
let ctx = { const tx = await models.Buy.beginTransaction({});
const options = {transaction: tx};
try {
const ctx = {
args: { args: {
typeFk: 2 typeFk: 2
} }
}; };
let results = await app.models.Buy.latestBuysFilter(ctx); const results = await models.Buy.latestBuysFilter(ctx, options);
expect(results.length).toBe(4); expect(results.length).toBe(4);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should return results matching "active"', async() => { it('should return results matching "active"', async() => {
let ctx = { const tx = await models.Buy.beginTransaction({});
const options = {transaction: tx};
try {
const ctx = {
args: { args: {
active: true active: true
} }
}; };
let results = await app.models.Buy.latestBuysFilter(ctx); const results = await models.Buy.latestBuysFilter(ctx, options);
expect(results.length).toBe(6); expect(results.length).toBe(6);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should return results matching "not active"', async() => { it('should return results matching "not active"', async() => {
let ctx = { const tx = await models.Buy.beginTransaction({});
const options = {transaction: tx};
try {
const ctx = {
args: { args: {
active: false active: false
} }
}; };
let results = await app.models.Buy.latestBuysFilter(ctx); const results = await models.Buy.latestBuysFilter(ctx, options);
expect(results.length).toBe(0); expect(results.length).toBe(0);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should return results matching "visible"', async() => { it('should return results matching "visible"', async() => {
let ctx = { const tx = await models.Buy.beginTransaction({});
const options = {transaction: tx};
try {
const ctx = {
args: { args: {
visible: true visible: true
} }
}; };
let results = await app.models.Buy.latestBuysFilter(ctx); const results = await models.Buy.latestBuysFilter(ctx, options);
expect(results.length).toBe(5); expect(results.length).toBe(5);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should return results matching "not visible"', async() => { it('should return results matching "not visible"', async() => {
let ctx = { const tx = await models.Buy.beginTransaction({});
const options = {transaction: tx};
try {
const ctx = {
args: { args: {
visible: false visible: false
} }
}; };
let results = await app.models.Buy.latestBuysFilter(ctx); const results = await models.Buy.latestBuysFilter(ctx, options);
expect(results.length).toBe(0); expect(results.length).toBe(0);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should return results matching "floramondo"', async() => { it('should return results matching "floramondo"', async() => {
let ctx = { const tx = await models.Buy.beginTransaction({});
const options = {transaction: tx};
try {
const ctx = {
args: { args: {
floramondo: true floramondo: true
} }
}; };
let results = await app.models.Buy.latestBuysFilter(ctx); const results = await models.Buy.latestBuysFilter(ctx, options);
expect(results.length).toBe(1); expect(results.length).toBe(1);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should return results matching "not floramondo"', async() => { it('should return results matching "not floramondo"', async() => {
let ctx = { const tx = await models.Buy.beginTransaction({});
const options = {transaction: tx};
try {
const ctx = {
args: { args: {
floramondo: false floramondo: false
} }
}; };
let results = await app.models.Buy.latestBuysFilter(ctx); const results = await models.Buy.latestBuysFilter(ctx, options);
expect(results.length).toBe(5); expect(results.length).toBe(5);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should return results matching "salesPersonFk"', async() => { it('should return results matching "salesPersonFk"', async() => {
let ctx = { const tx = await models.Buy.beginTransaction({});
const options = {transaction: tx};
try {
const ctx = {
args: { args: {
salesPersonFk: 35 salesPersonFk: 35
} }
}; };
let results = await app.models.Buy.latestBuysFilter(ctx); const results = await models.Buy.latestBuysFilter(ctx, options);
expect(results.length).toBe(6); expect(results.length).toBe(6);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should return results matching "description"', async() => { it('should return results matching "description"', async() => {
let ctx = { const tx = await models.Buy.beginTransaction({});
const options = {transaction: tx};
try {
const ctx = {
args: { args: {
description: 'Increases block' description: 'Increases block'
} }
}; };
let results = await app.models.Buy.latestBuysFilter(ctx); const results = await models.Buy.latestBuysFilter(ctx, options);
expect(results.length).toBe(1); expect(results.length).toBe(1);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should return results matching "supplierFk"', async() => { it('should return results matching "supplierFk"', async() => {
let ctx = { const tx = await models.Buy.beginTransaction({});
const options = {transaction: tx};
try {
const ctx = {
args: { args: {
supplierFk: 1 supplierFk: 1
} }
}; };
let results = await app.models.Buy.latestBuysFilter(ctx); const results = await models.Buy.latestBuysFilter(ctx, options);
expect(results.length).toBe(2); expect(results.length).toBe(2);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should return results matching "from" and "to"', async() => { it('should return results matching "from" and "to"', async() => {
const tx = await models.Buy.beginTransaction({});
const options = {transaction: tx};
try {
const from = new Date(); const from = new Date();
from.setHours(0, 0, 0, 0); from.setHours(0, 0, 0, 0);
const to = new Date(); const to = new Date();
to.setHours(23, 59, 59, 999); to.setHours(23, 59, 59, 999);
let ctx = { const ctx = {
args: { args: {
from: from, from: from,
to: to to: to
} }
}; };
let results = await app.models.Buy.latestBuysFilter(ctx); const results = await models.Buy.latestBuysFilter(ctx, options);
expect(results.length).toBe(2); expect(results.length).toBe(2);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
}); });

View File

@ -21,22 +21,42 @@ module.exports = Self => {
} }
}); });
Self.addToOrder = async params => { Self.addToOrder = async(params, options) => {
let isEditable = await Self.app.models.Order.isEditable(params.orderFk); const myOptions = {};
let tx;
if (typeof options == 'object')
Object.assign(myOptions, options);
if (!myOptions.transaction) {
tx = await Self.beginTransaction({});
myOptions.transaction = tx;
}
try {
const isEditable = await Self.app.models.Order.isEditable(params.orderFk, myOptions);
if (!isEditable) if (!isEditable)
throw new UserError('This order is not editable'); throw new UserError('This order is not editable');
let promises = []; const promises = [];
params.items.forEach(item => { for (const item of params.items) {
promises.push( promises.push(
Self.rawSql( Self.rawSql(
`CALL hedera.order_addItem(?, ?, ?, ?)`, `CALL hedera.order_addItem(?, ?, ?, ?)`,
[params.orderFk, item.warehouseFk, item.itemFk, item.quantity] [params.orderFk, item.warehouseFk, item.itemFk, item.quantity],
myOptions
) )
); );
}); }
await Promise.all(promises); await Promise.all(promises);
if (tx) await tx.commit();
return true; return true;
} catch (e) {
if (tx) await tx.rollback();
throw e;
}
}; };
}; };

View File

@ -21,19 +21,39 @@ module.exports = Self => {
} }
}); });
Self.removes = async params => { Self.removes = async(params, options) => {
const myOptions = {};
let tx;
if (typeof options == 'object')
Object.assign(myOptions, options);
if (!myOptions.transaction) {
tx = await Self.beginTransaction({});
myOptions.transaction = tx;
}
try {
if (!params.rows || !params.rows.length) if (!params.rows || !params.rows.length)
throw new UserError('There is nothing to delete'); throw new UserError('There is nothing to delete');
let isEditable = await Self.app.models.Order.isEditable(params.actualOrderId); const isEditable = await Self.app.models.Order.isEditable(params.actualOrderId, myOptions);
if (!isEditable) if (!isEditable)
throw new UserError('This order is not editable'); throw new UserError('This order is not editable');
let promises = []; const promises = [];
for (let i = 0; i < params.rows.length; i++) for (let i = 0; i < params.rows.length; i++)
promises.push(Self.app.models.OrderRow.destroyById(params.rows[i])); promises.push(Self.app.models.OrderRow.destroyById(params.rows[i], myOptions));
return await Promise.all(promises); const deletions = await Promise.all(promises);
if (tx) await tx.commit();
return deletions;
} catch (e) {
if (tx) await tx.rollback();
throw e;
}
}; };
}; };

View File

@ -1,18 +1,18 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
describe('order addToOrder()', () => { describe('order addToOrder()', () => {
const orderId = 8; const orderId = 8;
let rowToDelete;
afterAll(async() => {
await app.models.OrderRow.removes({rows: [rowToDelete], actualOrderId: orderId});
});
it('should add a row to a given order', async() => { it('should add a row to a given order', async() => {
let unmodifiedRows = await app.models.OrderRow.find({where: {orderFk: orderId}}); const tx = await models.Order.beginTransaction({});
try {
const options = {transaction: tx};
const unmodifiedRows = await models.OrderRow.find({where: {orderFk: orderId}}, options);
expect(unmodifiedRows.length).toBe(2); expect(unmodifiedRows.length).toBe(2);
let params = { const params = {
orderFk: orderId, orderFk: orderId,
items: [{ items: [{
itemFk: 1, itemFk: 1,
@ -21,12 +21,16 @@ describe('order addToOrder()', () => {
}] }]
}; };
await app.models.OrderRow.addToOrder(params); await models.OrderRow.addToOrder(params, options);
let modifiedRows = await app.models.OrderRow.find({where: {orderFk: orderId}}); const modifiedRows = await models.OrderRow.find({where: {orderFk: orderId}}, options);
rowToDelete = modifiedRows[modifiedRows.length - 1].id;
expect(modifiedRows.length).toBe(3); expect(modifiedRows.length).toBe(3);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
}); });

View File

@ -1,20 +1,18 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
describe('order removes()', () => { describe('order removes()', () => {
let row;
let newRow;
beforeAll(async() => {
row = await app.models.OrderRow.findOne({where: {id: 12}});
row.id = null;
newRow = await app.models.OrderRow.create(row);
});
it('should throw an error if rows property is empty', async() => { it('should throw an error if rows property is empty', async() => {
const tx = await models.Order.beginTransaction({});
let error; let error;
try { try {
await app.models.OrderRow.removes({rows: []}); const options = {transaction: tx};
await models.OrderRow.removes({rows: []}, options);
await tx.rollback();
} catch (e) { } catch (e) {
await tx.rollback();
error = e; error = e;
} }
@ -22,10 +20,17 @@ describe('order removes()', () => {
}); });
it('should throw an error if the row selected is not editable', async() => { it('should throw an error if the row selected is not editable', async() => {
const tx = await models.Order.beginTransaction({});
let error; let error;
try { try {
await app.models.OrderRow.removes({rows: [2]}); const options = {transaction: tx};
await models.OrderRow.removes({rows: [2]}, options);
await tx.rollback();
} catch (e) { } catch (e) {
await tx.rollback();
error = e; error = e;
} }
@ -33,13 +38,24 @@ describe('order removes()', () => {
}); });
it('should delete the row', async() => { it('should delete the row', async() => {
let params = { const tx = await models.Order.beginTransaction({});
rows: [newRow.id],
try {
const options = {transaction: tx};
const params = {
rows: [12],
actualOrderId: 16 actualOrderId: 16
}; };
let res = await app.models.OrderRow.removes(params); const res = await models.OrderRow.removes(params, options);
expect(res).toEqual([{count: 1}]); expect(res).toEqual([{count: 1}]);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
}); });

View File

@ -7,28 +7,28 @@ module.exports = Self => {
accepts: [ accepts: [
{ {
arg: 'orderFk', arg: 'orderFk',
type: 'Number', type: 'number',
required: true required: true
}, },
{ {
arg: 'orderBy', arg: 'orderBy',
type: 'Object', type: 'object',
description: 'Items order', description: 'Items order',
required: true required: true
}, },
{ {
arg: 'filter', arg: 'filter',
type: 'Object', type: 'object',
description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string' description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string'
}, },
{ {
arg: 'tagGroups', arg: 'tagGroups',
type: ['Object'], type: ['object'],
description: 'Filter by tag' description: 'Filter by tag'
}, },
], ],
returns: { returns: {
type: ['Object'], type: ['object'],
root: true, root: true,
}, },
http: { http: {
@ -37,8 +37,13 @@ module.exports = Self => {
}, },
}); });
Self.catalogFilter = async(orderFk, orderBy, filter, tagGroups) => { Self.catalogFilter = async(orderFk, orderBy, filter, tagGroups, options) => {
let conn = Self.dataSource.connector; const conn = Self.dataSource.connector;
const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
const stmts = []; const stmts = [];
let stmt; let stmt;
@ -85,7 +90,7 @@ module.exports = Self => {
stmts.push(stmt); stmts.push(stmt);
// Calculate items // Calculate items
const order = await Self.findById(orderFk); const order = await Self.findById(orderFk, null, myOptions);
stmts.push(new ParameterizedSQL( stmts.push(new ParameterizedSQL(
'CALL vn.catalog_calculate(?, ?, ?)', [ 'CALL vn.catalog_calculate(?, ?, ?)', [
order.landed, order.landed,
@ -131,9 +136,9 @@ module.exports = Self => {
params: [orderBy.field], params: [orderBy.field],
}); });
let way = orderBy.way == 'DESC' ? 'DESC' : 'ASC'; const way = orderBy.way == 'DESC' ? 'DESC' : 'ASC';
let tag = await Self.app.models.Tag.findById(orderBy.field); const tag = await Self.app.models.Tag.findById(orderBy.field, null, myOptions);
let orderSql = ` const orderSql = `
ORDER BY ORDER BY
itg.value IS NULL, itg.value IS NULL,
${tag.isQuantitative ? 'CAST(itg.value AS SIGNED)' : 'itg.value'} ${tag.isQuantitative ? 'CAST(itg.value AS SIGNED)' : 'itg.value'}
@ -181,7 +186,7 @@ module.exports = Self => {
stmts.push('CALL vn.ticketCalculatePurge()'); stmts.push('CALL vn.ticketCalculatePurge()');
const sql = ParameterizedSQL.join(stmts, ';'); const sql = ParameterizedSQL.join(stmts, ';');
const result = await conn.executeStmt(sql); const result = await conn.executeStmt(sql, myOptions);
// Add prices to items // Add prices to items
result[itemsIndex].forEach(item => { result[itemsIndex].forEach(item => {

View File

@ -21,7 +21,10 @@ module.exports = Self => {
Self.confirm = async(ctx, orderFk) => { Self.confirm = async(ctx, orderFk) => {
const userId = ctx.req.accessToken.userId; const userId = ctx.req.accessToken.userId;
let query = `CALL hedera.order_confirmWithUser(?, ?)`;
return await Self.rawSql(query, [orderFk, userId]); const query = `CALL hedera.order_confirmWithUser(?, ?)`;
const response = await Self.rawSql(query, [orderFk, userId]);
return response;
}; };
}; };

View File

@ -9,60 +9,60 @@ module.exports = Self => {
accepts: [ accepts: [
{ {
arg: 'ctx', arg: 'ctx',
type: 'Object', type: 'object',
http: {source: 'context'} http: {source: 'context'}
}, { }, {
arg: 'filter', arg: 'filter',
type: 'Object', type: 'object',
description: `Filter defining where, order, offset, and limit - must be a JSON-encoded string` description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string'
}, { }, {
arg: 'search', arg: 'search',
type: 'String', type: 'string',
description: `If it's and integer searchs by id, otherwise it searchs by nickname` description: `If it's and integer searchs by id, otherwise it searchs by nickname`
}, { }, {
arg: 'from', arg: 'from',
type: 'Date', type: 'date',
description: `The from date` description: 'The from date'
}, { }, {
arg: 'to', arg: 'to',
type: 'Date', type: 'date',
description: `The to date` description: 'The to date'
}, { }, {
arg: 'id', arg: 'id',
type: 'Integer', type: 'integer',
description: `The ticket id` description: 'The ticket id'
}, { }, {
arg: 'clientFk', arg: 'clientFk',
type: 'Integer', type: 'integer',
description: `The client id` description: 'The client id'
}, { }, {
arg: 'ticketFk', arg: 'ticketFk',
type: 'Integer', type: 'integer',
description: `The ticket id` description: 'The ticket id'
}, { }, {
arg: 'agencyModeFk', arg: 'agencyModeFk',
type: 'Integer', type: 'integer',
description: `The agency mode id` description: 'The agency mode id'
}, { }, {
arg: 'workerFk', arg: 'workerFk',
type: 'Integer', type: 'integer',
description: `The salesperson id` description: 'The salesperson id'
}, { }, {
arg: 'myTeam', arg: 'myTeam',
type: 'Boolean', type: 'boolean',
description: `Whether to show only tickets for the current logged user team (For now it shows only the current user tickets)` description: 'Whether to show only tickets for the current logged user team (currently user tickets)'
}, { }, {
arg: 'isConfirmed', arg: 'isConfirmed',
type: 'Boolean', type: 'boolean',
description: `Order is confirmed` description: 'Order is confirmed'
}, { }, {
arg: 'showEmpty', arg: 'showEmpty',
type: 'boolean', type: 'boolean',
description: `Show empty orders` description: 'Show empty orders'
} }
], ],
returns: { returns: {
type: ['Object'], type: ['object'],
root: true root: true
}, },
http: { http: {
@ -71,34 +71,35 @@ module.exports = Self => {
} }
}); });
Self.filter = async(ctx, filter) => { Self.filter = async(ctx, filter, options) => {
let conn = Self.dataSource.connector; const conn = Self.dataSource.connector;
let worker = await Self.app.models.Worker.findOne({ const myOptions = {};
where: {userFk: ctx.req.accessToken.userId},
include: [ if (typeof options == 'object')
{relation: 'collegues'} Object.assign(myOptions, options);
]
});
const args = ctx.args; const args = ctx.args;
let teamIds = [];
if (worker.collegues().length && args.myTeam) { // Apply filter by team
worker.collegues().forEach(collegue => { const teamMembersId = [];
teamIds.push(collegue.collegueFk); if (args.myTeam != null) {
}); const worker = await models.Worker.findById(userId, {
include: {
relation: 'collegues'
} }
}, myOptions);
const collegues = worker.collegues() || [];
for (let collegue of collegues)
teamMembersId.push(collegue.collegueFk);
if (worker.collegues().length === 0 && args.myTeam) { if (teamMembersId.length == 0)
worker = await Self.app.models.Worker.findOne({ teamMembersId.push(userId);
fields: ['id'],
where: {userFk: ctx.req.accessToken.userId}
});
teamIds = [worker && worker.id];
} }
if (args && args.myTeam) if (args && args.myTeam)
args.teamIds = teamIds; args.teamIds = teamIds;
let where = buildFilter(args, (param, value) => {
const where = buildFilter(args, (param, value) => {
switch (param) { switch (param) {
case 'search': case 'search':
return /^\d+$/.test(value) return /^\d+$/.test(value)
@ -123,7 +124,10 @@ module.exports = Self => {
case 'isConfirmed': case 'isConfirmed':
return {'o.confirmed': value ? 1 : 0}; return {'o.confirmed': value ? 1 : 0};
case 'myTeam': case 'myTeam':
return {'c.salesPersonFk': {inq: teamIds}}; if (value)
return {'c.salesPersonFk': {inq: teamMembersId}};
else
return {'c.salesPersonFk': {nin: teamMembersId}};
case 'showEmpty': case 'showEmpty':
return {'o.total': {neq: value}}; return {'o.total': {neq: value}};
case 'id': case 'id':
@ -133,7 +137,7 @@ module.exports = Self => {
}); });
filter = mergeFilters(filter, {where}); filter = mergeFilters(filter, {where});
let stmts = []; const stmts = [];
let stmt; let stmt;
stmt = new ParameterizedSQL( stmt = new ParameterizedSQL(
@ -183,7 +187,7 @@ module.exports = Self => {
stmts.push(`DROP TEMPORARY TABLE tmp.filter`); stmts.push(`DROP TEMPORARY TABLE tmp.filter`);
const sql = ParameterizedSQL.join(stmts, ';'); const sql = ParameterizedSQL.join(stmts, ';');
const result = await conn.executeStmt(sql); const result = await conn.executeStmt(sql, myOptions);
return result[ordersIndex]; return result[ordersIndex];
}; };

View File

@ -3,7 +3,7 @@ const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
module.exports = Self => { module.exports = Self => {
Self.remoteMethod('getItemTypeAvailable', { Self.remoteMethod('getItemTypeAvailable', {
description: 'Gets the item types available for an rder and item category ', description: 'Gets the item types available for an order and item category',
accessType: 'READ', accessType: 'READ',
accepts: [{ accepts: [{
arg: 'id', arg: 'id',
@ -27,11 +27,16 @@ module.exports = Self => {
} }
}); });
Self.getItemTypeAvailable = async(orderId, itemCategoryId) => { Self.getItemTypeAvailable = async(orderId, itemCategoryId, options) => {
const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
const stmts = []; const stmts = [];
let stmt; let stmt;
const order = await app.models.Order.findById(orderId); const order = await app.models.Order.findById(orderId, null, myOptions);
stmt = new ParameterizedSQL('call vn.available_calc(?, ?, ?)', [ stmt = new ParameterizedSQL('call vn.available_calc(?, ?, ?)', [
order.landed, order.landed,
order.addressFk, order.addressFk,
@ -78,7 +83,7 @@ module.exports = Self => {
stmts.push('DROP TEMPORARY TABLE tmp.item'); stmts.push('DROP TEMPORARY TABLE tmp.item');
const sql = ParameterizedSQL.join(stmts, ';'); const sql = ParameterizedSQL.join(stmts, ';');
const result = await Self.rawStmt(sql); const result = await Self.rawStmt(sql, myOptions);
return result[categoriesIndex]; return result[categoriesIndex];
}; };

View File

@ -3,7 +3,7 @@ module.exports = Self => {
description: 'Gets the sourceApp type set', description: 'Gets the sourceApp type set',
accessType: 'READ', accessType: 'READ',
returns: { returns: {
type: ['String'], type: ['string'],
root: true root: true
}, },
http: { http: {

View File

@ -21,10 +21,14 @@ module.exports = Self => {
} }
}); });
Self.getTaxes = async orderFk => { Self.getTaxes = async(orderFk, options) => {
let conn = Self.dataSource.connector; const conn = Self.dataSource.connector;
let stmts = []; const stmts = [];
let stmt; let stmt;
const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
stmts.push('DROP TEMPORARY TABLE IF EXISTS tmp.order'); stmts.push('DROP TEMPORARY TABLE IF EXISTS tmp.order');
@ -37,15 +41,15 @@ module.exports = Self => {
stmts.push('CALL hedera.order_getTax()'); stmts.push('CALL hedera.order_getTax()');
let orderTaxIndex = stmts.push('SELECT * FROM tmp.orderAmount') - 1; const orderTaxIndex = stmts.push('SELECT * FROM tmp.orderAmount') - 1;
stmts.push(` stmts.push(`
DROP TEMPORARY TABLE DROP TEMPORARY TABLE
tmp.order, tmp.order,
tmp.orderTax`); tmp.orderTax`);
let sql = ParameterizedSQL.join(stmts, ';'); const sql = ParameterizedSQL.join(stmts, ';');
let result = await conn.executeStmt(sql); const result = await conn.executeStmt(sql, myOptions);
return result[orderTaxIndex]; return result[orderTaxIndex];
}; };

View File

@ -19,9 +19,14 @@ module.exports = Self => {
} }
}); });
Self.getTotal = async orderFk => { Self.getTotal = async(orderFk, options) => {
let query = `SELECT hedera.order_getTotal(?) total;`; const myOptions = {};
let [total] = await Self.rawSql(query, [orderFk]);
if (typeof options == 'object')
Object.assign(myOptions, options);
const query = `SELECT hedera.order_getTotal(?) total;`;
const [total] = await Self.rawSql(query, [orderFk], myOptions);
return total.total; return total.total;
}; };

View File

@ -19,9 +19,14 @@ module.exports = Self => {
} }
}); });
Self.getTotalVolume = async orderFk => { Self.getTotalVolume = async(orderFk, options) => {
let query = `SELECT vn.orderTotalVolume(?) totalVolume, vn.orderTotalVolumeBoxes(?) totalBoxes`; const myOptions = {};
let [res] = await Self.rawSql(query, [orderFk, orderFk]);
if (typeof options == 'object')
Object.assign(myOptions, options);
const query = `SELECT vn.orderTotalVolume(?) totalVolume, vn.orderTotalVolumeBoxes(?) totalBoxes`;
const [res] = await Self.rawSql(query, [orderFk, orderFk], myOptions);
return res; return res;
}; };
}; };

View File

@ -19,9 +19,14 @@ module.exports = Self => {
} }
}); });
Self.getVAT = async orderId => { Self.getVAT = async(orderId, options) => {
const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
let totalTax = 0.00; let totalTax = 0.00;
let taxes = await Self.app.models.Order.getTaxes(orderId); const taxes = await Self.app.models.Order.getTaxes(orderId, myOptions);
taxes.forEach(tax => { taxes.forEach(tax => {
totalTax += tax.tax; totalTax += tax.tax;
}); });

View File

@ -18,8 +18,13 @@ module.exports = Self => {
} }
}); });
Self.getVolumes = async orderFk => { Self.getVolumes = async(orderFk, options) => {
let [volume] = await Self.rawSql(`CALL vn.orderListVolume(?)`, [orderFk]); const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
const [volume] = await Self.rawSql(`CALL vn.orderListVolume(?)`, [orderFk], myOptions);
return volume; return volume;
}; };
}; };

View File

@ -19,8 +19,13 @@ module.exports = Self => {
} }
}); });
Self.isEditable = async orderId => { Self.isEditable = async(orderId, options) => {
let exists = await Self.app.models.Order.findOne({ const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
const exists = await Self.app.models.Order.findOne({
where: {id: orderId}, where: {id: orderId},
fields: ['isConfirmed', 'clientFk'], fields: ['isConfirmed', 'clientFk'],
include: [ include: [
@ -32,7 +37,7 @@ module.exports = Self => {
} }
} }
] ]
}); }, myOptions);
if (exists && exists.client().type().code !== 'normal') if (exists && exists.client().type().code !== 'normal')
return true; return true;

View File

@ -32,8 +32,20 @@ module.exports = Self => {
} }
}); });
Self.new = async(landed, addressId, agencyModeId) => { Self.new = async(landed, addressId, agencyModeId, options) => {
let address = await Self.app.models.Address.findOne({ const myOptions = {};
let tx;
if (typeof options == 'object')
Object.assign(myOptions, options);
if (!myOptions.transaction) {
tx = await Self.beginTransaction({});
myOptions.transaction = tx;
}
try {
const address = await Self.app.models.Address.findOne({
where: {id: addressId}, where: {id: addressId},
fields: ['clientFk'], fields: ['clientFk'],
include: [ include: [
@ -45,11 +57,11 @@ module.exports = Self => {
} }
} }
] ]
}); }, myOptions);
if (address.client().type().code === 'normal') { if (address.client().type().code === 'normal') {
if (!address.client().isActive) if (!address.client().isActive)
throw new UserError(`You can't create an order for a inactive client`); throw new UserError(`You can't create an order for an inactive client`);
} }
query = `CALL vn.orderListCreate(?, ?, ?, ?);`; query = `CALL vn.orderListCreate(?, ?, ?, ?);`;
@ -58,8 +70,14 @@ module.exports = Self => {
agencyModeId, agencyModeId,
addressId, addressId,
'SALIX' 'SALIX'
]); ], myOptions);
if (tx) await tx.commit();
return result[0].vOrderId; return result[0].vOrderId;
} catch (e) {
if (tx) await tx.rollback();
throw e;
}
}; };
}; };

View File

@ -18,17 +18,35 @@ module.exports = Self => {
} }
}); });
Self.newFromTicket = async ticketFk => { Self.newFromTicket = async(ticketFk, options) => {
let ticket = await Self.app.models.Ticket.findOne({ const myOptions = {};
let tx;
if (typeof options == 'object')
Object.assign(myOptions, options);
if (!myOptions.transaction) {
tx = await Self.beginTransaction({});
myOptions.transaction = tx;
}
try {
const ticket = await Self.app.models.Ticket.findOne({
where: {id: ticketFk} where: {id: ticketFk}
}); }, myOptions);
let landed = ticket.landed; const landed = ticket.landed;
let addressFk = ticket.addressFk; const addressFk = ticket.addressFk;
let agencyModeFk = ticket.agencyModeFk; const agencyModeFk = ticket.agencyModeFk;
let orderID = await Self.app.models.Order.new(landed, addressFk, agencyModeFk); const orderID = await Self.app.models.Order.new(landed, addressFk, agencyModeFk, myOptions);
if (tx) await tx.commit();
return orderID; return orderID;
} catch (e) {
if (tx) await tx.rollback();
throw e;
}
}; };
}; };

View File

@ -1,27 +1,43 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
describe('order catalogFilter()', () => { describe('order catalogFilter()', () => {
const colorTagId = 1; const colorTagId = 1;
const categoryTagId = 67; const categoryTagId = 67;
it('should return an array of items', async() => { it('should return an array of items', async() => {
let filter = { const tx = await models.Order.beginTransaction({});
try {
const options = {transaction: tx};
const filter = {
where: { where: {
categoryFk: 1, categoryFk: 1,
typeFk: 2 typeFk: 2
} }
}; };
let tags = []; const tags = [];
let orderFk = 11; const orderFk = 11;
let orderBy = {field: 'relevancy DESC, name', way: 'DESC'}; const orderBy = {field: 'relevancy DESC, name', way: 'DESC'};
let result = await app.models.Order.catalogFilter(orderFk, orderBy, filter, tags); const result = await models.Order.catalogFilter(orderFk, orderBy, filter, tags, options);
let firstItemId = result[0].id; const firstItemId = result[0].id;
expect(result.length).toEqual(4); expect(result.length).toEqual(4);
expect(firstItemId).toEqual(1); expect(firstItemId).toEqual(1);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should now return an array of items based on tag filter', async() => { it('should now return an array of items based on tag filter', async() => {
const tx = await models.Order.beginTransaction({});
try {
const options = {transaction: tx};
const filter = { const filter = {
where: { where: {
categoryFk: 1, categoryFk: 1,
@ -35,7 +51,7 @@ describe('order catalogFilter()', () => {
]; ];
const orderFk = 11; const orderFk = 11;
const orderBy = {field: 'relevancy DESC, name', way: 'DESC'}; const orderBy = {field: 'relevancy DESC, name', way: 'DESC'};
const result = await app.models.Order.catalogFilter(orderFk, orderBy, filter, tagGroups); const result = await models.Order.catalogFilter(orderFk, orderBy, filter, tagGroups, options);
const randomIndex = Math.round(Math.random()); const randomIndex = Math.round(Math.random());
const item = result[randomIndex]; const item = result[randomIndex];
@ -47,5 +63,11 @@ describe('order catalogFilter()', () => {
expect(result.length).toEqual(2); expect(result.length).toEqual(2);
expect(colorTag.value).toEqual('Silver'); expect(colorTag.value).toEqual('Silver');
expect(categoryTag.value).toEqual('Concussion'); expect(categoryTag.value).toEqual('Concussion');
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
}); });

View File

@ -1,4 +1,4 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
describe('order filter()', () => { describe('order filter()', () => {
const ctx = { const ctx = {
@ -8,51 +8,107 @@ describe('order filter()', () => {
}; };
it('should call the filter method with a basic search', async() => { it('should call the filter method with a basic search', async() => {
const myCtx = Object.assign({}, ctx);
const tx = await models.Order.beginTransaction({});
try {
const options = {transaction: tx};
const filter = {where: {'o.id': 2}}; const filter = {where: {'o.id': 2}};
const result = await app.models.Order.filter(ctx, filter); const result = await models.Order.filter(myCtx, filter, options);
const orderId = result[0].id; const orderId = result[0].id;
expect(orderId).toEqual(2); expect(orderId).toEqual(2);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should call the filter method with a single advanced search', async() => { it('should call the filter method with a single advanced search', async() => {
const myCtx = Object.assign({}, ctx);
const tx = await models.Order.beginTransaction({});
try {
const options = {transaction: tx};
const filter = {where: {'o.confirmed': false}}; const filter = {where: {'o.confirmed': false}};
const result = await app.models.Order.filter(ctx, filter); const result = await models.Order.filter(myCtx, filter, options);
expect(result.length).toEqual(16); expect(result.length).toEqual(16);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should call the filter method with a complex advanced search', async() => { it('should call the filter method with a complex advanced search', async() => {
const myCtx = Object.assign({}, ctx);
const tx = await models.Order.beginTransaction({});
try {
const options = {transaction: tx};
const filter = {where: {'o.confirmed': false, 'c.salesPersonFk': 18}}; const filter = {where: {'o.confirmed': false, 'c.salesPersonFk': 18}};
const result = await app.models.Order.filter(ctx, filter); const result = await models.Order.filter(myCtx, filter, options);
expect(result.length).toEqual(9); expect(result.length).toEqual(9);
expect(result[0].id).toEqual(7); expect(result[0].id).toEqual(7);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should return the orders matching the showEmpty on false', async() => { it('should return the orders matching the showEmpty on false', async() => {
const myCtx = Object.assign({}, ctx);
const tx = await models.Order.beginTransaction({});
try {
const options = {transaction: tx};
const filter = {}; const filter = {};
ctx.args = {showEmpty: false}; myCtx.args = {showEmpty: false};
const result = await app.models.Order.filter(ctx, filter); const result = await models.Order.filter(myCtx, filter, options);
const hasEmptyLines = result.some(order => { const hasEmptyLines = result.some(order => {
return order.total === 0; return order.total === 0;
}); });
expect(hasEmptyLines).toBeFalsy(); expect(hasEmptyLines).toBeFalsy();
ctx.args = {showEmpty: null}; await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should return the orders matching the showEmpty on true', async() => { it('should return the orders matching the showEmpty on true', async() => {
const myCtx = Object.assign({}, ctx);
const tx = await models.Order.beginTransaction({});
try {
const options = {transaction: tx};
const filter = {}; const filter = {};
ctx.args = {showEmpty: true}; myCtx.args = {showEmpty: true};
const result = await app.models.Order.filter(ctx, filter); const result = await models.Order.filter(myCtx, filter, options);
const hasEmptyLines = result.some(order => { const hasEmptyLines = result.some(order => {
return order.total === 0; return order.total === 0;
}); });
expect(hasEmptyLines).toBeTruthy(); expect(hasEmptyLines).toBeTruthy();
ctx.args = {showEmpty: null}; await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
}); });

View File

@ -1,19 +1,41 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
describe('order getItemTypeAvailable()', () => { describe('order getItemTypeAvailable()', () => {
it('should call the getItemTypeAvailable method with a valid order and item category', async() => { it('should call the getItemTypeAvailable method with a valid order and item category', async() => {
let orderId = 11; const tx = await models.Order.beginTransaction({});
let itemCategoryId = 1;
let result = await app.models.Order.getItemTypeAvailable(orderId, itemCategoryId); try {
const options = {transaction: tx};
const orderId = 11;
const itemCategoryId = 1;
const result = await models.Order.getItemTypeAvailable(orderId, itemCategoryId, options);
expect(result.length).toEqual(1); expect(result.length).toEqual(1);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should call the getItemTypeAvailable method with the same order and different item category', async() => { it('should call the getItemTypeAvailable method with the same order and different item category', async() => {
let orderId = 11; const tx = await models.Order.beginTransaction({});
let itemCategoryId = 4;//
let result = await app.models.Order.getItemTypeAvailable(orderId, itemCategoryId); try {
const options = {transaction: tx};
const orderId = 11;
const itemCategoryId = 4;
const result = await models.Order.getItemTypeAvailable(orderId, itemCategoryId, options);
expect(result.length).toEqual(0); expect(result.length).toEqual(0);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
}); });

View File

@ -1,31 +1,75 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
describe('order getTaxes()', () => { describe('order getTaxes()', () => {
it('should call the getTaxes method and return undefined if its called with a string', async() => { it('should call the getTaxes method and return undefined if its called with a string', async() => {
let result = await app.models.Order.getTaxes('string'); const tx = await models.Order.beginTransaction({});
try {
const options = {transaction: tx};
const result = await models.Order.getTaxes('string', options);
expect(result.length).toEqual(0); expect(result.length).toEqual(0);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should call the getTaxes method and return undefined if its called with unknown id', async() => { it('should call the getTaxes method and return undefined if its called with unknown id', async() => {
let result = await app.models.Order.getTaxes(99999999999999999999999); const tx = await models.Order.beginTransaction({});
try {
const options = {transaction: tx};
const result = await models.Order.getTaxes(9999, options);
expect(result.length).toEqual(0); expect(result.length).toEqual(0);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should call the getTaxes method and return the taxes splited if different type of taxes', async() => { it('should call the getTaxes method and return the taxes splited if different type of taxes', async() => {
let result = await app.models.Order.getTaxes(1); const tx = await models.Order.beginTransaction({});
try {
const options = {transaction: tx};
const result = await models.Order.getTaxes(1, options);
const expectedResult = result[0].tax + result[1].tax; const expectedResult = result[0].tax + result[1].tax;
expect(expectedResult).toEqual(20.29); expect(expectedResult).toEqual(20.29);
expect(result.length).toEqual(2); expect(result.length).toEqual(2);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should call the getTaxes method and return the taxes for them same type', async() => { it('should call the getTaxes method and return the taxes for them same type', async() => {
let result = await app.models.Order.getTaxes(2); const tx = await models.Order.beginTransaction({});
try {
const options = {transaction: tx};
const result = await models.Order.getTaxes(2, options);
expect(result[0].tax).toEqual(9.1); expect(result[0].tax).toEqual(9.1);
expect(result.length).toEqual(1); expect(result.length).toEqual(1);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
}); });

View File

@ -1,9 +1,19 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
describe('order getTotal()', () => { describe('order getTotal()', () => {
it('should return the order total', async() => { it('should return the order total', async() => {
let result = await app.models.Order.getTotal(1); const tx = await models.Order.beginTransaction({});
try {
const options = {transaction: tx};
const result = await models.Order.getTotal(1, options);
expect(result).toEqual(155.89); expect(result).toEqual(155.89);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
}); });

View File

@ -1,10 +1,21 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
describe('order getTotalVolume()', () => { describe('order getTotalVolume()', () => {
it('should return the total', async() => { it('should return the total', async() => {
let result = await app.models.Order.getTotalVolume(1); const tx = await models.Order.beginTransaction({});
try {
const options = {transaction: tx};
const result = await models.Order.getTotalVolume(1, options);
expect(result.totalVolume).toEqual(1.568); expect(result.totalVolume).toEqual(1.568);
expect(result.totalBoxes).toEqual(11.1); expect(result.totalBoxes).toEqual(11.1);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
}); });

View File

@ -1,9 +1,20 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
describe('order getVAT()', () => { describe('order getVAT()', () => {
it('should return the order VAT', async() => { it('should return the order VAT', async() => {
const result = await app.models.Order.getVAT(1); const tx = await models.Order.beginTransaction({});
try {
const options = {transaction: tx};
const result = await models.Order.getVAT(1, options);
expect(result).toEqual(20.29); expect(result).toEqual(20.29);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
}); });

View File

@ -1,9 +1,20 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
describe('order getVolumes()', () => { describe('order getVolumes()', () => {
it('should return the volumes of a given order id', async() => { it('should return the volumes of a given order id', async() => {
let [result] = await app.models.Order.getVolumes(1); const tx = await models.Order.beginTransaction({});
try {
const options = {transaction: tx};
const [result] = await models.Order.getVolumes(1, options);
expect(result.volume).toEqual(1.09); expect(result.volume).toEqual(1.09);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
}); });

View File

@ -1,21 +1,54 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
describe('order isEditable()', () => { describe('order isEditable()', () => {
it('should return false when the given order is not editable', async() => { it('should return false when the given order is not editable', async() => {
let isEditable = await app.models.Order.isEditable(2); const tx = await models.Order.beginTransaction({});
try {
const options = {transaction: tx};
const isEditable = await models.Order.isEditable(2, options);
expect(isEditable).toBeFalsy(); expect(isEditable).toBeFalsy();
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should return false when the given order doesnt exists', async() => { it('should return false when the given order doesnt exists', async() => {
let isEditable = await app.models.Order.isEditable(99999); const tx = await models.Order.beginTransaction({});
try {
const options = {transaction: tx};
const isEditable = await models.Order.isEditable(999, options);
expect(isEditable).toBeFalsy(); expect(isEditable).toBeFalsy();
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should return true when the given order is editable', async() => { it('should return true when the given order is editable', async() => {
let isEditable = await app.models.Order.isEditable(16); const tx = await models.Order.beginTransaction({});
try {
const options = {transaction: tx};
const isEditable = await models.Order.isEditable(16, options);
expect(isEditable).toBeTruthy(); expect(isEditable).toBeTruthy();
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
}); });

View File

@ -1,36 +1,49 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
let UserError = require('vn-loopback/util/user-error'); const UserError = require('vn-loopback/util/user-error');
describe('order new()', () => { describe('order new()', () => {
let orderId;
afterAll(async() => {
await app.models.Order.destroyById(orderId);
});
it('should throw an error if the client isnt active', async() => { it('should throw an error if the client isnt active', async() => {
const tx = await models.Order.beginTransaction({});
let error; let error;
let landed = new Date(); try {
let addressFk = 6; const options = {transaction: tx};
let agencyModeFk = 1;
await app.models.Order.new(landed, addressFk, agencyModeFk) const landed = new Date();
.catch(e => { const addressFk = 6;
const agencyModeFk = 1;
await models.Order.new(landed, addressFk, agencyModeFk, options);
await tx.rollback();
} catch (e) {
await tx.rollback();
error = e; error = e;
}); }
expect(error).toEqual(new UserError(`You can't create an order for a inactive client`)); expect(error).toEqual(new UserError(`You can't create an order for an inactive client`));
}); });
it('should now create a new order when all conditions are met', async() => { it('should now create a new order when all conditions are met', async() => {
let landed = new Date(); const tx = await models.Order.beginTransaction({});
let addressFk = 121;
let agencyModeFk = 1;
orderId = await app.models.Order.new(landed, addressFk, agencyModeFk); try {
const options = {transaction: tx};
let highestOrderIdInFixtures = 3; const landed = new Date();
const addressFk = 121;
const agencyModeFk = 1;
orderId = await models.Order.new(landed, addressFk, agencyModeFk, options);
const highestOrderIdInFixtures = 3;
expect(orderId).toBeGreaterThan(highestOrderIdInFixtures); expect(orderId).toBeGreaterThan(highestOrderIdInFixtures);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
}); });

View File

@ -0,0 +1,24 @@
const models = require('vn-loopback/server/server').models;
describe('order newFromTicket()', () => {
it('should create a new order from an existing ticket', async() => {
const tx = await models.Order.beginTransaction({});
try {
const options = {transaction: tx};
const ticketId = 11;
const orderId = await models.Order.newFromTicket(ticketId, options);
const highestOrderIdInFixtures = 3;
expect(orderId).toBeGreaterThan(highestOrderIdInFixtures);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
});

View File

@ -1,36 +1,91 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
describe('order summary()', () => { describe('order summary()', () => {
it('should return a summary object containing data from 1 order', async() => { it('should return a summary object containing data from 1 order', async() => {
let result = await app.models.Order.summary(1); const tx = await models.Order.beginTransaction({});
try {
const options = {transaction: tx};
const result = await models.Order.summary(1, options);
expect(result.id).toEqual(1); expect(result.id).toEqual(1);
expect(result.clientFk).toEqual(1101); expect(result.clientFk).toEqual(1101);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should return a summary object containing sales from 1 order', async() => { it('should return a summary object containing sales from 1 order', async() => {
let result = await app.models.Order.summary(1); const tx = await models.Order.beginTransaction({});
try {
const options = {transaction: tx};
const result = await models.Order.summary(1, options);
expect(result.rows.length).toEqual(3); expect(result.rows.length).toEqual(3);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should return a summary object containing subTotal for 1 order', async() => { it('should return a summary object containing subTotal for 1 order', async() => {
let result = await app.models.Order.summary(1); const tx = await models.Order.beginTransaction({});
try {
const options = {transaction: tx};
const result = await models.Order.summary(1, options);
expect(Math.round(result.subTotal * 100) / 100).toEqual(135.60); expect(Math.round(result.subTotal * 100) / 100).toEqual(135.60);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should return a summary object containing VAT for 1 order', async() => { it('should return a summary object containing VAT for 1 order', async() => {
let result = await app.models.Order.summary(1); const tx = await models.Order.beginTransaction({});
try {
const options = {transaction: tx};
const result = await models.Order.summary(1, options);
expect(Math.round(result.VAT * 100) / 100).toEqual(20.29); expect(Math.round(result.VAT * 100) / 100).toEqual(20.29);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should return a summary object containing total for 1 order', async() => { it('should return a summary object containing total for 1 order', async() => {
let result = await app.models.Order.summary(1); const tx = await models.Order.beginTransaction({});
let total = result.subTotal + result.VAT;
let expectedTotal = Math.round(total * 100) / 100; try {
const options = {transaction: tx};
const result = await models.Order.summary(1, options);
const total = result.subTotal + result.VAT;
const expectedTotal = Math.round(total * 100) / 100;
expect(result.total).toEqual(expectedTotal); expect(result.total).toEqual(expectedTotal);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
}); });

View File

@ -1,61 +1,93 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
const UserError = require('vn-loopback/util/user-error');
describe('Order updateBasicData', () => { describe('Order updateBasicData', () => {
const orderId = 21; const orderId = 21;
afterAll(async() => {
let validparams = {note: null};
await app.models.Order.updateBasicData(orderId, validparams);
});
it('should return an error if the order is confirmed', async() => { it('should return an error if the order is confirmed', async() => {
const tx = await models.Order.beginTransaction({});
let error; let error;
try {
const options = {transaction: tx};
const params = [];
const orderConfirmed = 1;
let params = []; await models.Order.updateBasicData(orderConfirmed, params, options);
let orderConfirmed = 1;
await app.models.Order.updateBasicData(orderConfirmed, params) await tx.rollback();
.catch(e => { } catch (e) {
await tx.rollback();
error = e; error = e;
}); }
const expectedError = `You can't make changes on the basic data of an confirmed order or with rows`;
expect(error.toString()).toContain(`You can't make changes on the basic data of an confirmed order or with rows`); expect(error).toEqual(new UserError(expectedError));
}); });
it('should return an error if the order has rows', async() => { it('should return an error if the order has rows', async() => {
const tx = await models.Order.beginTransaction({});
let error; let error;
try {
const options = {transaction: tx};
let params = []; const params = [];
let orderWithRows = 16; const orderWithRows = 16;
await app.models.Order.updateBasicData(orderWithRows, params) await models.Order.updateBasicData(orderWithRows, params, options);
.catch(e => {
await tx.rollback();
} catch (e) {
await tx.rollback();
error = e; error = e;
}); }
expect(error.toString()).toContain(`You can't make changes on the basic data of an confirmed order or with rows`); const expectedError = `You can't make changes on the basic data of an confirmed order or with rows`;
expect(error).toEqual(new UserError(expectedError));
}); });
it('should skip invalid params', async() => { it('should skip invalid params', async() => {
const tx = await models.Order.beginTransaction({});
try {
const options = {transaction: tx};
let success; let success;
let invalidparams = {invalid: 'param for update'}; const invalidparams = {invalid: 'param for update'};
await app.models.Order.updateBasicData(orderId, invalidparams) await models.Order.updateBasicData(orderId, invalidparams, options)
.then(() => success = true); .then(() => success = true);
expect(success).toBeTruthy(); expect(success).toBeTruthy();
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should update the client fiscal data and return the count if changes made', async() => { it('should update the client fiscal data and return the count if changes made', async() => {
let validparams = {note: 'test note'}; const tx = await models.Order.beginTransaction({});
let order = await app.models.Order.findById(orderId); try {
const options = {transaction: tx};
const validparams = {note: 'test note'};
const order = await models.Order.findById(orderId, null, options);
expect(order.note).toEqual(null); expect(order.note).toEqual(null);
let result = await app.models.Order.updateBasicData(orderId, validparams); const result = await models.Order.updateBasicData(orderId, validparams, options);
expect(result.note).toEqual('test note'); expect(result.note).toEqual('test note');
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
}); });

View File

@ -19,17 +19,22 @@ module.exports = Self => {
} }
}); });
Self.summary = async orderId => { Self.summary = async(orderId, options) => {
let models = Self.app.models; const models = Self.app.models;
let summary = await getOrderData(Self, orderId); const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
const summary = await getOrderData(Self, orderId, myOptions);
summary.subTotal = getSubTotal(summary.rows); summary.subTotal = getSubTotal(summary.rows);
summary.VAT = await models.Order.getVAT(orderId); summary.VAT = await models.Order.getVAT(orderId, myOptions);
summary.total = await models.Order.getTotal(orderId); summary.total = await models.Order.getTotal(orderId, myOptions);
return summary; return summary;
}; };
async function getOrderData(Self, orderId) { async function getOrderData(Self, orderId, options) {
let filter = { const filter = {
include: [ include: [
{ {
relation: 'agencyMode', scope: {fields: ['name']}}, relation: 'agencyMode', scope: {fields: ['name']}},
@ -69,7 +74,7 @@ module.exports = Self => {
where: {id: orderId} where: {id: orderId}
}; };
return await Self.findOne(filter); return Self.findOne(filter, options);
} }
function getSubTotal(rows) { function getSubTotal(rows) {

View File

@ -31,16 +31,27 @@ module.exports = Self => {
} }
}); });
Self.updateBasicData = async(id, params) => { Self.updateBasicData = async(id, params, options) => {
let models = Self.app.models; const models = Self.app.models;
const myOptions = {};
let tx;
let order = await models.Order.findById(id); if (typeof options == 'object')
let orderRows = await models.OrderRow.find({where: {orderFk: id}}); Object.assign(myOptions, options);
if (!myOptions.transaction) {
tx = await Self.beginTransaction({});
myOptions.transaction = tx;
}
try {
const order = await models.Order.findById(id, null, myOptions);
const orderRows = await models.OrderRow.find({where: {orderFk: id}}, myOptions);
if (order.isConfirmed || orderRows.length != 0) if (order.isConfirmed || orderRows.length != 0)
throw new UserError(`You can't make changes on the basic data of an confirmed order or with rows`); throw new UserError(`You can't make changes on the basic data of an confirmed order or with rows`);
let updateParams = pick(params, [ const updateParams = pick(params, [
'clientFk', 'clientFk',
'addressFk', 'addressFk',
'landed', 'landed',
@ -48,8 +59,14 @@ module.exports = Self => {
'note', 'note',
]); ]);
if (Object.keys(updateParams).length) if (Object.keys(updateParams).length)
await order.updateAttributes(updateParams); await order.updateAttributes(updateParams, myOptions);
return await order; if (tx) await tx.commit();
return order;
} catch (e) {
if (tx) await tx.rollback();
throw e;
}
}; };
}; };

View File

@ -1,5 +1,5 @@
You can't create an order for a frozen client: No puedes crear una orden a un cliente congelado You can't create an order for a frozen client: No puedes crear una orden a un cliente congelado
You can't create an order for a inactive client: No puedes crear una orden a un cliente inactivo You can't create an order for an inactive client: No puedes crear una orden a un cliente inactivo
You can't create an order for a client that doesn't has tax data verified: You can't create an order for a client that doesn't has tax data verified:
No puedes crear una orden a un cliente cuyos datos fiscales no han sido verificados No puedes crear una orden a un cliente cuyos datos fiscales no han sido verificados
You can't create an order for a client that has a debt: No puedes crear una orden a un cliente que tiene deuda You can't create an order for a client that has a debt: No puedes crear una orden a un cliente que tiene deuda