Merge branch 'dev' into 3423-ticket_sale
gitea/salix/pipeline/head This commit looks good Details

This commit is contained in:
Carlos Jimenez Ruiz 2021-12-20 10:01:08 +00:00
commit 1440f29784
64 changed files with 1644 additions and 629 deletions

View File

@ -618,8 +618,10 @@ INSERT INTO `vn`.`ticket`(`id`, `priority`, `agencyModeFk`,`warehouseFk`,`routeF
(21, NULL, 5, 5, 5, DATE_ADD(CURDATE(), INTERVAL +1 MONTH), DATE_ADD(DATE_ADD(CURDATE(),INTERVAL +1 MONTH), INTERVAL +1 DAY), 1109, 'Somewhere in Holland', 102, NULL, 0, 13, 5, 1, DATE_ADD(CURDATE(), INTERVAL +1 MONTH)), (21, NULL, 5, 5, 5, DATE_ADD(CURDATE(), INTERVAL +1 MONTH), DATE_ADD(DATE_ADD(CURDATE(),INTERVAL +1 MONTH), INTERVAL +1 DAY), 1109, 'Somewhere in Holland', 102, NULL, 0, 13, 5, 1, DATE_ADD(CURDATE(), INTERVAL +1 MONTH)),
(22, NULL, 5, 5, 5, DATE_ADD(CURDATE(), INTERVAL +1 MONTH), DATE_ADD(DATE_ADD(CURDATE(),INTERVAL +1 MONTH), INTERVAL +1 DAY), 1109, 'Somewhere in Japan', 103, NULL, 0, 13, 5, 1, DATE_ADD(CURDATE(), INTERVAL +1 MONTH)), (22, NULL, 5, 5, 5, DATE_ADD(CURDATE(), INTERVAL +1 MONTH), DATE_ADD(DATE_ADD(CURDATE(),INTERVAL +1 MONTH), INTERVAL +1 DAY), 1109, 'Somewhere in Japan', 103, NULL, 0, 13, 5, 1, DATE_ADD(CURDATE(), INTERVAL +1 MONTH)),
(23, NULL, 8, 1, 7, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 1101, 'address 21', 121, NULL, 0, 5, 5, 1, CURDATE()), (23, NULL, 8, 1, 7, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 1101, 'address 21', 121, NULL, 0, 5, 5, 1, CURDATE()),
(24 ,NULL, 8, 1, 7, CURDATE(), CURDATE(), 1101, 'Bruce Wayne', 1, NULL, 0, 5, 5, 1, CURDATE()); (24 ,NULL, 8, 1, 7, CURDATE(), CURDATE(), 1101, 'Bruce Wayne', 1, NULL, 0, 5, 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()),
(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'),

View File

@ -127,8 +127,8 @@ describe('Item regularize path', () => {
await page.waitForState('ticket.index'); await page.waitForState('ticket.index');
}); });
it('should search for the ticket with id 25 once again', async() => { it('should search for the ticket with id 28 once again', async() => {
await page.accessToSearchResult('25'); await page.accessToSearchResult('28');
await page.waitForState('ticket.card.summary'); await page.waitForState('ticket.card.summary');
}); });

View File

@ -33,7 +33,7 @@ describe('Ticket index payout path', () => {
await page.waitToClick(selectors.ticketsIndex.openAdvancedSearchButton); await page.waitToClick(selectors.ticketsIndex.openAdvancedSearchButton);
await page.write(selectors.ticketsIndex.advancedSearchClient, '1101'); await page.write(selectors.ticketsIndex.advancedSearchClient, '1101');
await page.keyboard.press('Enter'); await page.keyboard.press('Enter');
await page.waitForNumberOfElements(selectors.ticketsIndex.anySearchResult, 6); await page.waitForNumberOfElements(selectors.ticketsIndex.anySearchResult, 9);
await page.waitToClick(selectors.ticketsIndex.firstTicketCheckbox); await page.waitToClick(selectors.ticketsIndex.firstTicketCheckbox);
await page.waitToClick(selectors.ticketsIndex.secondTicketCheckbox); await page.waitToClick(selectors.ticketsIndex.secondTicketCheckbox);

View File

@ -55,8 +55,8 @@ vn-chip {
&.message, &.message,
&.message.clickable:hover, &.message.clickable:hover,
&.message.clickable:focus { &.message.clickable:focus {
color: $color-font-dark; background-color: $color-font-bg-dark;
background-color: $color-bg-dark; color: $color-font-bg;
} }
&.clickable { &.clickable {
@extend %clickable; @extend %clickable;

View File

@ -1,7 +1,7 @@
@import "variables"; @import "variables";
vn-label { vn-label {
color: $color-font-secondary; color: $color-font-light;
&::after { &::after {
content: ':'; content: ':';

View File

@ -94,8 +94,8 @@ smart-table table {
color: $color-font-bg; color: $color-font-bg;
} }
&.message { &.message {
background-color: $color-bg-dark; background-color: $color-font-bg-dark;
color: $color-font-dark; color: $color-font-bg;
} }
} }
} }

View File

@ -150,8 +150,8 @@ vn-table {
color: $color-font-bg; color: $color-font-bg;
} }
&.message { &.message {
background-color: $color-bg-dark; background-color: $color-font-bg-dark;
color: $color-font-dark; color: $color-font-bg;
} }
} }
vn-icon-menu { vn-icon-menu {

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({});
args: { const options = {transaction: tx};
search: 1
}
};
let result = await app.models.Entry.filter(ctx); try {
const ctx = {
args: {
search: 1
}
};
expect(result.length).toEqual(1); const result = await models.Entry.filter(ctx, options);
expect(result[0].id).toEqual(1);
expect(result.length).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({});
args: { const options = {transaction: tx};
currencyFk: 1
}
};
let result = await app.models.Entry.filter(ctx); try {
const ctx = {
args: {
currencyFk: 1
}
};
expect(result.length).toEqual(8); const result = await models.Entry.filter(ctx, options);
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({});
args: { const options = {transaction: tx};
supplierFk: 2
}
};
let result = await app.models.Entry.filter(ctx); try {
const ctx = {
args: {
supplierFk: 2
}
};
expect(result.length).toEqual(6); const result = await models.Entry.filter(ctx, options);
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({});
args: { const options = {transaction: tx};
companyFk: 442
}
};
let result = await app.models.Entry.filter(ctx); try {
const ctx = {
args: {
companyFk: 442
}
};
expect(result.length).toEqual(7); const result = await models.Entry.filter(ctx, options);
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({});
args: { const options = {transaction: tx};
isBooked: true,
}
};
let result = await app.models.Entry.filter(ctx); try {
const ctx = {
args: {
isBooked: true,
}
};
expect(result.length).toEqual(0); const result = await models.Entry.filter(ctx, options);
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({});
args: { const options = {transaction: tx};
reference: 'movement',
travelFk: '2'
}
};
let result = await app.models.Entry.filter(ctx); try {
const ctx = {
args: {
reference: 'movement',
travelFk: '2'
}
};
expect(result.length).toEqual(2); const result = await models.Entry.filter(ctx, options);
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};
const length = result.length; try {
const anyResult = result[Math.floor(Math.random() * Math.floor(length))]; const result = await models.Entry.getBuys(entryId, options);
expect(result.length).toEqual(4); const length = result.length;
expect(anyResult.item).toBeDefined(); const anyResult = result[Math.floor(Math.random() * Math.floor(length))];
expect(result.length).toEqual(4);
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};
expect(entry.id).toEqual(entryId); try {
const entry = await models.Entry.getEntry(entryId, options);
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 supplierName = entry.supplier().nickname; const options = {transaction: tx};
expect(supplierName).toEqual('Plants nick'); try {
const entry = await models.Entry.getEntry(entryId, options);
const supplierName = entry.supplier().nickname;
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 receiverWarehouseName = entry.travel().warehouseIn().name; const options = {transaction: tx};
expect(receiverWarehouseName).toEqual('Warehouse One'); try {
const entry = await models.Entry.getEntry(entryId, options);
const receiverWarehouseName = entry.travel().warehouseIn().name;
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 companyCode = entry.company().code; const options = {transaction: tx};
expect(companyCode).toEqual('VNL'); try {
const entry = await models.Entry.getEntry(entryId, options);
const companyCode = entry.company().code;
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,30 +10,40 @@ describe('entry importBuysPreview()', () => {
}); });
it('should return the buys with the calculated packageFk', async() => { it('should return the buys with the calculated packageFk', async() => {
const expectedPackageFk = '3'; const tx = await models.Entry.beginTransaction({});
const buys = [ const options = {transaction: tx};
{
itemFk: 1,
buyingValue: 5.77,
description: 'Bow',
grouping: 1,
size: 1,
volume: 1200
},
{
itemFk: 4,
buyingValue: 2.16,
description: 'Arrow',
grouping: 1,
size: 25,
volume: 1125
}
];
const result = await app.models.Entry.importBuysPreview(entryId, buys); try {
const randomIndex = Math.floor(Math.random() * result.length); const expectedPackageFk = '3';
const buy = result[randomIndex]; const buys = [
{
itemFk: 1,
buyingValue: 5.77,
description: 'Bow',
grouping: 1,
size: 1,
volume: 1200
},
{
itemFk: 4,
buyingValue: 2.16,
description: 'Arrow',
grouping: 1,
size: 25,
volume: 1125
}
];
expect(buy.packageFk).toEqual(expectedPackageFk); const result = await models.Entry.importBuysPreview(entryId, buys, options);
const randomIndex = Math.floor(Math.random() * result.length);
const buy = result[randomIndex];
expect(buy.packageFk).toEqual(expectedPackageFk);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
}); });

View File

@ -1,195 +1,345 @@
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({});
args: { const options = {transaction: tx};
search: 'Ranged weapon longbow 2m'
}
};
let results = await app.models.Buy.latestBuysFilter(ctx); try {
let firstBuy = results[0]; const ctx = {
args: {
search: 'Ranged weapon longbow 2m'
}
};
expect(results.length).toEqual(1); const results = await models.Buy.latestBuysFilter(ctx);
expect(firstBuy.size).toEqual(70); const firstBuy = results[0];
expect(results.length).toEqual(1);
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({});
args: { const options = {transaction: tx};
id: 1
}
};
let results = await app.models.Buy.latestBuysFilter(ctx); try {
const ctx = {
args: {
id: 1
}
};
expect(results.length).toEqual(1); const results = await models.Buy.latestBuysFilter(ctx, options);
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({});
args: { const options = {transaction: tx};
tags: [
{tagFk: 27, value: '2m'}
]
}
};
let results = await app.models.Buy.latestBuysFilter(ctx); try {
const ctx = {
args: {
tags: [
{tagFk: 27, value: '2m'}
]
}
};
expect(results.length).toBe(2); const results = await models.Buy.latestBuysFilter(ctx, options);
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({});
args: { const options = {transaction: tx};
categoryFk: 1
}
};
let results = await app.models.Buy.latestBuysFilter(ctx); try {
const ctx = {
args: {
categoryFk: 1
}
};
expect(results.length).toBe(4); const results = await models.Buy.latestBuysFilter(ctx, options);
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({});
args: { const options = {transaction: tx};
typeFk: 2
}
};
let results = await app.models.Buy.latestBuysFilter(ctx); try {
const ctx = {
args: {
typeFk: 2
}
};
expect(results.length).toBe(4); const results = await models.Buy.latestBuysFilter(ctx, options);
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({});
args: { const options = {transaction: tx};
active: true
}
};
let results = await app.models.Buy.latestBuysFilter(ctx); try {
const ctx = {
args: {
active: true
}
};
expect(results.length).toBe(6); const results = await models.Buy.latestBuysFilter(ctx, options);
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({});
args: { const options = {transaction: tx};
active: false
}
};
let results = await app.models.Buy.latestBuysFilter(ctx); try {
const ctx = {
args: {
active: false
}
};
expect(results.length).toBe(0); const results = await models.Buy.latestBuysFilter(ctx, options);
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({});
args: { const options = {transaction: tx};
visible: true
}
};
let results = await app.models.Buy.latestBuysFilter(ctx); try {
const ctx = {
args: {
visible: true
}
};
expect(results.length).toBe(5); const results = await models.Buy.latestBuysFilter(ctx, options);
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({});
args: { const options = {transaction: tx};
visible: false
}
};
let results = await app.models.Buy.latestBuysFilter(ctx); try {
const ctx = {
args: {
visible: false
}
};
expect(results.length).toBe(0); const results = await models.Buy.latestBuysFilter(ctx, options);
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({});
args: { const options = {transaction: tx};
floramondo: true
}
};
let results = await app.models.Buy.latestBuysFilter(ctx); try {
const ctx = {
args: {
floramondo: true
}
};
expect(results.length).toBe(1); const results = await models.Buy.latestBuysFilter(ctx, options);
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({});
args: { const options = {transaction: tx};
floramondo: false
}
};
let results = await app.models.Buy.latestBuysFilter(ctx); try {
const ctx = {
args: {
floramondo: false
}
};
expect(results.length).toBe(5); const results = await models.Buy.latestBuysFilter(ctx, options);
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({});
args: { const options = {transaction: tx};
salesPersonFk: 35
}
};
let results = await app.models.Buy.latestBuysFilter(ctx); try {
const ctx = {
args: {
salesPersonFk: 35
}
};
expect(results.length).toBe(6); const results = await models.Buy.latestBuysFilter(ctx, options);
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({});
args: { const options = {transaction: tx};
description: 'Increases block'
}
};
let results = await app.models.Buy.latestBuysFilter(ctx); try {
const ctx = {
args: {
description: 'Increases block'
}
};
expect(results.length).toBe(1); const results = await models.Buy.latestBuysFilter(ctx, options);
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({});
args: { const options = {transaction: tx};
supplierFk: 1
}
};
let results = await app.models.Buy.latestBuysFilter(ctx); try {
const ctx = {
args: {
supplierFk: 1
}
};
expect(results.length).toBe(2); const results = await models.Buy.latestBuysFilter(ctx, options);
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 from = new Date(); const tx = await models.Buy.beginTransaction({});
from.setHours(0, 0, 0, 0); const options = {transaction: tx};
const to = new Date(); try {
to.setHours(23, 59, 59, 999); const from = new Date();
from.setHours(0, 0, 0, 0);
let ctx = { const to = new Date();
args: { to.setHours(23, 59, 59, 999);
from: from,
to: to
}
};
let results = await app.models.Buy.latestBuysFilter(ctx); const ctx = {
args: {
from: from,
to: to
}
};
expect(results.length).toBe(2); const results = await models.Buy.latestBuysFilter(ctx, options);
expect(results.length).toBe(2);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
}); });

View File

@ -160,7 +160,7 @@ module.exports = Self => {
stmts.push('DROP TEMPORARY TABLE IF EXISTS tmp.filter'); stmts.push('DROP TEMPORARY TABLE IF EXISTS tmp.filter');
stmt = new ParameterizedSQL( stmt = new ParameterizedSQL(
`CREATE TEMPORARY TABLE tmp.filter `CREATE TEMPORARY TABLE tmp.filter
(INDEX (id)) (PRIMARY KEY (id))
ENGINE = MEMORY ENGINE = MEMORY
SELECT SELECT
t.id, t.id,
@ -221,7 +221,7 @@ module.exports = Self => {
stmts.push('DROP TEMPORARY TABLE IF EXISTS tmp.clientGetDebt'); stmts.push('DROP TEMPORARY TABLE IF EXISTS tmp.clientGetDebt');
stmts.push(` stmts.push(`
CREATE TEMPORARY TABLE tmp.clientGetDebt CREATE TEMPORARY TABLE tmp.clientGetDebt
(INDEX (clientFk)) (PRIMARY KEY (clientFk))
ENGINE = MEMORY ENGINE = MEMORY
SELECT DISTINCT clientFk FROM tmp.filter`); SELECT DISTINCT clientFk FROM tmp.filter`);
@ -232,7 +232,7 @@ module.exports = Self => {
stmts.push('DROP TEMPORARY TABLE IF EXISTS tmp.tickets'); stmts.push('DROP TEMPORARY TABLE IF EXISTS tmp.tickets');
stmt = new ParameterizedSQL(` stmt = new ParameterizedSQL(`
CREATE TEMPORARY TABLE tmp.tickets CREATE TEMPORARY TABLE tmp.tickets
(INDEX (id)) (PRIMARY KEY (id))
ENGINE = MEMORY ENGINE = MEMORY
SELECT f.*, r.risk AS debt SELECT f.*, r.risk AS debt
FROM tmp.filter f FROM tmp.filter f

View File

@ -11,7 +11,7 @@ describe('SalesMonitor salesFilter()', () => {
const filter = {order: 'id DESC'}; const filter = {order: 'id DESC'};
const result = await models.SalesMonitor.salesFilter(ctx, filter, options); const result = await models.SalesMonitor.salesFilter(ctx, filter, options);
expect(result.length).toEqual(24); expect(result.length).toEqual(27);
await tx.rollback(); await tx.rollback();
} catch (e) { } catch (e) {
@ -39,7 +39,7 @@ describe('SalesMonitor salesFilter()', () => {
const filter = {}; const filter = {};
const result = await models.SalesMonitor.salesFilter(ctx, filter, options); const result = await models.SalesMonitor.salesFilter(ctx, filter, options);
expect(result.length).toEqual(13); expect(result.length).toEqual(16);
await tx.rollback(); await tx.rollback();
} catch (e) { } catch (e) {
@ -87,7 +87,7 @@ describe('SalesMonitor salesFilter()', () => {
const filter = {}; const filter = {};
const result = await models.SalesMonitor.salesFilter(ctx, filter, options); const result = await models.SalesMonitor.salesFilter(ctx, filter, options);
expect(result.length).toEqual(24); expect(result.length).toEqual(27);
await tx.rollback(); await tx.rollback();
} catch (e) { } catch (e) {
@ -130,7 +130,7 @@ describe('SalesMonitor salesFilter()', () => {
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(length).toEqual(7); expect(length).toEqual(10);
expect(anyResult.state).toMatch(/(Libre|Arreglar)/); expect(anyResult.state).toMatch(/(Libre|Arreglar)/);
await tx.rollback(); await tx.rollback();
@ -175,7 +175,7 @@ describe('SalesMonitor salesFilter()', () => {
const filter = {}; const filter = {};
const result = await models.SalesMonitor.salesFilter(ctx, filter, options); const result = await models.SalesMonitor.salesFilter(ctx, filter, options);
expect(result.length).toEqual(20); expect(result.length).toEqual(23);
await tx.rollback(); await tx.rollback();
} catch (e) { } catch (e) {

View File

@ -2,7 +2,7 @@
vn-id="model" vn-id="model"
url="SalesMonitors/salesFilter" url="SalesMonitors/salesFilter"
limit="20" limit="20"
order="shippedDate DESC, preparationHour ASC, zoneLanding ASC, id"> order="shippedDate DESC, theoreticalhour, id">
</vn-crud-model> </vn-crud-model>
<vn-portal slot="topbar"> <vn-portal slot="topbar">
<vn-searchbar <vn-searchbar
@ -167,7 +167,7 @@
{{::ticket.state}} {{::ticket.state}}
</span> </span>
</td> </td>
<td> <td name="zone">
<span <span
title="{{::ticket.zoneName}}" title="{{::ticket.zoneName}}"
vn-click-stop="zoneDescriptor.show($event, ticket.zoneFk)" vn-click-stop="zoneDescriptor.show($event, ticket.zoneFk)"

View File

@ -36,4 +36,12 @@ vn-monitor-sales-tickets {
.highRisk i { .highRisk i {
color: $color-alert color: $color-alert
} }
td[name="nickname"] {
max-width: 200px
}
td[name="zone"] {
max-width: 150px
}
} }

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 (!isEditable) if (typeof options == 'object')
throw new UserError('This order is not editable'); Object.assign(myOptions, options);
let promises = []; if (!myOptions.transaction) {
params.items.forEach(item => { tx = await Self.beginTransaction({});
promises.push( myOptions.transaction = tx;
Self.rawSql( }
`CALL hedera.order_addItem(?, ?, ?, ?)`,
[params.orderFk, item.warehouseFk, item.itemFk, item.quantity] try {
) const isEditable = await Self.app.models.Order.isEditable(params.orderFk, myOptions);
);
}); if (!isEditable)
await Promise.all(promises); throw new UserError('This order is not editable');
return true;
const promises = [];
for (const item of params.items) {
promises.push(
Self.rawSql(
`CALL hedera.order_addItem(?, ?, ?, ?)`,
[params.orderFk, item.warehouseFk, item.itemFk, item.quantity],
myOptions
)
);
}
await Promise.all(promises);
if (tx) await tx.commit();
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) => {
if (!params.rows || !params.rows.length) const myOptions = {};
throw new UserError('There is nothing to delete'); let tx;
let isEditable = await Self.app.models.Order.isEditable(params.actualOrderId); if (typeof options == 'object')
Object.assign(myOptions, options);
if (!isEditable) if (!myOptions.transaction) {
throw new UserError('This order is not editable'); tx = await Self.beginTransaction({});
myOptions.transaction = tx;
}
let promises = []; try {
for (let i = 0; i < params.rows.length; i++) if (!params.rows || !params.rows.length)
promises.push(Self.app.models.OrderRow.destroyById(params.rows[i])); throw new UserError('There is nothing to delete');
return await Promise.all(promises); const isEditable = await Self.app.models.Order.isEditable(params.actualOrderId, myOptions);
if (!isEditable)
throw new UserError('This order is not editable');
const promises = [];
for (let i = 0; i < params.rows.length; i++)
promises.push(Self.app.models.OrderRow.destroyById(params.rows[i], myOptions));
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,32 +1,36 @@
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({});
expect(unmodifiedRows.length).toBe(2); try {
const options = {transaction: tx};
let params = { const unmodifiedRows = await models.OrderRow.find({where: {orderFk: orderId}}, options);
orderFk: orderId,
items: [{
itemFk: 1,
quantity: 10,
warehouseFk: 1
}]
};
await app.models.OrderRow.addToOrder(params); expect(unmodifiedRows.length).toBe(2);
let modifiedRows = await app.models.OrderRow.find({where: {orderFk: orderId}}); const params = {
orderFk: orderId,
items: [{
itemFk: 1,
quantity: 10,
warehouseFk: 1
}]
};
rowToDelete = modifiedRows[modifiedRows.length - 1].id; await models.OrderRow.addToOrder(params, options);
expect(modifiedRows.length).toBe(3); const modifiedRows = await models.OrderRow.find({where: {orderFk: orderId}}, options);
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],
actualOrderId: 16
};
let res = await app.models.OrderRow.removes(params); try {
const options = {transaction: tx};
expect(res).toEqual([{count: 1}]); const params = {
rows: [12],
actualOrderId: 16
};
const res = await models.OrderRow.removes(params, options);
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,34 +32,52 @@ 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 = {};
where: {id: addressId}, let tx;
fields: ['clientFk'],
include: [
{relation: 'client',
scope: {
include: {
relation: 'type'
}
}
}
]
});
if (address.client().type().code === 'normal') { if (typeof options == 'object')
if (!address.client().isActive) Object.assign(myOptions, options);
throw new UserError(`You can't create an order for a inactive client`);
if (!myOptions.transaction) {
tx = await Self.beginTransaction({});
myOptions.transaction = tx;
} }
query = `CALL vn.orderListCreate(?, ?, ?, ?);`; try {
[result] = await Self.rawSql(query, [ const address = await Self.app.models.Address.findOne({
landed, where: {id: addressId},
agencyModeId, fields: ['clientFk'],
addressId, include: [
'SALIX' {relation: 'client',
]); scope: {
include: {
relation: 'type'
}
}
}
]
}, myOptions);
return result[0].vOrderId; if (address.client().type().code === 'normal') {
if (!address.client().isActive)
throw new UserError(`You can't create an order for an inactive client`);
}
query = `CALL vn.orderListCreate(?, ?, ?, ?);`;
[result] = await Self.rawSql(query, [
landed,
agencyModeId,
addressId,
'SALIX'
], myOptions);
if (tx) await tx.commit();
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 = {};
where: {id: ticketFk} let tx;
});
let landed = ticket.landed; if (typeof options == 'object')
let addressFk = ticket.addressFk; Object.assign(myOptions, options);
let agencyModeFk = ticket.agencyModeFk;
let orderID = await Self.app.models.Order.new(landed, addressFk, agencyModeFk); if (!myOptions.transaction) {
tx = await Self.beginTransaction({});
myOptions.transaction = tx;
}
return orderID; try {
const ticket = await Self.app.models.Ticket.findOne({
where: {id: ticketFk}
}, myOptions);
const landed = ticket.landed;
const addressFk = ticket.addressFk;
const agencyModeFk = ticket.agencyModeFk;
const orderID = await Self.app.models.Order.new(landed, addressFk, agencyModeFk, myOptions);
if (tx) await tx.commit();
return orderID;
} catch (e) {
if (tx) await tx.rollback();
throw e;
}
}; };
}; };

