Merge branch 'dev' into 2873-create-supplier-beneficiary
gitea/salix/pipeline/head This commit looks good Details

This commit is contained in:
Javi Gallego 2021-04-01 13:14:26 +02:00
commit 67f822ebdc
41 changed files with 6585 additions and 4731 deletions

View File

@ -20,17 +20,37 @@ module.exports = Self => {
}
});
Self.removeFile = async(ctx, id) => {
const models = Self.app.models;
const dms = await models.Dms.findById(id);
const trashDmsType = await models.DmsType.findOne({
where: {code: 'trash'}
});
Self.removeFile = async(ctx, id, options) => {
let tx;
let myOptions = {};
const hasWriteRole = await models.DmsType.hasWriteRole(ctx, dms.dmsTypeFk);
if (!hasWriteRole)
throw new UserError(`You don't have enough privileges`);
if (typeof options == 'object')
Object.assign(myOptions, options);
return dms.updateAttribute('dmsTypeFk', trashDmsType.id);
if (!myOptions.transaction) {
tx = await Self.beginTransaction({});
myOptions.transaction = tx;
}
try {
const models = Self.app.models;
const dms = await models.Dms.findById(id, null, myOptions);
const trashDmsType = await models.DmsType.findOne({
where: {code: 'trash'}
}, myOptions);
const hasWriteRole = await models.DmsType.hasWriteRole(ctx, dms.dmsTypeFk, myOptions);
if (!hasWriteRole)
throw new UserError(`You don't have enough privileges`);
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": {
"id": {
"type": "Number",
"type": "number",
"id": true,
"description": "The id"
},
"name": {
"type": "String",
"type": "string",
"required": true
},
"collectionFk": {
"type": "String",
"type": "string",
"required": true
},
"updated": {
"type": "Number"
"type": "number"
},
"nRefs": {
"type": "Number",
"required": true,
"default": 1
"type": "number"
}
},
"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)),
(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`)
VALUES
(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'),
(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
(1, 'CRI', 'Crisantemo', 2, 31, 35, 0),
(2, 'ITG', 'Anthurium', 1, 31, 35, 0),
(3, 'WPN', 'Paniculata', 2, 31, 35, 0),
(4, 'PRT', 'Delivery ports', 3, NULL, 35, 1),
(5, 'CON', 'Container', 3, NULL, 35, 1),
(6, 'ALS', 'Alstroemeria', 1, 31, 35, 0);
(1, 'CRI', 'Crisantemo', 2, 1, 31, 35, 0),
(2, 'ITG', 'Anthurium', 1, 1, 31, 35, 0),
(3, 'WPN', 'Paniculata', 2, 1, 31, 35, 0),
(4, 'PRT', 'Delivery ports', 3, 1, NULL, 35, 1),
(5, 'CON', 'Container', 3, 1, NULL, 35, 1),
(6, 'ALS', 'Alstroemeria', 1, 1, 31, 35, 0);
INSERT INTO `vn`.`ink`(`id`, `name`, `picture`, `showOrder`, `hex`)
VALUES
@ -2254,7 +2258,10 @@ INSERT INTO `vn`.`duaInvoiceIn`(`id`, `duaFk`, `invoiceInFk`)
(10, 10, 10);
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`();

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -2,7 +2,7 @@ const app = require('vn-loopback/server/server');
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
describe('item_getBalance()', () => {
it(`should return the item balance`, async() => {
it(`should return the item balance ordered by alert level`, async() => {
let stmts = [];
let params = {
@ -21,12 +21,11 @@ describe('item_getBalance()', () => {
let result = await conn.executeStmt(sql);
let itemBalance = result[0];
expect(itemBalance[0].alertLevel >= itemBalance[1].alertLevel).toBeTruthy();
expect(itemBalance[1].alertLevel >= itemBalance[2].alertLevel).toBeTruthy();
expect(itemBalance[2].alertLevel >= itemBalance[3].alertLevel).toBeTruthy();
expect(itemBalance[3].alertLevel >= itemBalance[4].alertLevel).toBeTruthy();
expect(itemBalance[4].alertLevel >= itemBalance[5].alertLevel).toBeTruthy();
expect(itemBalance[5].alertLevel >= itemBalance[6].alertLevel).toBeTruthy();
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');
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');
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',
accessType: 'READ',
returns: {
type: ['Object'],
type: ['object'],
root: true
},
http: {

View File

@ -4,12 +4,12 @@ module.exports = Self => {
accessType: 'WRITE',
accepts: {
arg: 'id',
type: 'Number',
type: 'number',
description: 'The document id',
http: {source: 'path'}
},
returns: {
type: 'Object',
type: 'object',
root: true
},
http: {
@ -18,16 +18,36 @@ module.exports = Self => {
}
});
Self.removeFile = async(ctx, id) => {
const models = Self.app.models;
const targetClaimDms = await models.ClaimDms.findById(id);
const targetDms = await models.Dms.findById(targetClaimDms.dmsFk);
const trashDmsType = await models.DmsType.findOne({where: {code: 'trash'}});
Self.removeFile = async(ctx, id, options) => {
let tx;
let myOptions = {};
await models.Dms.removeFile(ctx, targetClaimDms.dmsFk);
await targetClaimDms.destroy();
if (typeof options == 'object')
Object.assign(myOptions, options);
return targetDms.updateAttribute('dmsTypeFk', trashDmsType.id);
if (!myOptions.transaction) {
tx = await Self.beginTransaction({});
myOptions.transaction = tx;
}
try {
const models = Self.app.models;
const targetClaimDms = await models.ClaimDms.findById(id, null, myOptions);
const targetDms = await models.Dms.findById(targetClaimDms.dmsFk, null, myOptions);
const trashDmsType = await models.DmsType.findOne({where: {code: 'trash'}}, myOptions);
await models.Dms.removeFile(ctx, targetClaimDms.dmsFk, myOptions);
await targetClaimDms.destroy(myOptions);
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,24 +17,45 @@ module.exports = Self => {
}
});
Self.importTicketSales = async(ctx, params) => {
Self.importTicketSales = async(ctx, params, options) => {
let models = Self.app.models;
let userId = ctx.req.accessToken.userId;
let worker = await models.Worker.findOne({where: {userFk: userId}});
let ticketSales = await models.Sale.find({
where: {ticketFk: params.ticketFk}
});
let tx;
let myOptions = {};
let claimEnds = [];
ticketSales.forEach(sale => {
claimEnds.push({
saleFk: sale.id,
claimFk: params.claimFk,
workerFk: worker.id
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({
where: {ticketFk: params.ticketFk}
}, myOptions);
let claimEnds = [];
ticketSales.forEach(sale => {
claimEnds.push({
saleFk: sale.id,
claimFk: params.claimFk,
workerFk: worker.id
});
});
});
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');
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() => {
let ctx = {req: {accessToken: {userId: 5}}};
claimEnds = await app.models.ClaimEnd.importTicketSales(ctx, {
claimFk: 1,
ticketFk: 1
});
const ctx = {req: {accessToken: {userId: 5}}};
expect(claimEnds.length).toEqual(4);
expect(claimEnds[0].saleFk).toEqual(1);
expect(claimEnds[2].saleFk).toEqual(3);
const tx = await app.models.Entry.beginTransaction({});
try {
const options = {transaction: tx};
const claimEnds = await app.models.ClaimEnd.importTicketSales(ctx, {
claimFk: 1,
ticketFk: 1
}, options);
expect(claimEnds.length).toEqual(4);
expect(claimEnds[0].saleFk).toEqual(1);
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 userId = ctx.req.accessToken.userId;
const tx = await Self.beginTransaction({});
try {
let options = {transaction: tx};
const ticket = await models.Ticket.findById(ticketId, null, options);
const ticket = await models.Ticket.findById(ticketId, null, myOptions);
if (ticket.isDeleted)
throw new UserError(`You can't create a claim for a removed ticket`);
@ -41,7 +48,7 @@ module.exports = Self => {
clientFk: ticket.clientFk,
ticketCreated: ticket.shipped,
workerFk: userId
}, options);
}, myOptions);
const promises = [];
for (const sale of sales) {
@ -49,17 +56,18 @@ module.exports = Self => {
saleFk: sale.id,
claimFk: newClaim.id,
quantity: sale.quantity
}, options);
}, myOptions);
promises.push(newClaimBeginning);
}
await Promise.all(promises);
await tx.commit();
if (tx) await tx.commit();
return newClaim;
} catch (e) {
await tx.rollback();
if (tx) await tx.rollback();
throw e;
}
};

View File

@ -10,58 +10,67 @@ module.exports = Self => {
accepts: [
{
arg: 'filter',
type: 'Object',
type: 'object',
description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string',
http: {source: 'query'}
}, {
},
{
arg: 'tags',
type: ['Object'],
type: ['object'],
description: 'List of tags to filter with',
http: {source: 'query'}
}, {
},
{
arg: 'search',
type: 'String',
type: 'string',
description: `If it's and integer searchs by id, otherwise it searchs by client name`,
http: {source: 'query'}
}, {
},
{
arg: 'client',
type: 'String',
type: 'string',
description: 'The worker name',
http: {source: 'query'}
}, {
},
{
arg: 'id',
type: 'Integer',
type: 'integer',
description: 'The claim id',
http: {source: 'query'}
}, {
},
{
arg: 'clientFk',
type: 'Integer',
type: 'integer',
description: 'The client id',
http: {source: 'query'}
}, {
},
{
arg: 'claimStateFk',
type: 'Integer',
type: 'integer',
description: 'The claim state id',
http: {source: 'query'}
}, {
},
{
arg: 'salesPersonFk',
type: 'Integer',
type: 'integer',
description: 'The salesPerson id',
http: {source: 'query'}
}, {
},
{
arg: 'attenderFk',
type: 'Integer',
type: 'integer',
description: 'The attender worker id',
http: {source: 'query'}
}, {
},
{
arg: 'created',
type: 'Date',
type: 'date',
description: 'The to date filter',
http: {source: 'query'}
}
],
returns: {
type: ['Object'],
type: ['object'],
root: true
},
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 $t = ctx.req.__; // $translate
const resolvedState = 3;
let tx = await Self.beginTransaction({});
try {
let options = {transaction: tx};
let tx;
let myOptions = {};
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({
include: {
relation: 'claimDestination',
fields: ['addressFk']
},
where: {claimFk: claimFk}
}, options);
}, myOptions);
for (let i = 0; i < claimEnds.length; i++) {
const claimEnd = claimEnds[i];
for (let claimEnd of claimEnds) {
const destination = claimEnd.claimDestination();
const sale = await getSale(claimEnd.saleFk, options);
const sale = await getSale(claimEnd.saleFk, myOptions);
const addressId = destination && destination.addressFk;
let address;
if (addressId)
address = await models.Address.findById(addressId, null, options);
address = await models.Address.findById(addressId, null, myOptions);
const salesPerson = sale.ticket().client().salesPersonUser();
if (salesPerson) {
@ -67,7 +74,7 @@ module.exports = Self => {
addressFk: addressId,
companyFk: sale.ticket().companyFk,
warehouseFk: sale.ticket().warehouseFk
}, options);
}, myOptions);
if (!ticketFk) {
ticketFk = await createTicket(ctx, {
@ -75,7 +82,7 @@ module.exports = Self => {
warehouseId: sale.ticket().warehouseFk,
companyId: sale.ticket().companyFk,
addressId: addressId
}, options);
}, myOptions);
}
await models.Sale.create({
@ -85,19 +92,19 @@ module.exports = Self => {
quantity: -sale.quantity,
price: sale.price,
discount: 100
}, options);
}, myOptions);
}
let claim = await Self.findById(claimFk, null, options);
let claim = await Self.findById(claimFk, null, myOptions);
claim = await claim.updateAttributes({
claimStateFk: resolvedState
}, options);
}, myOptions);
await tx.commit();
if (tx) await tx.commit();
return claim;
} catch (e) {
await tx.rollback();
if (tx) await tx.rollback();
throw e;
}
};

View File

@ -10,36 +10,45 @@ describe('Claim createFromSales()', () => {
const ctx = {req: {accessToken: {userId: 1}}};
it('should create a new claim', async() => {
let claim = await app.models.Claim.createFromSales(ctx, ticketId, newSale);
const tx = await app.models.Claim.beginTransaction({});
expect(claim.ticketFk).toEqual(ticketId);
try {
const options = {transaction: tx};
let claimBeginning = await app.models.ClaimBeginning.findOne({where: {claimFk: claim.id}});
const claim = await app.models.Claim.createFromSales(ctx, ticketId, newSale, options);
expect(claimBeginning.saleFk).toEqual(newSale[0].id);
expect(claimBeginning.quantity).toEqual(newSale[0].quantity);
expect(claim.ticketFk).toEqual(ticketId);
const createdClaimId = claim.id;
let claimBeginning = await app.models.ClaimBeginning.findOne({where: {claimFk: claim.id}}, options);
// restores
await app.models.Claim.destroyById(createdClaimId);
expect(claimBeginning.saleFk).toEqual(newSale[0].id);
expect(claimBeginning.quantity).toEqual(newSale[0].quantity);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
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 createdClaimId = claim.id;
const tx = await app.models.Claim.beginTransaction({});
let error;
await app.models.Claim.createFromSales(ctx, ticketId, newSale)
try {
const options = {transaction: tx};
.catch(e => {
error = 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;
await tx.rollback();
}
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 trashTicket;
afterEach(async done => {
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 {
let claim = await app.models.Claim.findById(claimFk);
await claim.updateAttributes({
claimStateFk: pendentState,
hasToPickUp: false
});
const options = {transaction: tx};
spyOn(chatModel, 'sendCheckingPresence').and.callThrough();
claimEnds = await app.models.ClaimEnd.importTicketSales(ctx, {
claimFk: claimFk,
ticketFk: 1
}, options);
for (claimEnd of claimEnds)
await claimEnd.destroy();
await claimEnd.updateAttributes({claimDestinationFk: trashDestination}, options);
if (trashTicket)
await app.models.Ticket.destroyById(trashTicket.id);
} catch (error) {
console.error(error);
let claimBefore = await app.models.Claim.findById(claimFk, null, options);
await app.models.Claim.regularizeClaim(ctx, claimFk, options);
let claimAfter = await app.models.Claim.findById(claimFk, null, options);
trashTicket = await app.models.Ticket.findOne({where: {addressFk: 12}}, options);
expect(trashTicket.addressFk).toEqual(trashAddress);
expect(claimBefore.claimStateFk).toEqual(pendentState);
expect(claimAfter.claimStateFk).toEqual(resolvedState);
expect(chatModel.sendCheckingPresence).toHaveBeenCalledWith(ctx, 18, 'Trash');
expect(chatModel.sendCheckingPresence).toHaveBeenCalledTimes(4);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
done();
});
it('should send a chat message with value "Trash" and then change claim state to resolved', async() => {
spyOn(chatModel, 'sendCheckingPresence').and.callThrough();
claimEnds = await app.models.ClaimEnd.importTicketSales(ctx, {
claimFk: claimFk,
ticketFk: 1
});
for (claimEnd of claimEnds)
await claimEnd.updateAttributes({claimDestinationFk: trashDestination});
let claimBefore = await app.models.Claim.findById(claimFk);
await app.models.Claim.regularizeClaim(ctx, claimFk);
let claimAfter = await app.models.Claim.findById(claimFk);
trashTicket = await app.models.Ticket.findOne({where: {addressFk: 12}});
expect(trashTicket.addressFk).toEqual(trashAddress);
expect(claimBefore.claimStateFk).toEqual(pendentState);
expect(claimAfter.claimStateFk).toEqual(resolvedState);
expect(chatModel.sendCheckingPresence).toHaveBeenCalledWith(ctx, 18, 'Trash');
expect(chatModel.sendCheckingPresence).toHaveBeenCalledTimes(4);
});
it('should send a chat message with value "Bueno" and then change claim state to resolved', async() => {
spyOn(chatModel, 'sendCheckingPresence').and.callThrough();
const tx = await app.models.Claim.beginTransaction({});
claimEnds = await app.models.ClaimEnd.importTicketSales(ctx, {
claimFk: claimFk,
ticketFk: 1
});
try {
const options = {transaction: tx};
for (claimEnd of claimEnds)
await claimEnd.updateAttributes({claimDestinationFk: okDestination});
spyOn(chatModel, 'sendCheckingPresence').and.callThrough();
await app.models.Claim.regularizeClaim(ctx, claimFk);
claimEnds = await app.models.ClaimEnd.importTicketSales(ctx, {
claimFk: claimFk,
ticketFk: 1
}, options);
expect(chatModel.sendCheckingPresence).toHaveBeenCalledWith(ctx, 18, 'Bueno');
expect(chatModel.sendCheckingPresence).toHaveBeenCalledTimes(4);
for (claimEnd of claimEnds)
await claimEnd.updateAttributes({claimDestinationFk: okDestination}, options);
await app.models.Claim.regularizeClaim(ctx, claimFk, options);
expect(chatModel.sendCheckingPresence).toHaveBeenCalledWith(ctx, 18, 'Bueno');
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() => {
spyOn(chatModel, 'sendCheckingPresence').and.callThrough();
const tx = await app.models.Claim.beginTransaction({});
claimEnds = await app.models.ClaimEnd.importTicketSales(ctx, {
claimFk: claimFk,
ticketFk: 1
});
try {
const options = {transaction: tx};
for (claimEnd of claimEnds)
await claimEnd.updateAttributes({claimDestinationFk: okDestination});
spyOn(chatModel, 'sendCheckingPresence').and.callThrough();
await app.models.Claim.regularizeClaim(ctx, claimFk);
claimEnds = await app.models.ClaimEnd.importTicketSales(ctx, {
claimFk: claimFk,
ticketFk: 1
}, options);
expect(chatModel.sendCheckingPresence).toHaveBeenCalledWith(ctx, 18, 'Bueno');
expect(chatModel.sendCheckingPresence).toHaveBeenCalledTimes(4);
for (claimEnd of claimEnds)
await claimEnd.updateAttributes({claimDestinationFk: okDestination}, options);
await app.models.Claim.regularizeClaim(ctx, claimFk, options);
expect(chatModel.sendCheckingPresence).toHaveBeenCalledWith(ctx, 18, 'Bueno');
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');
describe('Update Claim', () => {
let newDate = new Date();
const newDate = new Date();
const originalData = {
ticketFk: 3,
clientFk: 101,
@ -14,89 +14,114 @@ describe('Update Claim', () => {
};
it(`should throw an error as the user doesn't have rights`, async() => {
let newClaim = await app.models.Claim.create(originalData);
const forbiddenState = 3;
const salesPersonId = 18;
const ctx = {
req: {
accessToken: {
userId: salesPersonId
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 salesPersonId = 18;
const ctx = {
req: {
accessToken: {
userId: salesPersonId
}
},
args: {
claimStateFk: forbiddenState,
observation: 'valid observation'
}
},
args: {
claimStateFk: forbiddenState,
observation: 'valid observation'
}
};
await app.models.Claim.updateClaim(ctx, newClaim.id)
.catch(e => {
error = e;
});
};
await app.models.Claim.updateClaim(ctx, newClaim.id, options);
await tx.rollback();
} catch (e) {
error = e;
await tx.rollback();
}
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() => {
let newClaim = await app.models.Claim.create(originalData);
const tx = await app.models.Claim.beginTransaction({});
const canceledState = 4;
const claimManagerId = 72;
const ctx = {
req: {
accessToken: {
userId: claimManagerId
try {
const options = {transaction: tx};
const newClaim = await app.models.Claim.create(originalData, options);
const canceledState = 4;
const claimManagerId = 72;
const ctx = {
req: {
accessToken: {
userId: claimManagerId
}
},
args: {
observation: 'valid observation',
claimStateFk: canceledState,
hasToPickUp: false
}
},
args: {
observation: 'valid observation',
claimStateFk: canceledState,
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 app.models.Claim.destroyById(newClaim.id);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should change some sensible fields as claimManager', async() => {
let newClaim = await app.models.Claim.create(originalData);
const chatModel = app.models.Chat;
spyOn(chatModel, 'sendCheckingPresence').and.callThrough();
const tx = await app.models.Claim.beginTransaction({});
const claimManagerId = 72;
const ctx = {
req: {
accessToken: {userId: claimManagerId},
headers: {origin: 'http://localhost'}
},
args: {
claimStateFk: 3,
workerFk: 5,
observation: 'another valid observation',
hasToPickUp: true
}
};
ctx.req.__ = (value, params) => {
return params.nickname;
};
await app.models.Claim.updateClaim(ctx, newClaim.id);
try {
const options = {transaction: tx};
let updatedClaim = await app.models.Claim.findById(newClaim.id);
const newClaim = await app.models.Claim.create(originalData, options);
expect(updatedClaim.observation).toEqual(ctx.args.observation);
expect(updatedClaim.claimStateFk).toEqual(ctx.args.claimStateFk);
expect(updatedClaim.workerFk).toEqual(ctx.args.workerFk);
expect(chatModel.sendCheckingPresence).toHaveBeenCalled();
const chatModel = app.models.Chat;
spyOn(chatModel, 'sendCheckingPresence').and.callThrough();
// restores
await app.models.Claim.destroyById(newClaim.id);
const claimManagerId = 72;
const ctx = {
req: {
accessToken: {userId: claimManagerId},
headers: {origin: 'http://localhost'}
},
args: {
claimStateFk: 3,
workerFk: 5,
observation: 'another valid observation',
hasToPickUp: true
}
};
ctx.req.__ = (value, params) => {
return params.nickname;
};
await app.models.Claim.updateClaim(ctx, newClaim.id, options);
let updatedClaim = await app.models.Claim.findById(newClaim.id, null, options);
expect(updatedClaim.observation).toEqual(ctx.args.observation);
expect(updatedClaim.claimStateFk).toEqual(ctx.args.claimStateFk);
expect(updatedClaim.workerFk).toEqual(ctx.args.workerFk);
expect(chatModel.sendCheckingPresence).toHaveBeenCalled();
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
});

View File

@ -1,9 +1,8 @@
const app = require('vn-loopback/server/server');
describe('Update Claim', () => {
let newDate = new Date();
let newInstance;
let original = {
const newDate = new Date();
const original = {
ticketFk: 3,
clientFk: 101,
ticketCreated: newDate,
@ -14,30 +13,43 @@ describe('Update Claim', () => {
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() => {
const ctx = {args: {isChargedToMana: false}};
const result = await app.models.Claim.updateClaimAction(ctx, newInstance.id);
const tx = await app.models.Claim.beginTransaction({});
expect(result.id).toEqual(newInstance.id);
expect(result.isChargedToMana).toBeFalsy();
try {
const options = {transaction: tx};
const ctx = {args: {isChargedToMana: false}};
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.isChargedToMana).toBeFalsy();
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should update the claim responsibility attribute', async() => {
const ctx = {args: {responsibility: 2}};
const result = await app.models.Claim.updateClaimAction(ctx, newInstance.id);
const tx = await app.models.Claim.beginTransaction({});
expect(result.id).toEqual(newInstance.id);
expect(result.responsibility).toEqual(2);
try {
const options = {transaction: tx};
const ctx = {args: {responsibility: 2}};
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.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',
accepts: [{
arg: 'ctx',
type: 'Object',
type: 'object',
http: {source: 'context'}
}, {
},
{
arg: 'id',
type: 'Number',
type: 'number',
description: 'Claim id',
http: {source: 'path'}
},
{
arg: 'workerFk',
type: 'Number'
type: 'number'
},
{
arg: 'claimStateFk',
type: 'Number'
type: 'number'
},
{
arg: 'observation',
type: 'String'
type: 'string'
},
{
arg: 'hasToPickUp',
@ -38,51 +39,69 @@ module.exports = Self => {
}
});
Self.updateClaim = async(ctx, id) => {
Self.updateClaim = async(ctx, id, options) => {
const models = Self.app.models;
const userId = ctx.req.accessToken.userId;
const args = ctx.args;
const $t = ctx.req.__; // $translate
const claim = await models.Claim.findById(id, {
include: {
relation: 'client',
scope: {
include: {
relation: 'salesPersonUser'
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, {
include: {
relation: 'client',
scope: {
include: {
relation: 'salesPersonUser'
}
}
}
}, myOptions);
let changedHasToPickUp = false;
if (args.hasToPickUp)
changedHasToPickUp = true;
if (args.claimStateFk) {
const canUpdate = await canChangeState(ctx, claim.claimStateFk, myOptions);
const hasRights = await canChangeState(ctx, args.claimStateFk, myOptions);
const isClaimManager = await models.Account.hasRole(userId, 'claimManager', myOptions);
if (!canUpdate || !hasRights || changedHasToPickUp && !isClaimManager)
throw new UserError(`You don't have enough privileges to change that field`);
}
delete args.ctx;
const updatedClaim = await claim.updateAttributes(args, myOptions);
// Get sales person from claim client
const salesPerson = claim.client().salesPersonUser();
if (salesPerson && changedHasToPickUp && updatedClaim.hasToPickUp) {
const origin = ctx.req.headers.origin;
const message = $t('Claim will be picked', {
claimId: claim.id,
clientName: claim.client().name,
claimUrl: `${origin}/#!/claim/${claim.id}/summary`
});
await models.Chat.sendCheckingPresence(ctx, salesPerson.id, message);
}
});
let changedHasToPickUp = false;
if (args.hasToPickUp)
changedHasToPickUp = true;
if (args.claimStateFk) {
const canUpdate = await canChangeState(ctx, claim.claimStateFk);
const hasRights = await canChangeState(ctx, args.claimStateFk);
const isClaimManager = await models.Account.hasRole(userId, 'claimManager');
if (tx) await tx.commit();
if (!canUpdate || !hasRights || changedHasToPickUp && !isClaimManager)
throw new UserError(`You don't have enough privileges to change that field`);
return updatedClaim;
} catch (e) {
if (tx) await tx.rollback();
throw e;
}
delete args.ctx;
const updatedClaim = await claim.updateAttributes(args);
// Get sales person from claim client
const salesPerson = claim.client().salesPersonUser();
if (salesPerson && changedHasToPickUp && updatedClaim.hasToPickUp) {
const origin = ctx.req.headers.origin;
const message = $t('Claim will be picked', {
claimId: claim.id,
clientName: claim.client().name,
claimUrl: `${origin}/#!/claim/${claim.id}/summary`
});
await models.Chat.sendCheckingPresence(ctx, salesPerson.id, message);
}
return updatedClaim;
};
async function canChangeState(ctx, id) {
async function canChangeState(ctx, id, options) {
let models = Self.app.models;
let userId = ctx.req.accessToken.userId;
@ -90,9 +109,9 @@ module.exports = Self => {
include: {
relation: 'writeRole'
}
});
}, options);
let stateRole = state.writeRole().name;
let canUpdate = await models.Account.hasRole(userId, stateRole);
let canUpdate = await models.Account.hasRole(userId, stateRole, options);
return canUpdate;
}

View File

@ -28,12 +28,32 @@ module.exports = Self => {
}
});
Self.updateClaimAction = async(ctx, id) => {
const models = Self.app.models;
const claim = await models.Claim.findById(id);
const args = ctx.args;
delete args.ctx;
Self.updateClaimAction = async(ctx, id, options) => {
let tx;
let myOptions = {};
return await claim.updateAttributes(args);
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 claim = await models.Claim.findById(id, null, myOptions);
const args = ctx.args;
delete args.ctx;
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',
accepts: [{
arg: 'id',
type: 'Number',
type: 'number',
description: 'The claim id',
http: {source: 'path'}
}, {
},
{
arg: 'warehouseId',
type: 'Number',
type: 'number',
description: 'The warehouse id',
required: true
}, {
},
{
arg: 'companyId',
type: 'Number',
type: 'number',
description: 'The company id',
required: true
}, {
},
{
arg: 'dmsTypeId',
type: 'Number',
type: 'number',
description: 'The dms type id',
required: true
}, {
},
{
arg: 'reference',
type: 'String',
type: 'string',
required: true
}, {
},
{
arg: 'description',
type: 'String',
type: 'string',
required: true
}, {
},
{
arg: 'hasFile',
type: 'Boolean',
type: 'boolean',
description: 'True if has an attached file',
required: true
}],
returns: {
type: 'Object',
type: 'object',
root: true
},
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 promises = [];
const tx = await Self.beginTransaction({});
try {
const options = {transaction: tx};
const uploadedFiles = await models.Dms.uploadFile(ctx, options);
const uploadedFiles = await models.Dms.uploadFile(ctx, myOptions);
uploadedFiles.forEach(dms => {
const newClaimDms = models.ClaimDms.create({
claimFk: id,
dmsFk: dms.id
}, options);
}, myOptions);
promises.push(newClaimDms);
});
const resolvedPromises = await Promise.all(promises);
await tx.commit();
if (tx) await tx.commit();
return resolvedPromises;
} catch (err) {
await tx.rollback();
throw err;
} catch (e) {
if (tx) await tx.rollback();
throw e;
}
};
};

View File

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

View File

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

View File

@ -1,14 +1,14 @@
const app = require('vn-loopback/server/server');
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() => {
const ids = [996, 997, 998, 999];
let error;
try {
await app.models.Route.clone(ids, startDate);
await app.models.Route.clone(ids, createdDate);
} catch (e) {
error = e;
}
@ -20,7 +20,7 @@ describe('route clone()', () => {
it('should clone two routes', async() => {
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);

View File

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

View File

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

View File

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

View File

@ -1,5 +1,5 @@
Vehicle: Vehículo
Download selected routes as PDF: Descargar rutas seleccionadas como PDF
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

View File

@ -10,7 +10,7 @@
data="contacts"
form="form">
</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">
<div ng-repeat="contact in contacts" class="contact">
<vn-vertical>

View File

@ -1,7 +1,6 @@
const app = require('vn-loopback/server/server');
// #2868 Excluded until database export
xdescribe('ticket filter()', () => {
describe('ticket filter()', () => {
it('should return the tickets matching the filter', async() => {
const ctx = {req: {accessToken: {userId: 9}}, args: {}};
const filter = {order: 'id DESC'};
@ -24,7 +23,7 @@ xdescribe('ticket filter()', () => {
const 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() => {
@ -42,7 +41,7 @@ xdescribe('ticket filter()', () => {
const 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() => {