2615-waste_detail #595

Merged
carlosjr merged 7 commits from 2615-waste_detail into dev 2021-04-07 09:27:20 +00:00
43 changed files with 6619 additions and 4733 deletions
Showing only changes of commit 41ee6e70a5 - Show all commits

View File

@ -20,17 +20,37 @@ module.exports = Self => {
} }
}); });
Self.removeFile = async(ctx, id) => { Self.removeFile = async(ctx, id, options) => {
let tx;
let myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
if (!myOptions.transaction) {
tx = await Self.beginTransaction({});
myOptions.transaction = tx;
}
try {
const models = Self.app.models; const models = Self.app.models;
const dms = await models.Dms.findById(id); const dms = await models.Dms.findById(id, null, myOptions);
const trashDmsType = await models.DmsType.findOne({ const trashDmsType = await models.DmsType.findOne({
where: {code: 'trash'} where: {code: 'trash'}
}); }, myOptions);
const hasWriteRole = await models.DmsType.hasWriteRole(ctx, dms.dmsTypeFk); const hasWriteRole = await models.DmsType.hasWriteRole(ctx, dms.dmsTypeFk, myOptions);
if (!hasWriteRole) if (!hasWriteRole)
throw new UserError(`You don't have enough privileges`); throw new UserError(`You don't have enough privileges`);
return dms.updateAttribute('dmsTypeFk', trashDmsType.id); await dms.updateAttribute('dmsTypeFk', trashDmsType.id, myOptions);
if (tx) await tx.commit();
return dms;
} catch (e) {
if (tx) await tx.rollback();
throw e;
}
}; };
}; };

View File