View File

@ -1,51 +1,73 @@
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({});
where: {
categoryFk: 1,
typeFk: 2
}
};
let tags = [];
let orderFk = 11;
let orderBy = {field: 'relevancy DESC, name', way: 'DESC'};
let result = await app.models.Order.catalogFilter(orderFk, orderBy, filter, tags);
let firstItemId = result[0].id;
expect(result.length).toEqual(4); try {
expect(firstItemId).toEqual(1); const options = {transaction: tx};
const filter = {
where: {
categoryFk: 1,
typeFk: 2
}
};
const tags = [];
const orderFk = 11;
const orderBy = {field: 'relevancy DESC, name', way: 'DESC'};
const result = await models.Order.catalogFilter(orderFk, orderBy, filter, tags, options);
const firstItemId = result[0].id;
expect(result.length).toEqual(4);
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 filter = { const tx = await models.Order.beginTransaction({});
where: {
categoryFk: 1,
typeFk: 2
}
};
const tagGroups = [ try {
{tagFk: colorTagId, values: [{value: 'Silver'}, {value: 'Brown'}]}, const options = {transaction: tx};
{tagFk: categoryTagId, values: [{value: 'Concussion'}]}
];
const orderFk = 11;
const orderBy = {field: 'relevancy DESC, name', way: 'DESC'};
const result = await app.models.Order.catalogFilter(orderFk, orderBy, filter, tagGroups);
const randomIndex = Math.round(Math.random()); const filter = {
const item = result[randomIndex]; where: {
const itemTags = item.tags; categoryFk: 1,
typeFk: 2
}
};
const colorTag = itemTags.find(tag => tag.tagFk == colorTagId); const tagGroups = [
const categoryTag = itemTags.find(tag => tag.tagFk == categoryTagId); {tagFk: colorTagId, values: [{value: 'Silver'}, {value: 'Brown'}]},
{tagFk: categoryTagId, values: [{value: 'Concussion'}]}
];
const orderFk = 11;
const orderBy = {field: 'relevancy DESC, name', way: 'DESC'};
const result = await models.Order.catalogFilter(orderFk, orderBy, filter, tagGroups, options);
expect(result.length).toEqual(2); const randomIndex = Math.round(Math.random());
expect(colorTag.value).toEqual('Silver'); const item = result[randomIndex];
expect(categoryTag.value).toEqual('Concussion'); const itemTags = item.tags;
const colorTag = itemTags.find(tag => tag.tagFk == colorTagId);
const categoryTag = itemTags.find(tag => tag.tagFk == categoryTagId);
expect(result.length).toEqual(2);
expect(colorTag.value).toEqual('Silver');
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 filter = {where: {'o.id': 2}}; const myCtx = Object.assign({}, ctx);
const result = await app.models.Order.filter(ctx, filter); const tx = await models.Order.beginTransaction({});
const orderId = result[0].id;
expect(orderId).toEqual(2); try {
const options = {transaction: tx};
const filter = {where: {'o.id': 2}};
const result = await models.Order.filter(myCtx, filter, options);
const orderId = result[0].id;
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 filter = {where: {'o.confirmed': false}}; const myCtx = Object.assign({}, ctx);
const result = await app.models.Order.filter(ctx, filter); const tx = await models.Order.beginTransaction({});
expect(result.length).toEqual(16); try {
const options = {transaction: tx};
const filter = {where: {'o.confirmed': false}};
const result = await models.Order.filter(myCtx, filter, options);
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 filter = {where: {'o.confirmed': false, 'c.salesPersonFk': 18}}; const myCtx = Object.assign({}, ctx);
const result = await app.models.Order.filter(ctx, filter); const tx = await models.Order.beginTransaction({});
expect(result.length).toEqual(9); try {
expect(result[0].id).toEqual(7); const options = {transaction: tx};
const filter = {where: {'o.confirmed': false, 'c.salesPersonFk': 18}};
const result = await models.Order.filter(myCtx, filter, options);
expect(result.length).toEqual(9);
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 filter = {}; const myCtx = Object.assign({}, ctx);
ctx.args = {showEmpty: false}; const tx = await models.Order.beginTransaction({});
const result = await app.models.Order.filter(ctx, filter);
const hasEmptyLines = result.some(order => {
return order.total === 0;
});
expect(hasEmptyLines).toBeFalsy(); try {
const options = {transaction: tx};
ctx.args = {showEmpty: null}; const filter = {};
myCtx.args = {showEmpty: false};
const result = await models.Order.filter(myCtx, filter, options);
const hasEmptyLines = result.some(order => {
return order.total === 0;
});
expect(hasEmptyLines).toBeFalsy();
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 filter = {}; const myCtx = Object.assign({}, ctx);
ctx.args = {showEmpty: true}; const tx = await models.Order.beginTransaction({});
const result = await app.models.Order.filter(ctx, filter);
const hasEmptyLines = result.some(order => {
return order.total === 0;
});
expect(hasEmptyLines).toBeTruthy(); try {
const options = {transaction: tx};
ctx.args = {showEmpty: null}; const filter = {};
myCtx.args = {showEmpty: true};
const result = await models.Order.filter(myCtx, filter, options);
const hasEmptyLines = result.some(order => {
return order.total === 0;
});
expect(hasEmptyLines).toBeTruthy();
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);
expect(result.length).toEqual(1); 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);
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);
expect(result.length).toEqual(0); 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);
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({});
expect(result.length).toEqual(0); try {
const options = {transaction: tx};
const result = await models.Order.getTaxes('string', options);
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({});
expect(result.length).toEqual(0); try {
const options = {transaction: tx};
const result = await models.Order.getTaxes(9999, options);
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({});
const expectedResult = result[0].tax + result[1].tax; try {
const options = {transaction: tx};
expect(expectedResult).toEqual(20.29); const result = await models.Order.getTaxes(1, options);
expect(result.length).toEqual(2);
const expectedResult = result[0].tax + result[1].tax;
expect(expectedResult).toEqual(20.29);
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({});
expect(result[0].tax).toEqual(9.1); try {
expect(result.length).toEqual(1); const options = {transaction: tx};
const result = await models.Order.getTaxes(2, options);
expect(result[0].tax).toEqual(9.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({});
expect(result).toEqual(155.89); try {
const options = {transaction: tx};
const result = await models.Order.getTotal(1, options);
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({});
expect(result.totalVolume).toEqual(1.568); try {
expect(result.totalBoxes).toEqual(11.1); const options = {transaction: tx};
const result = await models.Order.getTotalVolume(1, options);
expect(result.totalVolume).toEqual(1.568);
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({});
expect(result).toEqual(20.29); try {
const options = {transaction: tx};
const result = await models.Order.getVAT(1, options);
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({});
expect(result.volume).toEqual(1.09); try {
const options = {transaction: tx};
const [result] = await models.Order.getVolumes(1, options);
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({});
expect(isEditable).toBeFalsy(); try {
const options = {transaction: tx};
const isEditable = await models.Order.isEditable(2, options);
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({});
expect(isEditable).toBeFalsy(); try {
const options = {transaction: tx};
const isEditable = await models.Order.isEditable(999, options);
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({});
expect(isEditable).toBeTruthy(); try {
const options = {transaction: tx};
const isEditable = await models.Order.isEditable(16, options);
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;
error = e; const agencyModeFk = 1;
});
expect(error).toEqual(new UserError(`You can't create an order for a inactive client`)); await models.Order.new(landed, addressFk, agencyModeFk, options);
await tx.rollback();
} catch (e) {
await tx.rollback();
error = e;
}
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;
expect(orderId).toBeGreaterThan(highestOrderIdInFixtures); orderId = await models.Order.new(landed, addressFk, agencyModeFk, options);
const highestOrderIdInFixtures = 3;
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({});
expect(result.id).toEqual(1); try {
expect(result.clientFk).toEqual(1101); const options = {transaction: tx};
const result = await models.Order.summary(1, options);
expect(result.id).toEqual(1);
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({});
expect(result.rows.length).toEqual(3); try {
const options = {transaction: tx};
const result = await models.Order.summary(1, options);
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({});
expect(Math.round(result.subTotal * 100) / 100).toEqual(135.60); try {
const options = {transaction: tx};
const result = await models.Order.summary(1, options);
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({});
expect(Math.round(result.VAT * 100) / 100).toEqual(20.29); try {
const options = {transaction: tx};
const result = await models.Order.summary(1, options);
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;
expect(result.total).toEqual(expectedTotal); 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);
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) {
error = e; await tx.rollback();
}); 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 => {
error = e;
});
expect(error.toString()).toContain(`You can't make changes on the basic data of an confirmed order or with rows`); await tx.rollback();
} catch (e) {
await tx.rollback();
error = e;
}
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() => {
let success; const tx = await models.Order.beginTransaction({});
let invalidparams = {invalid: 'param for update'}; try {
const options = {transaction: tx};
let success;
await app.models.Order.updateBasicData(orderId, invalidparams) const invalidparams = {invalid: 'param for update'};
.then(() => success = true);
expect(success).toBeTruthy(); await models.Order.updateBasicData(orderId, invalidparams, options)
.then(() => success = true);
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};
expect(order.note).toEqual(null); const validparams = {note: 'test note'};
let result = await app.models.Order.updateBasicData(orderId, validparams); const order = await models.Order.findById(orderId, null, options);
expect(result.note).toEqual('test note'); expect(order.note).toEqual(null);
const result = await models.Order.updateBasicData(orderId, validparams, options);
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,25 +31,42 @@ 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 (order.isConfirmed || orderRows.length != 0) if (!myOptions.transaction) {
throw new UserError(`You can't make changes on the basic data of an confirmed order or with rows`); tx = await Self.beginTransaction({});
myOptions.transaction = tx;
}
let updateParams = pick(params, [ try {
'clientFk', const order = await models.Order.findById(id, null, myOptions);
'addressFk', const orderRows = await models.OrderRow.find({where: {orderFk: id}}, myOptions);
'landed',
'agencyModeFk',
'note',
]);
if (Object.keys(updateParams).length)
await order.updateAttributes(updateParams);
return await order; 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`);
const updateParams = pick(params, [
'clientFk',
'addressFk',
'landed',
'agencyModeFk',
'note',
]);
if (Object.keys(updateParams).length)
await order.updateAttributes(updateParams, myOptions);
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

View File

@ -29,9 +29,9 @@ describe('route getSuggestedTickets()', () => {
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(1); expect(result.length).toEqual(4);
expect(anyResult.zoneFk).toEqual(1); expect(anyResult.zoneFk).toEqual(1);
expect(anyResult.agencyModeFk).toEqual(1); expect(anyResult.agencyModeFk).toEqual(8);
await tx.rollback(); await tx.rollback();
} catch (e) { } catch (e) {

View File

@ -11,7 +11,7 @@ describe('ticket filter()', () => {
const filter = {order: 'id DESC'}; const filter = {order: 'id DESC'};
const result = await models.Ticket.filter(ctx, filter, options); const result = await models.Ticket.filter(ctx, filter, options);
expect(result.length).toEqual(24); expect(result.length).toEqual(27);
await tx.rollback(); await tx.rollback();
} catch (e) { } catch (e) {
@ -87,7 +87,7 @@ describe('ticket filter()', () => {
const filter = {}; const filter = {};
const result = await models.Ticket.filter(ctx, filter, options); const result = await models.Ticket.filter(ctx, filter, options);
expect(result.length).toEqual(24); expect(result.length).toEqual(27);
await tx.rollback(); await tx.rollback();
} catch (e) { } catch (e) {
@ -130,7 +130,7 @@ describe('ticket filter()', () => {
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(length).toEqual(7); expect(length).toEqual(10);
expect(anyResult.state).toMatch(/(Libre|Arreglar)/); expect(anyResult.state).toMatch(/(Libre|Arreglar)/);
await tx.rollback(); await tx.rollback();
@ -175,7 +175,7 @@ describe('ticket filter()', () => {
const filter = {}; const filter = {};
const result = await models.Ticket.filter(ctx, filter, options); const result = await models.Ticket.filter(ctx, filter, options);
expect(result.length).toEqual(20); expect(result.length).toEqual(23);
await tx.rollback(); await tx.rollback();
} catch (e) { } catch (e) {

View File

@ -0,0 +1,8 @@
const Stylesheet = require(`${appPath}/core/stylesheet`);
module.exports = new Stylesheet([
`${appPath}/common/css/layout.css`,
`${appPath}/common/css/report.css`,
`${appPath}/common/css/misc.css`,
`${__dirname}/style.css`])
.mergeStyles();

View File

@ -0,0 +1,31 @@
.grid-block {
font-size: 1.2em
}
.signature .dummy-signature {
width: 400px;
height: 190px;
display: block;
content: '';
overflow: hidden;
clear:both
}
.signature img {
width: 400px
}
.signature table {
width: 100%;
font-size: inherit;
border-collapse: separate;
border-spacing: 0 10px;
}
.signature table tr > td:first-child {
width: 50%
}
.signature table tr > td:last-child {
border-bottom: 1px dashed #CCC
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

View File

@ -0,0 +1,99 @@
<!DOCTYPE html>
<html v-bind:lang="$i18n.locale">
<body>
<table class="grid">
<tbody>
<tr>
<td>
<!-- Header block -->
<report-header v-bind="$props"></report-header>
<!-- Block -->
<div class="grid-row">
<div class="grid-block">
<p v-html="$t('description', {
socialName: client.socialName,
name: client.name,
address: client.street,
country: client.country,
fiscalID: client.fi
})"></p>
<p v-html="$t('declaration', {
socialName: client.socialName
})"></p>
<p
v-for="(declaration, $index) in $t('declarations')"
v-html="$t('declarations[' + $index + ']', {
socialName: client.socialName,
destinationCountry: ticket.country,
destinationWarehouse: ticket.warehouse
})">
</p>
<div class="columns">
<div class="size50 signature">
<p class="centered">{{client.name}}</p>
<div class="dummy-signature centered"></div>
<p>
<table>
<tbody>
<tr>
<td>{{$t('signer.representative')}}:</td>
<td></td>
</tr>
<tr>
<td>{{$t('signer.representativeRole')}}:</td>
<td></td>
</tr>
<tr>
<td>{{$t('signer.signed')}}:</td>
<td></td>
</tr>
</tbody>
</table>
</p>
</div>
<div class="size50 signature centered">
<p>{{$t('signature')}}</p>
<img v-bind:src="getReportSrc('signature.png')">
<p>
<div>Juan Vicente Ferrer Roig</div>
<div>Director</div>
<p>{{$t('issued', [
'Algemesí',
issued.getDate(),
$t('months')[issued.getMonth()],
issued.getFullYear()])
}}
</p>
</p>
</div>
</div>
<!-- <div class="signature">
<p>{{$t('issued', [
'Algemesí',
invoice.issued.getDate(),
$t('months')[invoice.issued.getMonth()],
invoice.issued.getFullYear()])
}}
</p>
<p><em>({{$t('signature')}})</em></p>
<img v-bind:src="getReportSrc('signature.png')">
<p>
<div>{{$t('signer.name')}}: JUAN VICENTE FERRER ROIG</div>
<div>{{$t('signer.ID')}}: 73943586N</div>
<div>{{$t('signer.position')}}: ADMINISTRADOR</div>
</p>
</div> -->
</div>
</div>
<!-- Footer block -->
<report-footer id="pageFooter"
v-bind:left-text="$t('client', [client.id])"
v-bind="$props">
</report-footer>
</td>
</tr>
</tbody>
</table>
</body>
</html>

View File

@ -0,0 +1,29 @@
const Component = require(`${appPath}/core/component`);
const reportHeader = new Component('report-header');
const reportFooter = new Component('report-footer');
module.exports = {
name: 'cmr-authorization',
async serverPrefetch() {
this.ticket = await this.findOneFromDef('ticket', [this.ticketId]);
if (!this.ticket)
throw new Error('Something went wrong');
this.client = await this.findOneFromDef('client', [this.ticket.clientFk]);
},
computed: {
issued: function() {
return new Date();
}
},
components: {
'report-header': reportHeader.build(),
'report-footer': reportFooter.build()
},
props: {
ticketId: {
required: true
}
}
};

View File

@ -0,0 +1,41 @@
description: '<em>{socialName}</em> una sociedad debidamente constituida con responsabilidad <em>limitada</em>
y registrada conforme al derecho de sociedades de {country} y aquí representada por
<span>___________________</span>. {socialName}, con domicilio en {address},
CIF <em>{fiscalID}</em>. En adelante denominada {name}.'
issued: 'En {0}, a {1} de {2} de {3}'
client: 'Client {0}'
declaration: '<em>{socialName}</em> declara por la presente que:'
declarations:
- 'Todas las compras realizadas por {socialName} con Verdnatura Levante, S.L. se
entregan, Ex Works (Incoterms), en el almacén de Verdnatura Levante, S.L. situado en
{destinationWarehouse}.'
- '{socialName} reconoce que es importante para Verdnatura Levante, S.L. tener
comprobante de la entrega intracomunitaria de la mercancía a {destinationCountry} para
poder facturar con 0% de IVA.'
- 'Por tanto, al firmar este acuerdo, {socialName} declara que todos los bienes que
se compren a Verdnatura Levante, S.L. serán entregados a {destinationCountry}.'
- 'Además, {socialName} deberá, a primera solicitud de Verdnatura Levante, S.L.,
proporcionar una prueba de que todos los productos comprados a Verdnatura Levante, S.L. han
sido entregados en {destinationCountry}.'
- 'Además de lo anterior, Verdnatura Levante, S.L. proporcionará a {socialName}
un resumen mensual en el que se incluyen todas las facturas (y las entregas correspondientes).
{socialName} firmará y devolverá el resumen mensual a Verdnatura Levante,
S.L. dentro de los 5 días posteriores a la recepción del resumen.'
signature: Verdnatura Levante, S.L.
signer:
representative: Representante
representativeRole: Cargo del representante
signed: Fecha de firma
months:
- 'Enero'
- 'Febrero'
- 'Marzo'
- 'Abril'
- 'Mayo'
- 'Junio'
- 'Julio'
- 'Agosto'
- 'Septiembre'
- 'Octubre'
- 'Noviembre'
- 'Diciembre'

View File

@ -0,0 +1,10 @@
SELECT
c.id,
c.socialName,
c.name,
c.fi,
c.street,
cty.country
FROM client c
JOIN country cty ON cty.id = c.countryFk
WHERE c.id = ?

View File

@ -0,0 +1,12 @@
SELECT
t.id,
t.clientFk,
cty.country,
w.name AS warehouse
FROM ticket t
JOIN warehouse w ON w.id = t.warehouseFk
JOIN address a ON a.id = t.addressFk
JOIN province p ON p.id = a.provinceFk
JOIN autonomy au ON au.id = p.autonomyFk
JOIN country cty ON cty.id = au.countryFk
WHERE t.id = ?