@ -8,25 +8,23 @@
}, },
"properties": { "properties": {
"id": { "id": {
"type": "Number", "type": "number",
"id": true, "id": true,
"description": "The id" "description": "The id"
}, },
"name": { "name": {
"type": "String", "type": "string",
"required": true "required": true
}, },
"collectionFk": { "collectionFk": {
"type": "String", "type": "string",
"required": true "required": true
}, },
"updated": { "updated": {
"type": "Number" "type": "number"
}, },
"nRefs": { "nRefs": {
"type": "Number", "type": "number"
"required": true,
"default": 1
} }
}, },
"relations": { "relations": {

View File

@ -1,4 +0,0 @@
ALTER TABLE `vn`.`department`
ADD code VARCHAR(45) NULL AFTER id;
UPDATE `vn`.`department` t SET t.code = 'IT', t.chatName = 'informatica-cau' WHERE t.id = 31;

View File

@ -1,2 +0,0 @@
ALTER TABLE `vn`.`itemImageQueue`
ADD attempts INT default 0 NULL AFTER error;

View File

@ -1,5 +0,0 @@
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
VALUES
('SupplierAccount', '*', '*', 'ALLOW', 'ROLE', 'administrative'),
('Entry', '*', '*', 'ALLOW', 'ROLE', 'administrative'),
('InvoiceIn', '*', '*', 'ALLOW', 'ROLE', 'administrative');

View File

@ -1,137 +0,0 @@
DROP PROCEDURE `vn`.`item_getBalance`;
DELIMITER $$
$$
CREATE DEFINER=`root`@`%` PROCEDURE `vn`.`item_getBalance`(IN vItemId INT, IN vWarehouse INT)
BEGIN
DECLARE vDateInventory DATETIME;
DECLARE vCurdate DATE DEFAULT CURDATE();
DECLARE vDayEnd DATETIME DEFAULT util.dayEnd(vCurdate);
SELECT inventoried INTO vDateInventory FROM config;
SET @a = 0;
SET @currentLineFk = 0;
SET @shipped = '';
SELECT DATE(@shipped:= shipped) shipped,
alertLevel,
stateName,
origin,
reference,
clientFk,
name,
`in`,
`out`,
@a := @a + IFNULL(`in`,0) - IFNULL(`out`,0) as balance,
@currentLineFk := IF (@shipped < CURDATE()
OR (@shipped = CURDATE() AND (isPicked OR alertLevel >= 2)),
lineFk,@currentLineFk) lastPreparedLineFk,
isTicket,
lineFk,
isPicked,
clientType
FROM
( SELECT tr.landed AS shipped,
b.quantity AS `in`,
NULL AS `out`,
al.alertLevel AS alertLevel,
st.name AS stateName,
s.name AS name,
e.ref AS reference,
e.id AS origin,
s.id AS clientFk,
IF(al.alertLevel = 3, TRUE, FALSE) isPicked,
FALSE AS isTicket,
b.id lineFk,
NULL `order`,
NULL AS clientType
FROM buy b
JOIN entry e ON e.id = b.entryFk
JOIN travel tr ON tr.id = e.travelFk
JOIN supplier s ON s.id = e.supplierFk
JOIN alertLevel al ON al.alertLevel =
CASE
WHEN tr.shipped < CURDATE() THEN 3
WHEN tr.shipped = CURDATE() AND tr.isReceived = TRUE THEN 3
ELSE 0
END
JOIN state st ON st.code = al.code
WHERE tr.landed >= vDateInventory
AND vWarehouse = tr.warehouseInFk
AND b.itemFk = vItemId
AND e.isInventory = FALSE
AND e.isRaid = FALSE
UNION ALL
SELECT tr.shipped,
NULL as `in`,
b.quantity AS `out`,
al.alertLevel AS alertLevel,
st.name AS stateName,
s.name AS name,
e.ref AS reference,
e.id AS origin,
s.id AS clientFk,
IF(al.alertLevel = 3, TRUE, FALSE) isPicked,
FALSE AS isTicket,
b.id,
NULL `order`,
NULL AS clientType
FROM buy b
JOIN entry e ON e.id = b.entryFk
JOIN travel tr ON tr.id = e.travelFk
JOIN warehouse w ON w.id = tr.warehouseOutFk
JOIN supplier s ON s.id = e.supplierFk
JOIN alertLevel al ON al.alertLevel =
CASE
WHEN tr.shipped < CURDATE() THEN 3
WHEN tr.shipped = CURDATE() AND tr.isReceived = TRUE THEN 3
ELSE 0
END
JOIN state st ON st.code = al.code
WHERE tr.shipped >= vDateInventory
AND vWarehouse =tr.warehouseOutFk
AND s.id <> 4
AND b.itemFk = vItemId
AND e.isInventory = FALSE
AND w.isFeedStock = FALSE
AND e.isRaid = FALSE
UNION ALL
SELECT DATE(t.shipped),
NULL as `in`,
s.quantity AS `out`,
al.alertLevel AS alertLevel,
st.name AS stateName,
t.nickname AS name,
t.refFk AS reference,
t.id AS origin,
t.clientFk,
stk.id AS isPicked,
TRUE AS isTicket,
s.id,
st.`order`,
ct.code AS clientType
FROM sale s
JOIN ticket t ON t.id = s.ticketFk
LEFT JOIN ticketState ts ON ts.ticket = t.id
LEFT JOIN state st ON st.code = ts.code
JOIN client c ON c.id = t.clientFk
JOIN clientType ct ON ct.id = c.clientTypeFk
JOIN alertLevel al ON al.alertLevel =
CASE
WHEN t.shipped < curdate() THEN 3
WHEN t.shipped > util.dayEnd(curdate()) THEN 0
ELSE IFNULL(ts.alertLevel, 0)
END
LEFT JOIN state stPrep ON stPrep.`code` = 'PREPARED'
LEFT JOIN saleTracking stk ON stk.saleFk = s.id AND stk.stateFk = stPrep.id
WHERE t.shipped >= vDateInventory
AND s.itemFk = vItemId
AND vWarehouse =t.warehouseFk
ORDER BY shipped, alertLevel DESC, isTicket, `order` DESC, isPicked DESC, `in` DESC, `out` DESC
) AS itemDiary;
END$$
DELIMITER ;

View File

@ -1,2 +0,0 @@
ALTER TABLE `vn`.`supplier` ADD COLUMN `workerFk` INT(11) NULL DEFAULT NULL COMMENT 'Responsible for approving invoices' AFTER `isTrucker`;
ALTER TABLE `vn`.`supplier` ADD CONSTRAINT `supplier_workerFk` FOREIGN KEY (`workerFk`) REFERENCES `vn`.`worker` (`id`) ON UPDATE CASCADE;

View File

@ -1,4 +0,0 @@
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
VALUES
('StarredModule', '*', '*', 'ALLOW', 'ROLE', 'employee'),
('ItemBotanical', '*', 'WRITE', 'ALLOW', 'ROLE', 'logisticBoss');

View File

@ -1,20 +0,0 @@
CREATE TABLE `salix`.`module` (
`code` VARCHAR(45) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
INSERT INTO `salix`.`module`(`code`)
VALUES
('Items'),
('Orders'),
('Clients'),
('Entries'),
('Travels'),
('Invoices out'),
('Suppliers'),
('Claims'),
('Routes'),
('Tickets'),
('Workers'),
('Users'),
('Zones');

View File

@ -1,10 +0,0 @@
CREATE TABLE `vn`.`starredModule` (
`id` INT(11) unsigned NOT NULL AUTO_INCREMENT,
`workerFk` INT(10) NOT NULL,
`moduleFk` VARCHAR(45) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`),
KEY `starred_workerFk` (`workerFk`),
KEY `starred_moduleFk` (`moduleFk`),
CONSTRAINT `starred_workerFk` FOREIGN KEY (`workerFk`) REFERENCES `vn`.`worker` (`id`) ON UPDATE CASCADE,
CONSTRAINT `starred_moduleFk` FOREIGN KEY (`moduleFk`) REFERENCES `salix`.`module` (`code`) ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

View File

@ -1,5 +0,0 @@
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
VALUES
('Genus', '*', 'WRITE', 'ALLOW', 'ROLE', 'logisticBoss'),
('Specie', '*', 'WRITE', 'ALLOW', 'ROLE', 'logisticBoss'),
('InvoiceOut', 'createPdf', 'WRITE', 'ALLOW', 'ROLE', 'invoicing');

File diff suppressed because one or more lines are too long

View File

@ -294,6 +294,10 @@ INSERT INTO `vn`.`clientManaCache`(`clientFk`, `mana`, `dated`)
(103, 0, DATE_ADD(CURDATE(), INTERVAL -1 MONTH)), (103, 0, DATE_ADD(CURDATE(), INTERVAL -1 MONTH)),
(104, -30, DATE_ADD(CURDATE(), INTERVAL -1 MONTH)); (104, -30, DATE_ADD(CURDATE(), INTERVAL -1 MONTH));
INSERT INTO `vn`.`clientConfig`(`riskTolerance`)
VALUES
(200);
INSERT INTO `vn`.`address`(`id`, `nickname`, `street`, `city`, `postalCode`, `provinceFk`, `phone`, `mobile`, `isActive`, `clientFk`, `agencyModeFk`, `longitude`, `latitude`, `isEqualizated`, `isDefaultAddress`) INSERT INTO `vn`.`address`(`id`, `nickname`, `street`, `city`, `postalCode`, `provinceFk`, `phone`, `mobile`, `isActive`, `clientFk`, `agencyModeFk`, `longitude`, `latitude`, `isEqualizated`, `isDefaultAddress`)
VALUES VALUES
(1, 'Bruce Wayne', '1007 Mountain Drive, Gotham', 'Silla', 46460, 1, 1111111111, 222222222, 1, 101, 2, NULL, NULL, 0, 1), (1, 'Bruce Wayne', '1007 Mountain Drive, Gotham', 'Silla', 46460, 1, 1111111111, 222222222, 1, 101, 2, NULL, NULL, 0, 1),
@ -711,14 +715,14 @@ INSERT INTO `vn`.`itemCategory`(`id`, `name`, `display`, `color`, `icon`, `code`
(7, 'Accessories', 1, NULL, 'icon-accessory', 'accessory'), (7, 'Accessories', 1, NULL, 'icon-accessory', 'accessory'),
(8, 'Fruit', 1, NULL, 'icon-fruit', 'fruit'); (8, 'Fruit', 1, NULL, 'icon-fruit', 'fruit');
INSERT INTO `vn`.`itemType`(`id`, `code`, `name`, `categoryFk`, `life`,`workerFk`, `isPackaging`) INSERT INTO `vn`.`itemType`(`id`, `code`, `name`, `categoryFk`, `warehouseFk`, `life`,`workerFk`, `isPackaging`)
VALUES VALUES
(1, 'CRI', 'Crisantemo', 2, 31, 35, 0), (1, 'CRI', 'Crisantemo', 2, 1, 31, 35, 0),
(2, 'ITG', 'Anthurium', 1, 31, 35, 0), (2, 'ITG', 'Anthurium', 1, 1, 31, 35, 0),
(3, 'WPN', 'Paniculata', 2, 31, 35, 0), (3, 'WPN', 'Paniculata', 2, 1, 31, 35, 0),
(4, 'PRT', 'Delivery ports', 3, NULL, 35, 1), (4, 'PRT', 'Delivery ports', 3, 1, NULL, 35, 1),
(5, 'CON', 'Container', 3, NULL, 35, 1), (5, 'CON', 'Container', 3, 1, NULL, 35, 1),
(6, 'ALS', 'Alstroemeria', 1, 31, 35, 0); (6, 'ALS', 'Alstroemeria', 1, 1, 31, 35, 0);
INSERT INTO `vn`.`ink`(`id`, `name`, `picture`, `showOrder`, `hex`) INSERT INTO `vn`.`ink`(`id`, `name`, `picture`, `showOrder`, `hex`)
VALUES VALUES
@ -2259,7 +2263,10 @@ INSERT INTO `vn`.`duaInvoiceIn`(`id`, `duaFk`, `invoiceInFk`)
(10, 10, 10); (10, 10, 10);
INSERT INTO `vn`.`ticketRecalc`(`ticketFk`) INSERT INTO `vn`.`ticketRecalc`(`ticketFk`)
SELECT `id` FROM `vn`.`ticket`; SELECT `id`
FROM `vn`.`ticket` t
LEFT JOIN vn.ticketRecalc tr ON tr.ticketFk = t.id
WHERE tr.ticketFk IS NULL;
CALL `vn`.`ticket_doRecalc`(); CALL `vn`.`ticket_doRecalc`();

File diff suppressed because it is too large Load Diff

View File

@ -86,6 +86,8 @@ IGNORETABLES=(
--ignore-table=vn.warehouseJoined --ignore-table=vn.warehouseJoined
--ignore-table=vn.workerTeam__ --ignore-table=vn.workerTeam__
--ignore-table=vn.XDiario__ --ignore-table=vn.XDiario__
--ignore-table=sage.movConta
--ignore-table=sage.movContaCopia
) )
mysqldump \ mysqldump \
--defaults-file=config.production.ini \ --defaults-file=config.production.ini \

View File

@ -0,0 +1,31 @@
const app = require('vn-loopback/server/server');
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
describe('item_getBalance()', () => {
it(`should return the item balance ordered by alert level`, async() => {
let stmts = [];
let params = {
warehouseFk: 1,
itemFk: 1
};
const conn = await app.models.Item.dataSource.connector;
stmts.push(new ParameterizedSQL('CALL vn.item_getBalance(?, ?)', [
params.warehouseFk,
params.itemFk
]));
let sql = ParameterizedSQL.join(stmts, ';');
let result = await conn.executeStmt(sql);
let itemBalance = result[0];
expect(itemBalance[0].alertLevel).toBeGreaterThanOrEqual(itemBalance[1].alertLevel);
expect(itemBalance[1].alertLevel).toBeGreaterThanOrEqual(itemBalance[2].alertLevel);
expect(itemBalance[2].alertLevel).toBeGreaterThanOrEqual(itemBalance[3].alertLevel);
expect(itemBalance[3].alertLevel).toBeGreaterThanOrEqual(itemBalance[4].alertLevel);
expect(itemBalance[4].alertLevel).toBeGreaterThanOrEqual(itemBalance[5].alertLevel);
expect(itemBalance[5].alertLevel).toBeGreaterThanOrEqual(itemBalance[6].alertLevel);
});
});

View File

@ -59,6 +59,6 @@ describe('Account create and basic data path', () => {
await page.accessToSection('account.card.roles'); await page.accessToSection('account.card.roles');
const rolesCount = await page.countElement(selectors.accountRoles.anyResult); const rolesCount = await page.countElement(selectors.accountRoles.anyResult);
expect(rolesCount).toEqual(3); expect(rolesCount).toEqual(4);
}); });
}); });

View File

@ -81,6 +81,6 @@ describe('Account Role create and basic data path', () => {
await page.accessToSection('account.role.card.inherited'); await page.accessToSection('account.role.card.inherited');
const rolesCount = await page.countElement(selectors.accountRoleInheritance.anyResult); const rolesCount = await page.countElement(selectors.accountRoleInheritance.anyResult);
expect(rolesCount).toEqual(6); expect(rolesCount).toEqual(7);
}); });
}); });

View File

@ -3,7 +3,7 @@ module.exports = Self => {
description: 'Returns a list of allowed contentTypes', description: 'Returns a list of allowed contentTypes',
accessType: 'READ', accessType: 'READ',
returns: { returns: {
type: ['Object'], type: ['object'],
root: true root: true
}, },
http: { http: {

View File

@ -4,12 +4,12 @@ module.exports = Self => {
accessType: 'WRITE', accessType: 'WRITE',
accepts: { accepts: {
arg: 'id', arg: 'id',
type: 'Number', type: 'number',
description: 'The document id', description: 'The document id',
http: {source: 'path'} http: {source: 'path'}
}, },
returns: { returns: {
type: 'Object', type: 'object',
root: true root: true
}, },
http: { http: {
@ -18,16 +18,36 @@ module.exports = Self => {
} }
}); });
Self.removeFile = async(ctx, id) => { Self.removeFile = async(ctx, id, options) => {
let tx;
let myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
if (!myOptions.transaction) {
tx = await Self.beginTransaction({});
myOptions.transaction = tx;
}
try {
const models = Self.app.models; const models = Self.app.models;
const targetClaimDms = await models.ClaimDms.findById(id); const targetClaimDms = await models.ClaimDms.findById(id, null, myOptions);
const targetDms = await models.Dms.findById(targetClaimDms.dmsFk); const targetDms = await models.Dms.findById(targetClaimDms.dmsFk, null, myOptions);
const trashDmsType = await models.DmsType.findOne({where: {code: 'trash'}}); const trashDmsType = await models.DmsType.findOne({where: {code: 'trash'}}, myOptions);
await models.Dms.removeFile(ctx, targetClaimDms.dmsFk); await models.Dms.removeFile(ctx, targetClaimDms.dmsFk, myOptions);
await targetClaimDms.destroy(); await targetClaimDms.destroy(myOptions);
return targetDms.updateAttribute('dmsTypeFk', trashDmsType.id); await targetDms.updateAttribute('dmsTypeFk', trashDmsType.id, myOptions);
if (tx) await tx.commit();
return targetDms;
} catch (e) {
if (tx) await tx.rollback();
throw e;
}
}; };
}; };

View File

@ -17,14 +17,27 @@ module.exports = Self => {
} }
}); });
Self.importTicketSales = async(ctx, params) => { Self.importTicketSales = async(ctx, params, options) => {
let models = Self.app.models; let models = Self.app.models;
let userId = ctx.req.accessToken.userId; let userId = ctx.req.accessToken.userId;
let worker = await models.Worker.findOne({where: {userFk: userId}});
let tx;
let myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
if (!myOptions.transaction) {
tx = await Self.beginTransaction({});
myOptions.transaction = tx;
}
try {
const worker = await models.Worker.findOne({where: {userFk: userId}}, myOptions);
let ticketSales = await models.Sale.find({ let ticketSales = await models.Sale.find({
where: {ticketFk: params.ticketFk} where: {ticketFk: params.ticketFk}
}); }, myOptions);
let claimEnds = []; let claimEnds = [];
ticketSales.forEach(sale => { ticketSales.forEach(sale => {
@ -35,6 +48,14 @@ module.exports = Self => {
}); });
}); });
return await Self.create(claimEnds); const createdClaimEnds = await Self.create(claimEnds, myOptions);
if (tx) await tx.commit();
return createdClaimEnds;
} catch (e) {
if (tx) await tx.rollback();
throw e;
}
}; };
}; };

View File

@ -1,25 +1,26 @@
const app = require('vn-loopback/server/server'); const app = require('vn-loopback/server/server');
describe('Claim importTicketSales()', () => { describe('Claim importTicketSales()', () => {
let claimEnds;
afterAll(async done => {
claimEnds.forEach(async line => {
await line.destroy();
});
done();
});
it('should import sales to a claim actions from an specific ticket', async() => { it('should import sales to a claim actions from an specific ticket', async() => {
let ctx = {req: {accessToken: {userId: 5}}}; const ctx = {req: {accessToken: {userId: 5}}};
claimEnds = await app.models.ClaimEnd.importTicketSales(ctx, {
const tx = await app.models.Entry.beginTransaction({});
try {
const options = {transaction: tx};
const claimEnds = await app.models.ClaimEnd.importTicketSales(ctx, {
claimFk: 1, claimFk: 1,
ticketFk: 1 ticketFk: 1
}); }, options);
expect(claimEnds.length).toEqual(4); expect(claimEnds.length).toEqual(4);
expect(claimEnds[0].saleFk).toEqual(1); expect(claimEnds[0].saleFk).toEqual(1);
expect(claimEnds[2].saleFk).toEqual(3); expect(claimEnds[2].saleFk).toEqual(3);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
}); });

View File

@ -24,15 +24,22 @@ module.exports = Self => {
} }
}); });
Self.createFromSales = async(ctx, ticketId, sales) => { Self.createFromSales = async(ctx, ticketId, sales, options) => {
let tx;
let myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
if (!myOptions.transaction) {
tx = await Self.beginTransaction({});
myOptions.transaction = tx;
}
const models = Self.app.models; const models = Self.app.models;
const userId = ctx.req.accessToken.userId; const userId = ctx.req.accessToken.userId;
const tx = await Self.beginTransaction({});
try { try {
let options = {transaction: tx}; const ticket = await models.Ticket.findById(ticketId, null, myOptions);
const ticket = await models.Ticket.findById(ticketId, null, options);
if (ticket.isDeleted) if (ticket.isDeleted)
throw new UserError(`You can't create a claim for a removed ticket`); throw new UserError(`You can't create a claim for a removed ticket`);
@ -41,7 +48,7 @@ module.exports = Self => {
clientFk: ticket.clientFk, clientFk: ticket.clientFk,
ticketCreated: ticket.shipped, ticketCreated: ticket.shipped,
workerFk: userId workerFk: userId
}, options); }, myOptions);
const promises = []; const promises = [];
for (const sale of sales) { for (const sale of sales) {
@ -49,17 +56,18 @@ module.exports = Self => {
saleFk: sale.id, saleFk: sale.id,
claimFk: newClaim.id, claimFk: newClaim.id,
quantity: sale.quantity quantity: sale.quantity
}, options); }, myOptions);
promises.push(newClaimBeginning); promises.push(newClaimBeginning);
} }
await Promise.all(promises); await Promise.all(promises);
await tx.commit(); if (tx) await tx.commit();
return newClaim; return newClaim;
} catch (e) { } catch (e) {
await tx.rollback(); if (tx) await tx.rollback();
throw e; throw e;
} }
}; };

View File

@ -10,58 +10,67 @@ module.exports = Self => {
accepts: [ accepts: [
{ {
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',
http: {source: 'query'} http: {source: 'query'}
}, { },
{
arg: 'tags', arg: 'tags',
type: ['Object'], type: ['object'],
description: 'List of tags to filter with', description: 'List of tags to filter with',
http: {source: 'query'} http: {source: 'query'}
}, { },
{
arg: 'search', arg: 'search',
type: 'String', type: 'string',
description: `If it's and integer searchs by id, otherwise it searchs by client name`, description: `If it's and integer searchs by id, otherwise it searchs by client name`,
http: {source: 'query'} http: {source: 'query'}
}, { },
{
arg: 'client', arg: 'client',
type: 'String', type: 'string',
description: 'The worker name', description: 'The worker name',
http: {source: 'query'} http: {source: 'query'}
}, { },
{
arg: 'id', arg: 'id',
type: 'Integer', type: 'integer',
description: 'The claim id', description: 'The claim id',
http: {source: 'query'} http: {source: 'query'}
}, { },
{
arg: 'clientFk', arg: 'clientFk',
type: 'Integer', type: 'integer',
description: 'The client id', description: 'The client id',
http: {source: 'query'} http: {source: 'query'}
}, { },
{
arg: 'claimStateFk', arg: 'claimStateFk',
type: 'Integer', type: 'integer',
description: 'The claim state id', description: 'The claim state id',
http: {source: 'query'} http: {source: 'query'}
}, { },
{
arg: 'salesPersonFk', arg: 'salesPersonFk',
type: 'Integer', type: 'integer',
description: 'The salesPerson id', description: 'The salesPerson id',
http: {source: 'query'} http: {source: 'query'}
}, { },
{
arg: 'attenderFk', arg: 'attenderFk',
type: 'Integer', type: 'integer',
description: 'The attender worker id', description: 'The attender worker id',
http: {source: 'query'} http: {source: 'query'}
}, { },
{
arg: 'created', arg: 'created',
type: 'Date', type: 'date',
description: 'The to date filter', description: 'The to date filter',
http: {source: 'query'} http: {source: 'query'}
} }
], ],
returns: { returns: {
type: ['Object'], type: ['object'],
root: true root: true
}, },
http: { http: {

View File

@ -18,32 +18,39 @@ module.exports = Self => {
} }
}); });
Self.regularizeClaim = async(ctx, claimFk) => { Self.regularizeClaim = async(ctx, claimFk, options) => {
const models = Self.app.models; const models = Self.app.models;
const $t = ctx.req.__; // $translate const $t = ctx.req.__; // $translate
const resolvedState = 3; const resolvedState = 3;
let tx = await Self.beginTransaction({}); let tx;
try { let myOptions = {};
let options = {transaction: tx};
if (typeof options == 'object')
Object.assign(myOptions, options);
if (!myOptions.transaction) {
tx = await Self.beginTransaction({});
myOptions.transaction = tx;
}
try {
const claimEnds = await models.ClaimEnd.find({ const claimEnds = await models.ClaimEnd.find({
include: { include: {
relation: 'claimDestination', relation: 'claimDestination',
fields: ['addressFk'] fields: ['addressFk']
}, },
where: {claimFk: claimFk} where: {claimFk: claimFk}
}, options); }, myOptions);
for (let i = 0; i < claimEnds.length; i++) { for (let claimEnd of claimEnds) {
const claimEnd = claimEnds[i];
const destination = claimEnd.claimDestination(); const destination = claimEnd.claimDestination();
const sale = await getSale(claimEnd.saleFk, options); const sale = await getSale(claimEnd.saleFk, myOptions);
const addressId = destination && destination.addressFk; const addressId = destination && destination.addressFk;
let address; let address;
if (addressId) if (addressId)
address = await models.Address.findById(addressId, null, options); address = await models.Address.findById(addressId, null, myOptions);
const salesPerson = sale.ticket().client().salesPersonUser(); const salesPerson = sale.ticket().client().salesPersonUser();
if (salesPerson) { if (salesPerson) {
@ -67,7 +74,7 @@ module.exports = Self => {
addressFk: addressId, addressFk: addressId,
companyFk: sale.ticket().companyFk, companyFk: sale.ticket().companyFk,
warehouseFk: sale.ticket().warehouseFk warehouseFk: sale.ticket().warehouseFk
}, options); }, myOptions);
if (!ticketFk) { if (!ticketFk) {
ticketFk = await createTicket(ctx, { ticketFk = await createTicket(ctx, {
@ -75,7 +82,7 @@ module.exports = Self => {
warehouseId: sale.ticket().warehouseFk, warehouseId: sale.ticket().warehouseFk,
companyId: sale.ticket().companyFk, companyId: sale.ticket().companyFk,
addressId: addressId addressId: addressId
}, options); }, myOptions);
} }
await models.Sale.create({ await models.Sale.create({
@ -85,19 +92,19 @@ module.exports = Self => {
quantity: -sale.quantity, quantity: -sale.quantity,
price: sale.price, price: sale.price,
discount: 100 discount: 100
}, options); }, myOptions);
} }
let claim = await Self.findById(claimFk, null, options); let claim = await Self.findById(claimFk, null, myOptions);
claim = await claim.updateAttributes({ claim = await claim.updateAttributes({
claimStateFk: resolvedState claimStateFk: resolvedState
}, options); }, myOptions);
await tx.commit(); if (tx) await tx.commit();
return claim; return claim;
} catch (e) { } catch (e) {
await tx.rollback(); if (tx) await tx.rollback();
throw e; throw e;
} }
}; };

View File

@ -10,36 +10,45 @@ describe('Claim createFromSales()', () => {
const ctx = {req: {accessToken: {userId: 1}}}; const ctx = {req: {accessToken: {userId: 1}}};
it('should create a new claim', async() => { it('should create a new claim', async() => {
let claim = await app.models.Claim.createFromSales(ctx, ticketId, newSale); const tx = await app.models.Claim.beginTransaction({});
try {
const options = {transaction: tx};
const claim = await app.models.Claim.createFromSales(ctx, ticketId, newSale, options);
expect(claim.ticketFk).toEqual(ticketId); expect(claim.ticketFk).toEqual(ticketId);
let claimBeginning = await app.models.ClaimBeginning.findOne({where: {claimFk: claim.id}}); let claimBeginning = await app.models.ClaimBeginning.findOne({where: {claimFk: claim.id}}, options);
expect(claimBeginning.saleFk).toEqual(newSale[0].id); expect(claimBeginning.saleFk).toEqual(newSale[0].id);
expect(claimBeginning.quantity).toEqual(newSale[0].quantity); expect(claimBeginning.quantity).toEqual(newSale[0].quantity);
const createdClaimId = claim.id; await tx.rollback();
} catch (e) {
// restores await tx.rollback();
await app.models.Claim.destroyById(createdClaimId); throw e;
}
}); });
it('should not be able to create a claim if exists that sale', async() => { it('should not be able to create a claim if exists that sale', async() => {
let claim = await app.models.Claim.createFromSales(ctx, ticketId, newSale); const tx = await app.models.Claim.beginTransaction({});
const createdClaimId = claim.id;
let error; let error;
await app.models.Claim.createFromSales(ctx, ticketId, newSale) try {
const options = {transaction: tx};
.catch(e => { await app.models.Claim.createFromSales(ctx, ticketId, newSale, options);
await app.models.Claim.createFromSales(ctx, ticketId, newSale, options);
await tx.rollback();
} catch (e) {
error = e; error = e;
}); await tx.rollback();
}
expect(error.toString()).toContain(`A claim with that sale already exists`); expect(error.toString()).toContain(`A claim with that sale already exists`);
// restores
await app.models.Claim.destroyById(createdClaimId);
}); });
}); });

View File

@ -21,81 +21,94 @@ describe('regularizeClaim()', () => {
let claimEnds = []; let claimEnds = [];
let trashTicket; let trashTicket;
afterEach(async done => {
try {
let claim = await app.models.Claim.findById(claimFk);
await claim.updateAttributes({
claimStateFk: pendentState,
hasToPickUp: false
});
for (claimEnd of claimEnds)
await claimEnd.destroy();
if (trashTicket)
await app.models.Ticket.destroyById(trashTicket.id);
} catch (error) {
console.error(error);
}
done();
});
it('should send a chat message with value "Trash" and then change claim state to resolved', async() => { it('should send a chat message with value "Trash" and then change claim state to resolved', async() => {
const tx = await app.models.Claim.beginTransaction({});
try {
const options = {transaction: tx};
spyOn(chatModel, 'sendCheckingPresence').and.callThrough(); spyOn(chatModel, 'sendCheckingPresence').and.callThrough();
claimEnds = await app.models.ClaimEnd.importTicketSales(ctx, { claimEnds = await app.models.ClaimEnd.importTicketSales(ctx, {
claimFk: claimFk, claimFk: claimFk,
ticketFk: 1 ticketFk: 1
}); }, options);
for (claimEnd of claimEnds) for (claimEnd of claimEnds)
await claimEnd.updateAttributes({claimDestinationFk: trashDestination}); await claimEnd.updateAttributes({claimDestinationFk: trashDestination}, options);
let claimBefore = await app.models.Claim.findById(claimFk); let claimBefore = await app.models.Claim.findById(claimFk, null, options);
await app.models.Claim.regularizeClaim(ctx, claimFk); await app.models.Claim.regularizeClaim(ctx, claimFk, options);
let claimAfter = await app.models.Claim.findById(claimFk); let claimAfter = await app.models.Claim.findById(claimFk, null, options);
trashTicket = await app.models.Ticket.findOne({where: {addressFk: 12}}); trashTicket = await app.models.Ticket.findOne({where: {addressFk: 12}}, options);
expect(trashTicket.addressFk).toEqual(trashAddress); expect(trashTicket.addressFk).toEqual(trashAddress);
expect(claimBefore.claimStateFk).toEqual(pendentState); expect(claimBefore.claimStateFk).toEqual(pendentState);
expect(claimAfter.claimStateFk).toEqual(resolvedState); expect(claimAfter.claimStateFk).toEqual(resolvedState);
expect(chatModel.sendCheckingPresence).toHaveBeenCalledWith(ctx, 18, 'Trash'); expect(chatModel.sendCheckingPresence).toHaveBeenCalledWith(ctx, 18, 'Trash');
expect(chatModel.sendCheckingPresence).toHaveBeenCalledTimes(4); expect(chatModel.sendCheckingPresence).toHaveBeenCalledTimes(4);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should send a chat message with value "Bueno" and then change claim state to resolved', async() => { it('should send a chat message with value "Bueno" and then change claim state to resolved', async() => {
const tx = await app.models.Claim.beginTransaction({});
try {
const options = {transaction: tx};
spyOn(chatModel, 'sendCheckingPresence').and.callThrough(); spyOn(chatModel, 'sendCheckingPresence').and.callThrough();
claimEnds = await app.models.ClaimEnd.importTicketSales(ctx, { claimEnds = await app.models.ClaimEnd.importTicketSales(ctx, {
claimFk: claimFk, claimFk: claimFk,
ticketFk: 1 ticketFk: 1
}); }, options);
for (claimEnd of claimEnds) for (claimEnd of claimEnds)
await claimEnd.updateAttributes({claimDestinationFk: okDestination}); await claimEnd.updateAttributes({claimDestinationFk: okDestination}, options);
await app.models.Claim.regularizeClaim(ctx, claimFk); await app.models.Claim.regularizeClaim(ctx, claimFk, options);
expect(chatModel.sendCheckingPresence).toHaveBeenCalledWith(ctx, 18, 'Bueno'); expect(chatModel.sendCheckingPresence).toHaveBeenCalledWith(ctx, 18, 'Bueno');
expect(chatModel.sendCheckingPresence).toHaveBeenCalledTimes(4); expect(chatModel.sendCheckingPresence).toHaveBeenCalledTimes(4);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should send a chat message to the salesPerson when claim isPickUp is enabled', async() => { it('should send a chat message to the salesPerson when claim isPickUp is enabled', async() => {
const tx = await app.models.Claim.beginTransaction({});
try {
const options = {transaction: tx};
spyOn(chatModel, 'sendCheckingPresence').and.callThrough(); spyOn(chatModel, 'sendCheckingPresence').and.callThrough();
claimEnds = await app.models.ClaimEnd.importTicketSales(ctx, { claimEnds = await app.models.ClaimEnd.importTicketSales(ctx, {
claimFk: claimFk, claimFk: claimFk,
ticketFk: 1 ticketFk: 1
}); }, options);
for (claimEnd of claimEnds) for (claimEnd of claimEnds)
await claimEnd.updateAttributes({claimDestinationFk: okDestination}); await claimEnd.updateAttributes({claimDestinationFk: okDestination}, options);
await app.models.Claim.regularizeClaim(ctx, claimFk); await app.models.Claim.regularizeClaim(ctx, claimFk, options);
expect(chatModel.sendCheckingPresence).toHaveBeenCalledWith(ctx, 18, 'Bueno'); expect(chatModel.sendCheckingPresence).toHaveBeenCalledWith(ctx, 18, 'Bueno');
expect(chatModel.sendCheckingPresence).toHaveBeenCalledTimes(4); expect(chatModel.sendCheckingPresence).toHaveBeenCalledTimes(4);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
}); });

View File

@ -1,7 +1,7 @@
const app = require('vn-loopback/server/server'); const app = require('vn-loopback/server/server');
describe('Update Claim', () => { describe('Update Claim', () => {
let newDate = new Date(); const newDate = new Date();
const originalData = { const originalData = {
ticketFk: 3, ticketFk: 3,
clientFk: 101, clientFk: 101,
@ -14,7 +14,15 @@ describe('Update Claim', () => {
}; };
it(`should throw an error as the user doesn't have rights`, async() => { it(`should throw an error as the user doesn't have rights`, async() => {
let newClaim = await app.models.Claim.create(originalData); const tx = await app.models.Claim.beginTransaction({});
let error;
try {
const options = {transaction: tx};
const newClaim = await app.models.Claim.create(originalData, options);
const forbiddenState = 3; const forbiddenState = 3;
const salesPersonId = 18; const salesPersonId = 18;
const ctx = { const ctx = {
@ -28,19 +36,24 @@ describe('Update Claim', () => {
observation: 'valid observation' observation: 'valid observation'
} }
}; };
await app.models.Claim.updateClaim(ctx, newClaim.id) await app.models.Claim.updateClaim(ctx, newClaim.id, options);
.catch(e => {
await tx.rollback();
} catch (e) {
error = e; error = e;
}); await tx.rollback();
}
expect(error.message).toEqual(`You don't have enough privileges to change that field`); expect(error.message).toEqual(`You don't have enough privileges to change that field`);
// restores
await app.models.Claim.destroyById(newClaim.id);
}); });
it(`should success to update the claim within privileges `, async() => { it(`should success to update the claim within privileges `, async() => {
let newClaim = await app.models.Claim.create(originalData); const tx = await app.models.Claim.beginTransaction({});
try {
const options = {transaction: tx};
const newClaim = await app.models.Claim.create(originalData, options);
const canceledState = 4; const canceledState = 4;
const claimManagerId = 72; const claimManagerId = 72;
@ -56,18 +69,27 @@ describe('Update Claim', () => {
hasToPickUp: false hasToPickUp: false
} }
}; };
await app.models.Claim.updateClaim(ctx, newClaim.id); await app.models.Claim.updateClaim(ctx, newClaim.id, options);
let updatedClaim = await app.models.Claim.findById(newClaim.id); let updatedClaim = await app.models.Claim.findById(newClaim.id, null, options);
expect(updatedClaim.observation).toEqual(ctx.args.observation); expect(updatedClaim.observation).toEqual(ctx.args.observation);
// restores await tx.rollback();
await app.models.Claim.destroyById(newClaim.id); } catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should change some sensible fields as claimManager', async() => { it('should change some sensible fields as claimManager', async() => {
let newClaim = await app.models.Claim.create(originalData); const tx = await app.models.Claim.beginTransaction({});
try {
const options = {transaction: tx};
const newClaim = await app.models.Claim.create(originalData, options);
const chatModel = app.models.Chat; const chatModel = app.models.Chat;
spyOn(chatModel, 'sendCheckingPresence').and.callThrough(); spyOn(chatModel, 'sendCheckingPresence').and.callThrough();
@ -87,16 +109,19 @@ describe('Update Claim', () => {
ctx.req.__ = (value, params) => { ctx.req.__ = (value, params) => {
return params.nickname; return params.nickname;
}; };
await app.models.Claim.updateClaim(ctx, newClaim.id); await app.models.Claim.updateClaim(ctx, newClaim.id, options);
let updatedClaim = await app.models.Claim.findById(newClaim.id); let updatedClaim = await app.models.Claim.findById(newClaim.id, null, options);
expect(updatedClaim.observation).toEqual(ctx.args.observation); expect(updatedClaim.observation).toEqual(ctx.args.observation);
expect(updatedClaim.claimStateFk).toEqual(ctx.args.claimStateFk); expect(updatedClaim.claimStateFk).toEqual(ctx.args.claimStateFk);
expect(updatedClaim.workerFk).toEqual(ctx.args.workerFk); expect(updatedClaim.workerFk).toEqual(ctx.args.workerFk);
expect(chatModel.sendCheckingPresence).toHaveBeenCalled(); expect(chatModel.sendCheckingPresence).toHaveBeenCalled();
// restores await tx.rollback();
await app.models.Claim.destroyById(newClaim.id); } catch (e) {
await tx.rollback();
throw e;
}
}); });
}); });

View File

@ -1,9 +1,8 @@
const app = require('vn-loopback/server/server'); const app = require('vn-loopback/server/server');
describe('Update Claim', () => { describe('Update Claim', () => {
let newDate = new Date(); const newDate = new Date();
let newInstance; const original = {
let original = {
ticketFk: 3, ticketFk: 3,
clientFk: 101, clientFk: 101,
ticketCreated: newDate, ticketCreated: newDate,
@ -14,30 +13,43 @@ describe('Update Claim', () => {
observation: 'observation' observation: 'observation'
}; };
beforeAll(async done => {
newInstance = await app.models.Claim.create(original);
done();
});
afterAll(async done => {
await app.models.Claim.destroyById(newInstance.id);
done();
});
it('should update the claim isChargedToMana attribute', async() => { it('should update the claim isChargedToMana attribute', async() => {
const tx = await app.models.Claim.beginTransaction({});
try {
const options = {transaction: tx};
const ctx = {args: {isChargedToMana: false}}; const ctx = {args: {isChargedToMana: false}};
const result = await app.models.Claim.updateClaimAction(ctx, newInstance.id);
const newInstance = await app.models.Claim.create(original, options);
const result = await app.models.Claim.updateClaimAction(ctx, newInstance.id, options);
expect(result.id).toEqual(newInstance.id); expect(result.id).toEqual(newInstance.id);
expect(result.isChargedToMana).toBeFalsy(); expect(result.isChargedToMana).toBeFalsy();
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should update the claim responsibility attribute', async() => { it('should update the claim responsibility attribute', async() => {
const tx = await app.models.Claim.beginTransaction({});
try {
const options = {transaction: tx};
const ctx = {args: {responsibility: 2}}; const ctx = {args: {responsibility: 2}};
const result = await app.models.Claim.updateClaimAction(ctx, newInstance.id);
const newInstance = await app.models.Claim.create(original, options);
const result = await app.models.Claim.updateClaimAction(ctx, newInstance.id, options);
expect(result.id).toEqual(newInstance.id); expect(result.id).toEqual(newInstance.id);
expect(result.responsibility).toEqual(2); expect(result.responsibility).toEqual(2);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
}); });

View File

@ -4,25 +4,26 @@ module.exports = Self => {
description: 'Update a claim with privileges', description: 'Update a claim with privileges',
accepts: [{ accepts: [{
arg: 'ctx', arg: 'ctx',
type: 'Object', type: 'object',
http: {source: 'context'} http: {source: 'context'}
}, { },
{
arg: 'id', arg: 'id',
type: 'Number', type: 'number',
description: 'Claim id', description: 'Claim id',
http: {source: 'path'} http: {source: 'path'}
}, },
{ {
arg: 'workerFk', arg: 'workerFk',
type: 'Number' type: 'number'
}, },
{ {
arg: 'claimStateFk', arg: 'claimStateFk',
type: 'Number' type: 'number'
}, },
{ {
arg: 'observation', arg: 'observation',
type: 'String' type: 'string'
}, },
{ {
arg: 'hasToPickUp', arg: 'hasToPickUp',
@ -38,11 +39,23 @@ module.exports = Self => {
} }
}); });
Self.updateClaim = async(ctx, id) => { Self.updateClaim = async(ctx, id, options) => {
const models = Self.app.models; const models = Self.app.models;
const userId = ctx.req.accessToken.userId; const userId = ctx.req.accessToken.userId;
const args = ctx.args; const args = ctx.args;
const $t = ctx.req.__; // $translate const $t = ctx.req.__; // $translate
let tx;
let myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
if (!myOptions.transaction) {
tx = await Self.beginTransaction({});
myOptions.transaction = tx;
}
try {
const claim = await models.Claim.findById(id, { const claim = await models.Claim.findById(id, {
include: { include: {
relation: 'client', relation: 'client',
@ -52,21 +65,21 @@ module.exports = Self => {
} }
} }
} }
}); }, myOptions);
let changedHasToPickUp = false; let changedHasToPickUp = false;
if (args.hasToPickUp) if (args.hasToPickUp)
changedHasToPickUp = true; changedHasToPickUp = true;
if (args.claimStateFk) { if (args.claimStateFk) {
const canUpdate = await canChangeState(ctx, claim.claimStateFk); const canUpdate = await canChangeState(ctx, claim.claimStateFk, myOptions);
const hasRights = await canChangeState(ctx, args.claimStateFk); const hasRights = await canChangeState(ctx, args.claimStateFk, myOptions);
const isClaimManager = await models.Account.hasRole(userId, 'claimManager'); const isClaimManager = await models.Account.hasRole(userId, 'claimManager', myOptions);
if (!canUpdate || !hasRights || changedHasToPickUp && !isClaimManager) if (!canUpdate || !hasRights || changedHasToPickUp && !isClaimManager)
throw new UserError(`You don't have enough privileges to change that field`); throw new UserError(`You don't have enough privileges to change that field`);
} }
delete args.ctx; delete args.ctx;
const updatedClaim = await claim.updateAttributes(args); const updatedClaim = await claim.updateAttributes(args, myOptions);
// Get sales person from claim client // Get sales person from claim client
const salesPerson = claim.client().salesPersonUser(); const salesPerson = claim.client().salesPersonUser();
if (salesPerson && changedHasToPickUp && updatedClaim.hasToPickUp) { if (salesPerson && changedHasToPickUp && updatedClaim.hasToPickUp) {
@ -79,10 +92,16 @@ module.exports = Self => {
await models.Chat.sendCheckingPresence(ctx, salesPerson.id, message); await models.Chat.sendCheckingPresence(ctx, salesPerson.id, message);
} }
if (tx) await tx.commit();
return updatedClaim; return updatedClaim;
} catch (e) {
if (tx) await tx.rollback();
throw e;
}
}; };
async function canChangeState(ctx, id) { async function canChangeState(ctx, id, options) {
let models = Self.app.models; let models = Self.app.models;
let userId = ctx.req.accessToken.userId; let userId = ctx.req.accessToken.userId;
@ -90,9 +109,9 @@ module.exports = Self => {
include: { include: {
relation: 'writeRole' relation: 'writeRole'
} }
}); }, options);
let stateRole = state.writeRole().name; let stateRole = state.writeRole().name;
let canUpdate = await models.Account.hasRole(userId, stateRole); let canUpdate = await models.Account.hasRole(userId, stateRole, options);
return canUpdate; return canUpdate;
} }

View File

@ -28,12 +28,32 @@ module.exports = Self => {
} }
}); });
Self.updateClaimAction = async(ctx, id) => { Self.updateClaimAction = async(ctx, id, options) => {
let tx;
let myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
if (!myOptions.transaction) {
tx = await Self.beginTransaction({});
myOptions.transaction = tx;
}
try {
const models = Self.app.models; const models = Self.app.models;
const claim = await models.Claim.findById(id); const claim = await models.Claim.findById(id, null, myOptions);
const args = ctx.args; const args = ctx.args;
delete args.ctx; delete args.ctx;
return await claim.updateAttributes(args); const updatedClaim = await claim.updateAttributes(args, myOptions);
if (tx) await tx.commit();
return updatedClaim;
} catch (e) {
if (tx) await tx.rollback();
throw e;
}
}; };
}; };

View File

@ -4,40 +4,46 @@ module.exports = Self => {
accessType: 'WRITE', accessType: 'WRITE',
accepts: [{ accepts: [{
arg: 'id', arg: 'id',
type: 'Number', type: 'number',
description: 'The claim id', description: 'The claim id',
http: {source: 'path'} http: {source: 'path'}
}, { },
{
arg: 'warehouseId', arg: 'warehouseId',
type: 'Number', type: 'number',
description: 'The warehouse id', description: 'The warehouse id',
required: true required: true
}, { },
{
arg: 'companyId', arg: 'companyId',
type: 'Number', type: 'number',
description: 'The company id', description: 'The company id',
required: true required: true
}, { },
{
arg: 'dmsTypeId', arg: 'dmsTypeId',
type: 'Number', type: 'number',
description: 'The dms type id', description: 'The dms type id',
required: true required: true
}, { },
{
arg: 'reference', arg: 'reference',
type: 'String', type: 'string',
required: true required: true
}, { },
{
arg: 'description', arg: 'description',
type: 'String', type: 'string',
required: true required: true
}, { },
{
arg: 'hasFile', arg: 'hasFile',
type: 'Boolean', type: 'boolean',
description: 'True if has an attached file', description: 'True if has an attached file',
required: true required: true
}], }],
returns: { returns: {
type: 'Object', type: 'object',
root: true root: true
}, },
http: { http: {
@ -46,31 +52,38 @@ module.exports = Self => {
} }
}); });
Self.uploadFile = async(ctx, id) => { Self.uploadFile = async(ctx, id, options) => {
let tx;
let myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
if (!myOptions.transaction) {
tx = await Self.beginTransaction({});
myOptions.transaction = tx;
}
const models = Self.app.models; const models = Self.app.models;
const promises = []; const promises = [];
const tx = await Self.beginTransaction({});
try { try {
const options = {transaction: tx}; const uploadedFiles = await models.Dms.uploadFile(ctx, myOptions);
const uploadedFiles = await models.Dms.uploadFile(ctx, options);
uploadedFiles.forEach(dms => { uploadedFiles.forEach(dms => {
const newClaimDms = models.ClaimDms.create({ const newClaimDms = models.ClaimDms.create({
claimFk: id, claimFk: id,
dmsFk: dms.id dmsFk: dms.id
}, options); }, myOptions);
promises.push(newClaimDms); promises.push(newClaimDms);
}); });
const resolvedPromises = await Promise.all(promises); const resolvedPromises = await Promise.all(promises);
await tx.commit(); if (tx) await tx.commit();
return resolvedPromises; return resolvedPromises;
} catch (err) { } catch (e) {
await tx.rollback(); if (tx) await tx.rollback();
throw err; throw e;
} }
}; };
}; };

View File

@ -10,10 +10,10 @@ module.exports = Self => {
description: 'The routes ids to clone' description: 'The routes ids to clone'
}, },
{ {
arg: 'started', arg: 'created',
type: 'date', type: 'date',
required: true, required: true,
description: 'The started date for all routes' description: 'The created date for all routes'
} }
], ],
returns: { returns: {
@ -26,7 +26,7 @@ module.exports = Self => {
} }
}); });
Self.clone = async(ids, started) => { Self.clone = async(ids, created) => {
const tx = await Self.beginTransaction({}); const tx = await Self.beginTransaction({});
try { try {
const options = {transaction: tx}; const options = {transaction: tx};
@ -39,8 +39,7 @@ module.exports = Self => {
throw new Error(`The amount of routes found don't match`); throw new Error(`The amount of routes found don't match`);
const routes = originalRoutes.map(route => { const routes = originalRoutes.map(route => {
route.started = started; route.created = created;
route.created = new Date();
return route; return route;
}); });

View File

@ -38,10 +38,10 @@ module.exports = Self => {
for (let zoneAgencyMode of zoneAgencyModes) for (let zoneAgencyMode of zoneAgencyModes)
zoneIds.push(zoneAgencyMode.zoneFk); zoneIds.push(zoneAgencyMode.zoneFk);
const minDate = new Date(route.finished); const minDate = new Date(route.created);
minDate.setHours(0, 0, 0, 0); minDate.setHours(0, 0, 0, 0);
const maxDate = new Date(route.finished); const maxDate = new Date(route.created);
maxDate.setHours(23, 59, 59, 59); maxDate.setHours(23, 59, 59, 59);
let tickets = await Self.app.models.Ticket.find({ let tickets = await Self.app.models.Ticket.find({
@ -49,7 +49,7 @@ module.exports = Self => {
agencyModeFk: route.agencyModeFk, agencyModeFk: route.agencyModeFk,
zoneFk: {inq: zoneIds}, zoneFk: {inq: zoneIds},
id: {nin: idsToExclude}, id: {nin: idsToExclude},
landed: {between: [minDate, maxDate]} created: {between: [minDate, maxDate]}
}, },
include: [ include: [
{ {

View File

@ -1,14 +1,14 @@
const app = require('vn-loopback/server/server'); const app = require('vn-loopback/server/server');
describe('route clone()', () => { describe('route clone()', () => {
const startDate = new Date(); const createdDate = new Date();
it('should throw an error if the amount of ids pased to the clone function do no match the database', async() => { it('should throw an error if the amount of ids pased to the clone function do no match the database', async() => {
const ids = [996, 997, 998, 999]; const ids = [996, 997, 998, 999];
let error; let error;
try { try {
await app.models.Route.clone(ids, startDate); await app.models.Route.clone(ids, createdDate);
} catch (e) { } catch (e) {
error = e; error = e;
} }
@ -20,7 +20,7 @@ describe('route clone()', () => {
it('should clone two routes', async() => { it('should clone two routes', async() => {
const ids = [1, 2]; const ids = [1, 2];
const clones = await app.models.Route.clone(ids, startDate); const clones = await app.models.Route.clone(ids, createdDate);
expect(clones.length).toEqual(2); expect(clones.length).toEqual(2);

View File

@ -105,8 +105,7 @@
<vn-horizontal> <vn-horizontal>
<vn-date-picker <vn-date-picker
label="Starting date" label="Starting date"
ng-model="$ctrl.startedDate" ng-model="$ctrl.createdDate">
required="true">
</vn-date-picker> </vn-date-picker>
</vn-horizontal> </vn-horizontal>
</tpl-body> </tpl-body>

View File

@ -41,19 +41,26 @@ export default class Controller extends Section {
} }
openClonationDialog() { openClonationDialog() {
this.startedDate = new Date();
this.$.clonationDialog.show(); this.$.clonationDialog.show();
this.createdDate = new Date();
} }
cloneSelectedRoutes() { cloneSelectedRoutes() {
try {
if (!this.createdDate)
throw new Error(`The date can't be empty`);
const routesIds = []; const routesIds = [];
for (let route of this.checked) for (let route of this.checked)
routesIds.push(route.id); routesIds.push(route.id);
return this.$http.post('Routes/clone', {ids: routesIds, started: this.startedDate}).then(() => { return this.$http.post('Routes/clone', {ids: routesIds, created: this.createdDate}).then(() => {
this.$.model.refresh(); this.$.model.refresh();
this.vnApp.showSuccess(this.$t('Data saved!')); this.vnApp.showSuccess(this.$t('Data saved!'));
}); });
} catch (e) {
this.vnApp.showError(this.$t(e.message));
}
} }
onDrop($event) { onDrop($event) {

View File

@ -62,7 +62,7 @@ describe('Component vnRouteIndex', () => {
describe('cloneSelectedRoutes()', () => { describe('cloneSelectedRoutes()', () => {
it('should perform an http request to Routes/clone', () => { it('should perform an http request to Routes/clone', () => {
controller.startedDate = new Date(); controller.createdDate = new Date();
$httpBackend.expect('POST', 'Routes/clone').respond(); $httpBackend.expect('POST', 'Routes/clone').respond();
controller.cloneSelectedRoutes(); controller.cloneSelectedRoutes();

View File

@ -1,5 +1,5 @@
Vehicle: Vehículo Vehicle: Vehículo
Download selected routes as PDF: Descargar rutas seleccionadas como PDF Download selected routes as PDF: Descargar rutas seleccionadas como PDF
Clone selected routes: Clonar rutas seleccionadas Clone selected routes: Clonar rutas seleccionadas
Select the starting date: Seleccione fecha de inicio The date can't be empty: La fecha no puede estar vacía
Starting date: Fecha de inicio Starting date: Fecha de inicio

View File

@ -10,7 +10,7 @@
data="contacts" data="contacts"
form="form"> form="form">
</vn-watcher> </vn-watcher>
<form name="form" ng-submit="$ctrl.onSubmit()" class="vn-w-md"> <form name="form" ng-submit="$ctrl.onSubmit()" class="vn-w-lg">
<vn-card class="vn-pa-lg"> <vn-card class="vn-pa-lg">
<div ng-repeat="contact in contacts" class="contact"> <div ng-repeat="contact in contacts" class="contact">
<vn-vertical> <vn-vertical>

View File

@ -1,7 +1,6 @@
const app = require('vn-loopback/server/server'); const app = require('vn-loopback/server/server');
// #2868 Excluded until database export describe('ticket filter()', () => {
xdescribe('ticket filter()', () => {
it('should return the tickets matching the filter', async() => { it('should return the tickets matching the filter', async() => {
const ctx = {req: {accessToken: {userId: 9}}, args: {}}; const ctx = {req: {accessToken: {userId: 9}}, args: {}};
const filter = {order: 'id DESC'}; const filter = {order: 'id DESC'};
@ -24,7 +23,7 @@ xdescribe('ticket filter()', () => {
const filter = {}; const filter = {};
const result = await app.models.Ticket.filter(ctx, filter); const result = await app.models.Ticket.filter(ctx, filter);
expect(result.length).toEqual(4); expect(result.length).toEqual(3);
}); });
it('should return the tickets matching the problems on false', async() => { it('should return the tickets matching the problems on false', async() => {
@ -42,7 +41,7 @@ xdescribe('ticket filter()', () => {
const filter = {}; const filter = {};
const result = await app.models.Ticket.filter(ctx, filter); const result = await app.models.Ticket.filter(ctx, filter);
expect(result.length).toEqual(10); expect(result.length).toEqual(7);
}); });
it('should return the tickets matching the problems on null', async() => { it('should return the tickets matching the problems on null', async() => {

18
package-lock.json generated
View File

@ -9575,13 +9575,13 @@
"dev": true "dev": true
}, },
"jasmine-reporters": { "jasmine-reporters": {
"version": "2.3.2", "version": "2.4.0",
"resolved": "https://registry.npmjs.org/jasmine-reporters/-/jasmine-reporters-2.3.2.tgz", "resolved": "https://registry.npmjs.org/jasmine-reporters/-/jasmine-reporters-2.4.0.tgz",
"integrity": "sha512-u/7AT9SkuZsUfFBLLzbErohTGNsEUCKaQbsVYnLFW1gEuL2DzmBL4n8v90uZsqIqlWvWUgian8J6yOt5Fyk/+A==", "integrity": "sha512-jxONSrBLN1vz/8zCx5YNWQSS8iyDAlXQ5yk1LuqITe4C6iXCDx5u6Q0jfNtkKhL4qLZPe69fL+AWvXFt9/x38w==",
"dev": true, "dev": true,
"requires": { "requires": {
"mkdirp": "^0.5.1", "mkdirp": "^0.5.1",
"xmldom": "^0.1.22" "xmldom": "^0.5.0"
} }
}, },
"jasmine-spec-reporter": { "jasmine-spec-reporter": {
@ -19907,7 +19907,7 @@
}, },
"globby": { "globby": {
"version": "6.1.0", "version": "6.1.0",
"resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", "resolved": "http://registry.npmjs.org/globby/-/globby-6.1.0.tgz",
"integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=",
"dev": true, "dev": true,
"requires": { "requires": {
@ -20470,9 +20470,9 @@
"integrity": "sha1-+mv3YqYKQT+z3Y9LA8WyaSONMI8=" "integrity": "sha1-+mv3YqYKQT+z3Y9LA8WyaSONMI8="
}, },
"xmldom": { "xmldom": {
"version": "0.1.31", "version": "0.5.0",
"resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.1.31.tgz", "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.5.0.tgz",
"integrity": "sha512-yS2uJflVQs6n+CyjHoaBmVSqIDevTAWrzMmjG1Gc7h1qQ7uVozNhEPJAwZXWyGQ/Gafo3fCwrcaokezLPupVyQ==", "integrity": "sha512-Foaj5FXVzgn7xFzsKeNIde9g6aFBxTPi37iwsno8QvApmtg7KYrr+OPyRHcJF7dud2a5nGRBXK3n0dL62Gf7PA==",
"dev": true "dev": true
}, },
"xpath": { "xpath": {
@ -20568,7 +20568,7 @@
}, },
"os-locale": { "os-locale": {
"version": "1.4.0", "version": "1.4.0",
"resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", "resolved": "http://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",
"integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=",
"dev": true, "dev": true,
"requires": { "requires": {

View File

@ -76,7 +76,7 @@
"html-webpack-plugin": "^4.0.0-beta.11", "html-webpack-plugin": "^4.0.0-beta.11",
"identity-obj-proxy": "^3.0.0", "identity-obj-proxy": "^3.0.0",
"jasmine": "^3.6.3", "jasmine": "^3.6.3",
"jasmine-reporters": "^2.3.2", "jasmine-reporters": "^2.4.0",
"jasmine-spec-reporter": "^6.0.0", "jasmine-spec-reporter": "^6.0.0",
"jest": "^26.0.1", "jest": "^26.0.1",
"jest-junit": "^8.0.0", "jest-junit": "^8.0.0",