Merge branch 'dev' into 5425-modCamposBasicos(pesoycaja)
gitea/salix/pipeline/head There was a failure building this commit
Details
gitea/salix/pipeline/head There was a failure building this commit
Details
This commit is contained in:
commit
1ab8570ed3
|
@ -5,5 +5,6 @@
|
|||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.eslint": true
|
||||
},
|
||||
"search.useIgnoreFiles": false
|
||||
"search.useIgnoreFiles": false,
|
||||
"editor.defaultFormatter": "dbaeumer.vscode-eslint"
|
||||
}
|
||||
|
|
|
@ -1,215 +0,0 @@
|
|||
const md5 = require('md5');
|
||||
const fs = require('fs-extra');
|
||||
|
||||
module.exports = Self => {
|
||||
Self.remoteMethodCtx('saveSign', {
|
||||
description: 'Save sign',
|
||||
accessType: 'WRITE',
|
||||
accepts:
|
||||
[
|
||||
{
|
||||
arg: 'signContent',
|
||||
type: 'string',
|
||||
required: true,
|
||||
description: 'The sign content'
|
||||
}, {
|
||||
arg: 'tickets',
|
||||
type: ['number'],
|
||||
required: true,
|
||||
description: 'The tickets'
|
||||
}, {
|
||||
arg: 'signedTime',
|
||||
type: 'date',
|
||||
description: 'The signed time'
|
||||
}, {
|
||||
arg: 'addressFk',
|
||||
type: 'number',
|
||||
required: true,
|
||||
description: 'The address fk'
|
||||
}
|
||||
],
|
||||
returns: {
|
||||
type: 'Object',
|
||||
root: true
|
||||
},
|
||||
http: {
|
||||
path: `/saveSign`,
|
||||
verb: 'POST'
|
||||
}
|
||||
});
|
||||
|
||||
async function createGestDoc(ticketId, userFk) {
|
||||
const models = Self.app.models;
|
||||
if (!await gestDocExists(ticketId)) {
|
||||
const result = await models.Ticket.findOne({
|
||||
where: {
|
||||
id: ticketId
|
||||
},
|
||||
include: [
|
||||
{
|
||||
relation: 'warehouse',
|
||||
scope: {
|
||||
fields: ['id']
|
||||
}
|
||||
}, {
|
||||
relation: 'client',
|
||||
scope: {
|
||||
fields: ['name']
|
||||
}
|
||||
}, {
|
||||
relation: 'route',
|
||||
scope: {
|
||||
fields: ['id']
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
const warehouseFk = result.warehouseFk;
|
||||
const companyFk = result.companyFk;
|
||||
const client = result.client.name;
|
||||
const route = result.route.id;
|
||||
|
||||
const resultDmsType = await models.DmsType.findOne({
|
||||
where: {
|
||||
code: 'Ticket'
|
||||
}
|
||||
});
|
||||
|
||||
const resultDms = await models.Dms.create({
|
||||
dmsTypeFk: resultDmsType.id,
|
||||
reference: ticketId,
|
||||
description: `Ticket ${ticketId} Cliente ${client} Ruta ${route}`,
|
||||
companyFk: companyFk,
|
||||
warehouseFk: warehouseFk,
|
||||
workerFk: userFk
|
||||
});
|
||||
|
||||
return resultDms.insertId;
|
||||
}
|
||||
}
|
||||
|
||||
async function gestDocExists(ticket) {
|
||||
const models = Self.app.models;
|
||||
const result = await models.TicketDms.findOne({
|
||||
where: {
|
||||
ticketFk: ticket
|
||||
},
|
||||
fields: ['dmsFk']
|
||||
});
|
||||
|
||||
if (result == null)
|
||||
return false;
|
||||
|
||||
const isSigned = await models.Ticket.findOne({
|
||||
where: {
|
||||
id: ticket
|
||||
},
|
||||
fields: ['isSigned']
|
||||
});
|
||||
|
||||
if (isSigned)
|
||||
return true;
|
||||
else
|
||||
await models.Dms.destroyById(ticket);
|
||||
}
|
||||
|
||||
async function dmsRecover(ticket, signContent) {
|
||||
const models = Self.app.models;
|
||||
await models.DmsRecover.create({
|
||||
ticketFk: ticket,
|
||||
sign: signContent
|
||||
});
|
||||
}
|
||||
|
||||
async function ticketGestdoc(ticket, dmsFk) {
|
||||
const models = Self.app.models;
|
||||
models.TicketDms.replaceOrCreate({
|
||||
ticketFk: ticket,
|
||||
dmsFk: dmsFk
|
||||
});
|
||||
|
||||
const queryVnTicketSetState = `CALL vn.ticket_setState(?, ?)`;
|
||||
|
||||
await Self.rawSql(queryVnTicketSetState, [ticket, 'DELIVERED']);
|
||||
}
|
||||
|
||||
async function updateGestdoc(file, ticket) {
|
||||
const models = Self.app.models;
|
||||
models.Dms.updateOne({
|
||||
where: {
|
||||
id: ticket
|
||||
},
|
||||
file: file,
|
||||
contentType: 'image/png'
|
||||
});
|
||||
}
|
||||
|
||||
Self.saveSign = async(ctx, signContent, tickets, signedTime) => {
|
||||
const models = Self.app.models;
|
||||
let tx = await Self.beginTransaction({});
|
||||
try {
|
||||
const userId = ctx.req.accessToken.userId;
|
||||
|
||||
const dmsDir = `storage/dms`;
|
||||
|
||||
let image = null;
|
||||
|
||||
for (let i = 0; i < tickets.length; i++) {
|
||||
const alertLevel = await models.TicketState.findOne({
|
||||
where: {
|
||||
ticketFk: tickets[i]
|
||||
},
|
||||
fields: ['alertLevel']
|
||||
});
|
||||
|
||||
signedTime ? signedTime != undefined : signedTime = Date.vnNew();
|
||||
|
||||
if (alertLevel >= 2) {
|
||||
let dir;
|
||||
let id = null;
|
||||
let fileName = null;
|
||||
|
||||
if (!await gestDocExists(tickets[i])) {
|
||||
id = await createGestDoc(tickets[i], userId);
|
||||
|
||||
const hashDir = md5(id).substring(0, 3);
|
||||
dir = `${dmsDir}/${hashDir}`;
|
||||
|
||||
if (!fs.existsSync(dir))
|
||||
fs.mkdirSync(dir);
|
||||
|
||||
fileName = `${id}.png`;
|
||||
image = `${dir}/${fileName}`;
|
||||
} else
|
||||
|
||||
if (image != null) {
|
||||
if (!fs.existsSync(dir))
|
||||
dmsRecover(tickets[i], signContent);
|
||||
else {
|
||||
fs.writeFile(image, signContent, 'base64', async function(err) {
|
||||
if (err) {
|
||||
await tx.rollback();
|
||||
return err.message;
|
||||
}
|
||||
});
|
||||
}
|
||||
} else
|
||||
dmsRecover(tickets[i], signContent);
|
||||
|
||||
if (id != null && fileName.length > 0) {
|
||||
ticketGestdoc(tickets[i], id);
|
||||
updateGestdoc(id, fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tx) await tx.commit();
|
||||
|
||||
return 'OK';
|
||||
} catch (err) {
|
||||
await tx.rollback();
|
||||
throw err.message;
|
||||
}
|
||||
};
|
||||
};
|
|
@ -9,17 +9,29 @@
|
|||
"properties": {
|
||||
"id": {
|
||||
"id": true,
|
||||
"type": "number",
|
||||
"forceId": false
|
||||
"type": "number"
|
||||
},
|
||||
"date": {
|
||||
"created": {
|
||||
"type": "date"
|
||||
},
|
||||
"m3":{
|
||||
"longitude":{
|
||||
"type": "number"
|
||||
},
|
||||
"warehouseFk":{
|
||||
"latitude":{
|
||||
"type": "number"
|
||||
},
|
||||
"dated":{
|
||||
"type": "date"
|
||||
},
|
||||
"ticketFk":{
|
||||
"type": "number"
|
||||
}
|
||||
}
|
||||
},
|
||||
"relations": {
|
||||
"ticket": {
|
||||
"type": "belongsTo",
|
||||
"model": "Ticket",
|
||||
"foreignKey": "ticketFk"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@ module.exports = Self => {
|
|||
require('../methods/dms/removeFile')(Self);
|
||||
require('../methods/dms/updateFile')(Self);
|
||||
require('../methods/dms/deleteTrashFiles')(Self);
|
||||
require('../methods/dms/saveSign')(Self);
|
||||
|
||||
Self.checkRole = async function(ctx, id) {
|
||||
const models = Self.app.models;
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
DROP TABLE `vn`.`dmsRecover`;
|
||||
|
||||
ALTER TABLE `vn`.`delivery` DROP FOREIGN KEY delivery_FK;
|
||||
ALTER TABLE `vn`.`delivery` DROP COLUMN addressFk;
|
||||
ALTER TABLE `vn`.`delivery` ADD ticketFk INT NOT NULL;
|
||||
ALTER TABLE `vn`.`delivery` ADD CONSTRAINT delivery_ticketFk_FK FOREIGN KEY (`ticketFk`) REFERENCES `vn`.`ticket`(`id`);
|
||||
|
||||
DELETE FROM `salix`.`ACL` WHERE `property` = 'saveSign';
|
||||
INSERT INTO `salix`.`ACL` (`model`,`property`,`accessType`,`permission`,`principalId`)
|
||||
VALUES
|
||||
('Ticket','saveSign','WRITE','ALLOW','employee');
|
||||
|
||||
DROP PROCEDURE IF EXISTS vn.route_getTickets;
|
||||
|
||||
DELIMITER $$
|
||||
$$
|
||||
CREATE DEFINER=`root`@`localhost` PROCEDURE `vn`.`route_getTickets`(vRouteFk INT)
|
||||
BEGIN
|
||||
/**
|
||||
* Pasado un RouteFk devuelve la información
|
||||
* de sus tickets.
|
||||
*
|
||||
* @param vRouteFk
|
||||
*
|
||||
* @select Información de los tickets
|
||||
*/
|
||||
|
||||
SELECT
|
||||
t.id Id,
|
||||
t.clientFk Client,
|
||||
a.id Address,
|
||||
t.packages Packages,
|
||||
a.street AddressName,
|
||||
a.postalCode PostalCode,
|
||||
a.city City,
|
||||
sub2.itemPackingTypeFk PackingType,
|
||||
c.phone ClientPhone,
|
||||
c.mobile ClientMobile,
|
||||
a.phone AddressPhone,
|
||||
a.mobile AddressMobile,
|
||||
d.longitude Longitude,
|
||||
d.latitude Latitude,
|
||||
wm.mediaValue SalePersonPhone,
|
||||
tob.Note Note,
|
||||
t.isSigned Signed
|
||||
FROM ticket t
|
||||
JOIN client c ON t.clientFk = c.id
|
||||
JOIN address a ON t.addressFk = a.id
|
||||
LEFT JOIN delivery d ON t.id = d.ticketFk
|
||||
LEFT JOIN workerMedia wm ON wm.workerFk = c.salesPersonFk
|
||||
LEFT JOIN
|
||||
(SELECT tob.description Note, t.id
|
||||
FROM ticketObservation tob
|
||||
JOIN ticket t ON tob.ticketFk = t.id
|
||||
JOIN observationType ot ON ot.id = tob.observationTypeFk
|
||||
WHERE t.routeFk = vRouteFk
|
||||
AND ot.code = 'delivery'
|
||||
)tob ON tob.id = t.id
|
||||
LEFT JOIN
|
||||
(SELECT sub.ticketFk,
|
||||
CONCAT('(', GROUP_CONCAT(DISTINCT sub.itemPackingTypeFk ORDER BY sub.items DESC SEPARATOR ','), ') ') itemPackingTypeFk
|
||||
FROM (SELECT s.ticketFk , i.itemPackingTypeFk, COUNT(*) items
|
||||
FROM ticket t
|
||||
JOIN sale s ON s.ticketFk = t.id
|
||||
JOIN item i ON i.id = s.itemFk
|
||||
WHERE t.routeFk = vRouteFk
|
||||
GROUP BY t.id,i.itemPackingTypeFk)sub
|
||||
GROUP BY sub.ticketFk
|
||||
) sub2 ON sub2.ticketFk = t.id
|
||||
WHERE t.routeFk = vRouteFk
|
||||
GROUP BY t.id
|
||||
ORDER BY t.priority;
|
||||
END$$
|
||||
DELIMITER ;
|
|
@ -0,0 +1,3 @@
|
|||
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
|
||||
VALUES ('Operator', '*', 'READ', 'ALLOW', 'ROLE', 'employee'),
|
||||
('Operator', '*', 'WRITE', 'ALLOW', 'ROLE', 'employee');
|
|
@ -0,0 +1,159 @@
|
|||
ALTER TABLE `vn`.`operator` ADD sectorFk int(11) NULL;
|
||||
ALTER TABLE `vn`.`operator` ADD labelerFk tinyint(3) unsigned NULL;
|
||||
ALTER TABLE `vn`.`operator` ADD CONSTRAINT operator_FK_5 FOREIGN KEY (labelerFk) REFERENCES `vn`.`printer`(id) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
UPDATE `vn`.`operator` o
|
||||
JOIN (SELECT id, sectorFk, labelerFk
|
||||
FROM `vn`.`worker`) sub ON sub.id = o.workerFk
|
||||
SET o.sectorFk = sub.sectorFk,
|
||||
o.labelerFk = sub.labelerFk;
|
||||
|
||||
DELIMITER $$
|
||||
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`collection_printSticker`(
|
||||
vSelf INT,
|
||||
vLabelCount INT
|
||||
)
|
||||
BEGIN
|
||||
/**
|
||||
* Prints a yellow label from a collection or a ticket
|
||||
*
|
||||
* @param vSelf collection or ticket
|
||||
* @param vLabelCount number of times the collection has been printed
|
||||
*/
|
||||
DECLARE vPrintArgs JSON DEFAULT JSON_OBJECT('collectionOrTicketFk', vSelf);
|
||||
|
||||
IF vLabelCount IS NULL THEN
|
||||
INSERT INTO ticketTrolley
|
||||
SELECT ticketFk, 1
|
||||
FROM ticketCollection
|
||||
WHERE collectionFk = vSelf
|
||||
ON DUPLICATE KEY UPDATE labelCount = labelCount + 1;
|
||||
ELSE
|
||||
SET vPrintArgs = JSON_MERGE_PATCH(vPrintArgs, JSON_OBJECT('labelCount', vLabelCount));
|
||||
END IF;
|
||||
|
||||
CALL report_print(
|
||||
'LabelCollection',
|
||||
(SELECT o.labelerFk FROM operator o WHERE o.workerFk = account.myUser_getId()),
|
||||
account.myUser_getId(),
|
||||
vPrintArgs,
|
||||
'high'
|
||||
);
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
||||
DELIMITER $$
|
||||
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`expeditionPallet_printLabel`(vSelf INT)
|
||||
BEGIN
|
||||
/**
|
||||
* Calls the report_print procedure and passes it
|
||||
* the necessary parameters for printing.
|
||||
*
|
||||
* @param vSelf expeditioPallet id.
|
||||
*/
|
||||
DECLARE vPrinterFk INT;
|
||||
DECLARE vUserFk INT DEFAULT account.myUser_getId();
|
||||
|
||||
SELECT o.labelerFk INTO vPrinterFk
|
||||
FROM operator o
|
||||
WHERE o.workerFk = vUserFk;
|
||||
|
||||
CALL vn.report_print(
|
||||
'LabelPalletExpedition',
|
||||
vPrinterFk,
|
||||
account.myUser_getId(),
|
||||
JSON_OBJECT('palletFk', vSelf, 'userFk', vUserFk),
|
||||
'high'
|
||||
);
|
||||
|
||||
UPDATE vn.expeditionPallet
|
||||
SET isPrint = TRUE
|
||||
WHERE id = vSelf;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
||||
DELIMITER $$
|
||||
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`itemShelving_getAlternatives`(vShelvingFk VARCHAR(10))
|
||||
BEGIN
|
||||
/**
|
||||
* Devuelve un listado de posibles ubicaciones alternativas a ubicar los item de la matricula
|
||||
* del carro que se le ha pasado.
|
||||
*
|
||||
* @param vShelvingFk matricula del carro
|
||||
*/
|
||||
SELECT is2.id,is2.shelvingFk , p.code, is2.itemFk , is2.visible, p.pickingOrder
|
||||
FROM itemShelving is2
|
||||
JOIN shelving sh ON sh.code = is2.shelvingFk
|
||||
JOIN parking p ON p.id = sh.parkingFk
|
||||
JOIN sector s ON s.id = p.sectorFk
|
||||
LEFT JOIN operator o ON o.sectorFk = s.id
|
||||
LEFT JOIN worker w ON w.sectorFk = s.id AND w.id = account.myUser_getId()
|
||||
JOIN warehouse wh ON wh.id = s.warehouseFk
|
||||
JOIN itemShelving is3 ON is3.itemFk = is2.itemFk AND is3.shelvingFk = vShelvingFk COLLATE utf8_unicode_ci
|
||||
WHERE is2.shelvingFk <> vShelvingFk COLLATE utf8_unicode_ci
|
||||
GROUP BY is2.id
|
||||
ORDER BY p.pickingOrder DESC;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
||||
DELIMITER $$
|
||||
CREATE OR REPLACE DEFINER=`root`@`localhost` TRIGGER `vn`.`operator_beforeInsert`
|
||||
BEFORE INSERT ON `operator`
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
CALL vn.printer_checkSector(NEW.labelerFk, NEW.sectorFk);
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
||||
DELIMITER $$
|
||||
CREATE OR REPLACE DEFINER=`root`@`localhost` TRIGGER `vn`.`operator_beforeUpdate`
|
||||
BEFORE UPDATE ON `operator`
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
IF NOT (NEW.labelerFk <=> OLD.labelerFk AND NEW.sectorFk <=> OLD.sectorFk) THEN
|
||||
CALL vn.printer_checkSector(NEW.labelerFk, NEW.sectorFk);
|
||||
END IF;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
||||
DELIMITER $$
|
||||
CREATE OR REPLACE DEFINER=`root`@`localhost` TRIGGER `vn`.`worker_beforeUpdate`
|
||||
BEFORE UPDATE ON `worker`
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
IF NOT (NEW.labelerFk <=> OLD.labelerFk AND NEW.sectorFk <=> OLD.sectorFk) THEN
|
||||
CALL vn.printer_checkSector(NEW.labelerFk, NEW.sectorFk);
|
||||
|
||||
INSERT IGNORE INTO vn.operator (workerFk)
|
||||
VALUES (NEW.id);
|
||||
|
||||
UPDATE operator
|
||||
SET labelerFk = NEW.labelerFk,
|
||||
sectorFk = NEW.sectorFk
|
||||
WHERE workerFk = NEW.id;
|
||||
END IF;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
||||
CREATE OR REPLACE DEFINER=`root`@`localhost`
|
||||
SQL SECURITY DEFINER
|
||||
VIEW `vn`.`operatorWorkerCode`
|
||||
AS SELECT `o`.`workerFk` AS `workerFk`,
|
||||
concat(`w`.`firstName`, ' ', `w`.`lastName`) AS `fullName`,
|
||||
`w`.`code` AS `code`,
|
||||
`o`.`numberOfWagons` AS `numberOfWagons`
|
||||
FROM (
|
||||
(
|
||||
`vn`.`worker` `w`
|
||||
JOIN `vn`.`operator` `o` ON(`o`.`workerFk` = `w`.`id`)
|
||||
)
|
||||
JOIN `vn`.`sector` `s` ON(`o`.`sectorFk` = `s`.`id`)
|
||||
)
|
||||
WHERE `o`.`sectorFk` IS NOT NULL
|
||||
AND `s`.`code` IN (
|
||||
'H2',
|
||||
'H2',
|
||||
'PEQUES_H',
|
||||
'ALTILLO COMP',
|
||||
'ALTILLO ARTI'
|
||||
)
|
|
@ -173,6 +173,10 @@ INSERT INTO `vn`.`sector`(`id`, `description`, `warehouseFk`, `isPreviousPrepare
|
|||
(1, 'First sector', 1, 1, 'FIRST'),
|
||||
(2, 'Second sector', 2, 0, 'SECOND');
|
||||
|
||||
INSERT INTO `vn`.`operator` (`workerFk`, `numberOfWagons`, `trainFk`, `itemPackingTypeFk`, `warehouseFk`, `sectorFk`, `labelerFk`)
|
||||
VALUES ('1106', '1', '1', 'H', '1', '1', '1'),
|
||||
('1107', '1', '1', 'V', '1', '2', '1');
|
||||
|
||||
INSERT INTO `vn`.`printer` (`id`, `name`, `path`, `isLabeler`, `sectorFk`, `ipAddress`)
|
||||
VALUES
|
||||
(1, 'printer1', 'path1', 0, 1 , NULL),
|
||||
|
@ -295,7 +299,8 @@ INSERT INTO `vn`.`payMethod`(`id`,`code`, `name`, `graceDays`, `outstandingDebt
|
|||
INSERT INTO `vn`.`payDem`(`id`, `payDem`)
|
||||
VALUES
|
||||
(1, 10),
|
||||
(2, 20);
|
||||
(2, 20),
|
||||
(7, 0);
|
||||
|
||||
INSERT INTO `vn`.`autonomy`(`id`, `name`, `countryFk`)
|
||||
VALUES
|
||||
|
|
|
@ -524,7 +524,7 @@ export default {
|
|||
},
|
||||
itemLog: {
|
||||
anyLineCreated: 'vn-item-log > vn-log vn-tbody > vn-tr',
|
||||
fifthLineCreatedProperty: 'vn-item-log > vn-log vn-tbody > vn-tr:nth-child(5) table tr:nth-child(4) td.after',
|
||||
fifthLineCreatedProperty: 'vn-item-log > vn-log vn-tbody > vn-tr:nth-child(5) table tr:nth-child(5) td.after',
|
||||
},
|
||||
ticketSummary: {
|
||||
header: 'vn-ticket-summary > vn-card > h5',
|
||||
|
@ -1040,7 +1040,6 @@ export default {
|
|||
boss: 'vn-worker-create vn-autocomplete[ng-model="$ctrl.worker.bossFk"]',
|
||||
role: 'vn-worker-create vn-autocomplete[ng-model="$ctrl.worker.roleFk"]',
|
||||
iban: 'vn-worker-create vn-textfield[ng-model="$ctrl.worker.iban"]',
|
||||
switft: 'vn-worker-create vn-autocomplete[ng-model="$ctrl.worker.bankEntityFk"]',
|
||||
createButton: 'vn-worker-create vn-submit[label="Create"]',
|
||||
},
|
||||
workerPda: {
|
||||
|
|
|
@ -27,7 +27,7 @@ describe('Worker time control path', () => {
|
|||
date.setMonth(date.getMonth() + 1);
|
||||
let month = date.toLocaleString('default', {month: 'long'});
|
||||
|
||||
await page.click(selectors.workerTimeControl.nextMonthButton);
|
||||
await page.waitToClick(selectors.workerTimeControl.nextMonthButton);
|
||||
let result = await page.getProperty(selectors.workerTimeControl.monthName, 'innerText');
|
||||
|
||||
expect(result).toContain(month);
|
||||
|
@ -36,7 +36,7 @@ describe('Worker time control path', () => {
|
|||
date.setDate(1);
|
||||
month = date.toLocaleString('default', {month: 'long'});
|
||||
|
||||
await page.click(selectors.workerTimeControl.previousMonthButton);
|
||||
await page.waitToClick(selectors.workerTimeControl.previousMonthButton);
|
||||
result = await page.getProperty(selectors.workerTimeControl.monthName, 'innerText');
|
||||
|
||||
expect(result).toContain(month);
|
||||
|
@ -49,7 +49,7 @@ describe('Worker time control path', () => {
|
|||
|
||||
await page.loginAndModule('salesBoss', 'worker');
|
||||
await page.goto(`http://localhost:5000/#!/worker/${hankPymId}/time-control?timestamp=${timestamp}`);
|
||||
await page.click(selectors.workerTimeControl.secondWeekDay);
|
||||
await page.waitToClick(selectors.workerTimeControl.secondWeekDay);
|
||||
|
||||
result = await page.getProperty(selectors.workerTimeControl.monthName, 'innerText');
|
||||
|
||||
|
|
|
@ -26,7 +26,6 @@ describe('Worker create path', () => {
|
|||
await page.write(selectors.workerCreate.street, 'S/ Doomstadt');
|
||||
await page.write(selectors.workerCreate.email, 'doctorDoom@marvel.com');
|
||||
await page.write(selectors.workerCreate.iban, 'ES9121000418450200051332');
|
||||
await page.autocompleteSearch(selectors.workerCreate.switft, 'BBKKESMMMMM');
|
||||
|
||||
// should check for autocompleted worker code and worker user name
|
||||
const workerCode = await page
|
||||
|
|
|
@ -54,7 +54,7 @@ describe('Ticket Future path', () => {
|
|||
it('should search with the origin IPT', async() => {
|
||||
await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton);
|
||||
|
||||
await page.autocompleteSearch(selectors.ticketFuture.ipt, 'Horizontal');
|
||||
await page.autocompleteSearch(selectors.ticketFuture.ipt, 'H');
|
||||
await page.waitToClick(selectors.ticketFuture.submit);
|
||||
|
||||
expect(httpRequest).toContain('ipt=H');
|
||||
|
@ -65,7 +65,7 @@ describe('Ticket Future path', () => {
|
|||
|
||||
await page.clearInput(selectors.ticketFuture.ipt);
|
||||
|
||||
await page.autocompleteSearch(selectors.ticketFuture.futureIpt, 'Horizontal');
|
||||
await page.autocompleteSearch(selectors.ticketFuture.futureIpt, 'H');
|
||||
await page.waitToClick(selectors.ticketFuture.submit);
|
||||
|
||||
expect(httpRequest).toContain('futureIpt=H');
|
||||
|
@ -108,7 +108,7 @@ describe('Ticket Future path', () => {
|
|||
|
||||
it('should search in smart-table with an IPT Destination', async() => {
|
||||
await page.waitToClick(selectors.ticketFuture.tableButtonSearch);
|
||||
await page.autocompleteSearch(selectors.ticketFuture.tableFutureIpt, 'Horizontal');
|
||||
await page.autocompleteSearch(selectors.ticketFuture.tableFutureIpt, 'H');
|
||||
|
||||
expect(httpRequest).toContain('futureIpt');
|
||||
await page.waitToClick(selectors.ticketFuture.tableButtonSearch);
|
||||
|
|
|
@ -54,7 +54,7 @@ describe('Ticket Advance path', () => {
|
|||
|
||||
it('should search with the origin IPT', async() => {
|
||||
await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton);
|
||||
await page.autocompleteSearch(selectors.ticketAdvance.futureIpt, 'Horizontal');
|
||||
await page.autocompleteSearch(selectors.ticketAdvance.futureIpt, 'H');
|
||||
await page.waitToClick(selectors.ticketAdvance.submit);
|
||||
|
||||
expect(httpRequest).toContain('futureIpt=H');
|
||||
|
@ -66,7 +66,7 @@ describe('Ticket Advance path', () => {
|
|||
|
||||
it('should search with the destination IPT', async() => {
|
||||
await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton);
|
||||
await page.autocompleteSearch(selectors.ticketAdvance.ipt, 'Horizontal');
|
||||
await page.autocompleteSearch(selectors.ticketAdvance.ipt, 'H');
|
||||
await page.waitToClick(selectors.ticketAdvance.submit);
|
||||
|
||||
expect(httpRequest).toContain('ipt=H');
|
||||
|
@ -78,7 +78,7 @@ describe('Ticket Advance path', () => {
|
|||
|
||||
it('should search in smart-table with an IPT Origin', async() => {
|
||||
await page.waitToClick(selectors.ticketAdvance.tableButtonSearch);
|
||||
await page.autocompleteSearch(selectors.ticketAdvance.tableFutureIpt, 'Vertical');
|
||||
await page.autocompleteSearch(selectors.ticketAdvance.tableFutureIpt, 'V');
|
||||
|
||||
expect(httpRequest).toContain('futureIpt');
|
||||
|
||||
|
@ -89,7 +89,7 @@ describe('Ticket Advance path', () => {
|
|||
|
||||
it('should search in smart-table with an IPT Destination', async() => {
|
||||
await page.waitToClick(selectors.ticketAdvance.tableButtonSearch);
|
||||
await page.autocompleteSearch(selectors.ticketAdvance.tableIpt, 'Vertical');
|
||||
await page.autocompleteSearch(selectors.ticketAdvance.tableIpt, 'V');
|
||||
|
||||
expect(httpRequest).toContain('ipt');
|
||||
|
||||
|
|
|
@ -114,12 +114,14 @@ export default class Calendar extends FormInput {
|
|||
let day = date.getDate();
|
||||
let wday = date.getDay();
|
||||
let month = date.getMonth();
|
||||
let year = date.getFullYear();
|
||||
|
||||
const currentDay = Date.vnNew().getDate();
|
||||
const currentMonth = Date.vnNew().getMonth();
|
||||
const currentYear = Date.vnNew().getFullYear();
|
||||
|
||||
let classes = {
|
||||
today: day === currentDay && month === currentMonth,
|
||||
today: day === currentDay && month === currentMonth && year === currentYear,
|
||||
weekend: wday === 6 || wday === 0,
|
||||
previous: month < this.month,
|
||||
current: month == this.month,
|
||||
|
|
|
@ -270,5 +270,6 @@
|
|||
"Warehouse inventory not set": "El almacén inventario no está establecido",
|
||||
"This locker has already been assigned": "Esta taquilla ya ha sido asignada",
|
||||
"Tickets with associated refunds": "No se pueden borrar tickets con abonos asociados. Este ticket está asociado al abono Nº {{id}}",
|
||||
"Not exist this branch": "La rama no existe"
|
||||
"Not exist this branch": "La rama no existe",
|
||||
"This ticket cannot be signed because it has not been boxed": "Este ticket no puede firmarse porque no ha sido encajado"
|
||||
}
|
||||
|
|
|
@ -1,49 +0,0 @@
|
|||
|
||||
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
|
||||
|
||||
module.exports = Self => {
|
||||
Self.remoteMethod('getTransactions', {
|
||||
description: 'Returns last entries',
|
||||
accessType: 'READ',
|
||||
accepts: [{
|
||||
arg: 'filter',
|
||||
type: 'object',
|
||||
description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string',
|
||||
http: {source: 'query'}
|
||||
}],
|
||||
returns: {
|
||||
type: ['object'],
|
||||
root: true
|
||||
},
|
||||
http: {
|
||||
path: `/getTransactions`,
|
||||
verb: 'GET'
|
||||
}
|
||||
});
|
||||
|
||||
Self.getTransactions = async(filter, options) => {
|
||||
const myOptions = {};
|
||||
|
||||
if (typeof options == 'object')
|
||||
Object.assign(myOptions, options);
|
||||
|
||||
const conn = Self.dataSource.connector;
|
||||
const stmt = new ParameterizedSQL(`
|
||||
SELECT
|
||||
t.id,
|
||||
t.clientFk,
|
||||
t.created,
|
||||
t.amount / 100 amount,
|
||||
t.receiptFk IS NOT NULL AS isConfirmed,
|
||||
tt.message responseMessage,
|
||||
te.message errorMessage
|
||||
FROM hedera.tpvTransaction t
|
||||
JOIN hedera.tpvMerchant m ON m.id = t.merchantFk
|
||||
LEFT JOIN hedera.tpvResponse tt ON tt.id = t.response
|
||||
LEFT JOIN hedera.tpvError te ON te.code = errorCode`);
|
||||
|
||||
stmt.merge(conn.makeSuffix(filter, 't'));
|
||||
|
||||
return Self.rawStmt(stmt, myOptions);
|
||||
};
|
||||
};
|
|
@ -1,21 +0,0 @@
|
|||
const models = require('vn-loopback/server/server').models;
|
||||
|
||||
describe('Client getTransations', () => {
|
||||
it('should call getTransations() method to receive a list of Web Payments from Bruce Wayne', async() => {
|
||||
const tx = await models.Client.beginTransaction({});
|
||||
|
||||
try {
|
||||
const options = {transaction: tx};
|
||||
|
||||
const filter = {where: {clientFk: 1101}};
|
||||
const result = await models.Client.getTransactions(filter, options);
|
||||
|
||||
expect(result[1].id).toBeTruthy();
|
||||
|
||||
await tx.rollback();
|
||||
} catch (e) {
|
||||
await tx.rollback();
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
});
|
|
@ -0,0 +1,66 @@
|
|||
const models = require('vn-loopback/server/server').models;
|
||||
|
||||
describe('Client transactions', () => {
|
||||
it('should call transactions() method to receive a list of Web Payments from Bruce Wayne', async() => {
|
||||
const tx = await models.Client.beginTransaction({});
|
||||
|
||||
try {
|
||||
const options = {transaction: tx};
|
||||
|
||||
const ctx = {};
|
||||
const filter = {where: {clientFk: 1101}};
|
||||
const result = await models.Client.transactions(ctx, filter, options);
|
||||
|
||||
expect(result[1].id).toBeTruthy();
|
||||
|
||||
await tx.rollback();
|
||||
} catch (e) {
|
||||
await tx.rollback();
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
|
||||
it('should call transactions() method filtering by orderFk', async() => {
|
||||
const tx = await models.Client.beginTransaction({});
|
||||
|
||||
try {
|
||||
const options = {transaction: tx};
|
||||
|
||||
const ctx = {args: {orderFk: 6}};
|
||||
const filter = {};
|
||||
const result = await models.Client.transactions(ctx, filter, options);
|
||||
|
||||
const firstRow = result[0];
|
||||
|
||||
expect(result.length).toEqual(1);
|
||||
expect(firstRow.id).toEqual(6);
|
||||
|
||||
await tx.rollback();
|
||||
} catch (e) {
|
||||
await tx.rollback();
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
|
||||
it('should call transactions() method filtering by amount', async() => {
|
||||
const tx = await models.Client.beginTransaction({});
|
||||
|
||||
try {
|
||||
const options = {transaction: tx};
|
||||
|
||||
const ctx = {args: {amount: 40}};
|
||||
const filter = {};
|
||||
const result = await models.Client.transactions(ctx, filter, options);
|
||||
|
||||
const randomIndex = Math.floor(Math.random() * result.length);
|
||||
const transaction = result[randomIndex];
|
||||
|
||||
expect(transaction.amount).toEqual(40);
|
||||
|
||||
await tx.rollback();
|
||||
} catch (e) {
|
||||
await tx.rollback();
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
});
|
|
@ -0,0 +1,84 @@
|
|||
|
||||
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
|
||||
const buildFilter = require('vn-loopback/util/filter').buildFilter;
|
||||
const mergeFilters = require('vn-loopback/util/filter').mergeFilters;
|
||||
|
||||
module.exports = Self => {
|
||||
Self.remoteMethodCtx('transactions', {
|
||||
description: 'Returns customer transactions',
|
||||
accessType: 'READ',
|
||||
accepts: [
|
||||
{
|
||||
arg: 'filter',
|
||||
type: 'object',
|
||||
description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string',
|
||||
http: {source: 'query'}
|
||||
},
|
||||
{
|
||||
arg: 'orderFk',
|
||||
type: 'number',
|
||||
http: {source: 'query'}
|
||||
},
|
||||
{
|
||||
arg: 'clientFk',
|
||||
type: 'number',
|
||||
http: {source: 'query'}
|
||||
},
|
||||
{
|
||||
arg: 'amount',
|
||||
type: 'number',
|
||||
http: {source: 'query'}
|
||||
}
|
||||
],
|
||||
returns: {
|
||||
type: ['object'],
|
||||
root: true
|
||||
},
|
||||
http: {
|
||||
path: `/transactions`,
|
||||
verb: 'GET'
|
||||
}
|
||||
});
|
||||
|
||||
Self.transactions = async(ctx, filter, options) => {
|
||||
const args = ctx.args;
|
||||
const myOptions = {};
|
||||
|
||||
if (typeof options == 'object')
|
||||
Object.assign(myOptions, options);
|
||||
|
||||
const where = buildFilter(args, (param, value) => {
|
||||
switch (param) {
|
||||
case 'orderFk':
|
||||
return {'t.id': value};
|
||||
case 'clientFk':
|
||||
return {'t.clientFk': value};
|
||||
case 'amount':
|
||||
return {'t.amount': (value * 100)};
|
||||
}
|
||||
});
|
||||
|
||||
filter = mergeFilters(filter, {where});
|
||||
|
||||
const conn = Self.dataSource.connector;
|
||||
const stmt = new ParameterizedSQL(`
|
||||
SELECT
|
||||
t.id,
|
||||
t.clientFk,
|
||||
c.name AS customerName,
|
||||
t.created,
|
||||
t.amount / 100 amount,
|
||||
t.receiptFk IS NOT NULL AS isConfirmed,
|
||||
tt.message responseMessage,
|
||||
te.message errorMessage
|
||||
FROM hedera.tpvTransaction t
|
||||
JOIN client c ON c.id = t.clientFk
|
||||
JOIN hedera.tpvMerchant m ON m.id = t.merchantFk
|
||||
LEFT JOIN hedera.tpvResponse tt ON tt.id = t.response
|
||||
LEFT JOIN hedera.tpvError te ON te.code = errorCode`);
|
||||
|
||||
stmt.merge(conn.makeSuffix(filter, 't'));
|
||||
|
||||
return Self.rawStmt(stmt, myOptions);
|
||||
};
|
||||
};
|
|
@ -13,7 +13,7 @@ module.exports = Self => {
|
|||
require('../methods/client/getCard')(Self);
|
||||
require('../methods/client/getDebt')(Self);
|
||||
require('../methods/client/getMana')(Self);
|
||||
require('../methods/client/getTransactions')(Self);
|
||||
require('../methods/client/transactions')(Self);
|
||||
require('../methods/client/hasCustomerRole')(Self);
|
||||
require('../methods/client/isValidClient')(Self);
|
||||
require('../methods/client/lastActiveTickets')(Self);
|
||||
|
|
|
@ -1,55 +1,39 @@
|
|||
<vn-crud-model
|
||||
vn-id="model"
|
||||
url="clients/getTransactions"
|
||||
link="{clientFk: $ctrl.$params.id}"
|
||||
limit="20"
|
||||
data="transactions"
|
||||
order="created DESC"
|
||||
auto-load="true">
|
||||
<vn-crud-model vn-id="model" url="clients/transactions" link="{clientFk: $ctrl.$params.id}" limit="20"
|
||||
data="transactions" order="created DESC" auto-load="true">
|
||||
</vn-crud-model>
|
||||
<vn-data-viewer
|
||||
model="model"
|
||||
class="vn-w-md">
|
||||
<vn-data-viewer model="model" class="vn-w-md">
|
||||
<vn-card>
|
||||
<vn-table model="model">
|
||||
<vn-thead>
|
||||
<vn-tr>
|
||||
<vn-th shrink>State</vn-th>
|
||||
<vn-th field="id" number>Id</vn-th>
|
||||
<vn-th field="created" expand>Date</vn-th>
|
||||
<vn-th field="amount" number>Amount</vn-th>
|
||||
<vn-th shrink></vn-th>
|
||||
</vn-tr>
|
||||
</vn-thead>
|
||||
<vn-tbody>
|
||||
<vn-tr ng-repeat="transaction in transactions">
|
||||
<vn-td shrink>
|
||||
<vn-icon
|
||||
vn-tooltip="{{::$ctrl.getFormattedMessage(transaction)}}"
|
||||
ng-show="::((transaction.errorMessage || transaction.responseMessage) && !transaction.isConfirmed)"
|
||||
icon="clear">
|
||||
</vn-icon>
|
||||
<vn-icon
|
||||
vn-tooltip="Confirmed"
|
||||
ng-show="::(transaction.isConfirmed)"
|
||||
icon="check">
|
||||
</vn-icon>
|
||||
</vn-td>
|
||||
<vn-td number>{{::transaction.id}}</vn-td>
|
||||
<vn-td>{{::transaction.created | date:'dd/MM/yyyy HH:mm'}}</vn-td>
|
||||
<vn-td number>{{::transaction.amount | currency: 'EUR':2}}</vn-td>
|
||||
<vn-td shrink>
|
||||
<vn-icon-button
|
||||
icon="done_all"
|
||||
vn-acl="administrative"
|
||||
vn-acl-action="remove"
|
||||
translate-attr="{title: 'Confirm transaction'}"
|
||||
ng-show="::!transaction.isConfirmed"
|
||||
ng-click="$ctrl.confirm(transaction)">
|
||||
</vn-icon-button>
|
||||
</vn-td>
|
||||
</vn-tr>
|
||||
</vn-tbody>
|
||||
</vn-table>
|
||||
<vn-table model="model">
|
||||
<vn-thead>
|
||||
<vn-tr>
|
||||
<vn-th shrink>State</vn-th>
|
||||
<vn-th field="id" number>Id</vn-th>
|
||||
<vn-th field="created" expand>Date</vn-th>
|
||||
<vn-th field="amount" number>Amount</vn-th>
|
||||
<vn-th shrink></vn-th>
|
||||
</vn-tr>
|
||||
</vn-thead>
|
||||
<vn-tbody>
|
||||
<vn-tr ng-repeat="transaction in transactions">
|
||||
<vn-td shrink>
|
||||
<vn-icon vn-tooltip="{{::$ctrl.getFormattedMessage(transaction)}}"
|
||||
ng-show="::((transaction.errorMessage || transaction.responseMessage) && !transaction.isConfirmed)"
|
||||
icon="clear">
|
||||
</vn-icon>
|
||||
<vn-icon vn-tooltip="Confirmed" ng-show="::(transaction.isConfirmed)" icon="check">
|
||||
</vn-icon>
|
||||
</vn-td>
|
||||
<vn-td number>{{::transaction.id}}</vn-td>
|
||||
<vn-td>{{::transaction.created | date:'dd/MM/yyyy HH:mm'}}</vn-td>
|
||||
<vn-td number>{{::transaction.amount | currency: 'EUR':2}}</vn-td>
|
||||
<vn-td shrink>
|
||||
<vn-icon-button icon="done_all" vn-acl="administrative" vn-acl-action="remove"
|
||||
translate-attr="{title: 'Confirm transaction'}" ng-show="::!transaction.isConfirmed"
|
||||
ng-click="$ctrl.confirm(transaction)">
|
||||
</vn-icon-button>
|
||||
</vn-td>
|
||||
</vn-tr>
|
||||
</vn-tbody>
|
||||
</vn-table>
|
||||
</vn-card>
|
||||
</vn-data-viewer>
|
|
@ -86,11 +86,11 @@
|
|||
class="expendable">
|
||||
<span
|
||||
vn-tooltip="
|
||||
{{::$ctrl.$t('Cost')}}: {{::entry.buyingValue | currency: 'EUR':2 | dashIfEmpty}}<br>
|
||||
{{::$ctrl.$t('Package')}}: {{::entry.packageValue | currency: 'EUR':2 | dashIfEmpty}}<br>
|
||||
{{::$ctrl.$t('Freight')}}: {{::entry.freightValue | currency: 'EUR':2 | dashIfEmpty}}<br>
|
||||
{{::$ctrl.$t('Comission')}}: {{::entry.comissionValue | currency: 'EUR':2 | dashIfEmpty}}">
|
||||
{{::entry.cost | currency: 'EUR':2 | dashIfEmpty}}
|
||||
{{::$ctrl.$t('Cost')}}: {{::entry.buyingValue | currency: 'EUR':3 | dashIfEmpty}}<br>
|
||||
{{::$ctrl.$t('Package')}}: {{::entry.packageValue | currency: 'EUR':3 | dashIfEmpty}}<br>
|
||||
{{::$ctrl.$t('Freight')}}: {{::entry.freightValue | currency: 'EUR':3 | dashIfEmpty}}<br>
|
||||
{{::$ctrl.$t('Comission')}}: {{::entry.comissionValue | currency: 'EUR':3 | dashIfEmpty}}">
|
||||
{{::entry.cost | currency: 'EUR':3 | dashIfEmpty}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td number>{{::entry.weight | dashIfEmpty}}</vn-td>
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
module.exports = Self => {
|
||||
Self.remoteMethod('newSupplier', {
|
||||
Self.remoteMethodCtx('newSupplier', {
|
||||
description: 'Creates a new supplier and returns it',
|
||||
accessType: 'WRITE',
|
||||
accepts: [{
|
||||
arg: 'params',
|
||||
type: 'object',
|
||||
http: {source: 'body'}
|
||||
arg: 'name',
|
||||
type: 'string'
|
||||
}],
|
||||
returns: {
|
||||
type: 'string',
|
||||
|
@ -17,29 +16,18 @@ module.exports = Self => {
|
|||
}
|
||||
});
|
||||
|
||||
Self.newSupplier = async params => {
|
||||
Self.newSupplier = async(ctx, options) => {
|
||||
const models = Self.app.models;
|
||||
const args = ctx.args;
|
||||
const myOptions = {};
|
||||
|
||||
if (typeof(params) == 'string')
|
||||
params = JSON.parse(params);
|
||||
if (typeof options == 'object')
|
||||
Object.assign(myOptions, options);
|
||||
|
||||
params.nickname = params.name;
|
||||
delete args.ctx;
|
||||
const data = {...args, ...{nickname: args.name}};
|
||||
const supplier = await models.Supplier.create(data, myOptions);
|
||||
|
||||
if (!myOptions.transaction) {
|
||||
tx = await Self.beginTransaction({});
|
||||
myOptions.transaction = tx;
|
||||
}
|
||||
|
||||
try {
|
||||
const supplier = await models.Supplier.create(params, myOptions);
|
||||
|
||||
if (tx) await tx.commit();
|
||||
|
||||
return supplier;
|
||||
} catch (e) {
|
||||
if (tx) await tx.rollback();
|
||||
throw e;
|
||||
}
|
||||
return supplier;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,31 +1,39 @@
|
|||
const app = require('vn-loopback/server/server');
|
||||
const models = require('vn-loopback/server/server').models;
|
||||
const LoopBackContext = require('loopback-context');
|
||||
|
||||
describe('Supplier newSupplier()', () => {
|
||||
const newSupp = {
|
||||
name: 'TestSupplier-1'
|
||||
};
|
||||
const administrativeId = 5;
|
||||
const activeCtx = {
|
||||
accessToken: {userId: administrativeId},
|
||||
http: {
|
||||
req: {
|
||||
headers: {origin: 'http://localhost'}
|
||||
}
|
||||
}
|
||||
};
|
||||
const ctx = {req: activeCtx};
|
||||
|
||||
it('should create a new supplier containing only the name', async() => {
|
||||
pending('https://redmine.verdnatura.es/issues/5203');
|
||||
const activeCtx = {
|
||||
accessToken: {userId: administrativeId},
|
||||
};
|
||||
beforeEach(() => {
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
|
||||
active: activeCtx
|
||||
});
|
||||
});
|
||||
|
||||
let result = await app.models.Supplier.newSupplier(JSON.stringify(newSupp));
|
||||
it('should create a new supplier containing only the name', async() => {
|
||||
const tx = await models.Supplier.beginTransaction({});
|
||||
|
||||
expect(result.name).toEqual('TestSupplier-1');
|
||||
expect(result.id).toEqual(443);
|
||||
try {
|
||||
const options = {transaction: tx};
|
||||
ctx.args = {
|
||||
name: 'newSupplier'
|
||||
};
|
||||
|
||||
const createdSupplier = await app.models.Supplier.findById(result.id);
|
||||
const result = await models.Supplier.newSupplier(ctx, options);
|
||||
|
||||
expect(createdSupplier.id).toEqual(result.id);
|
||||
expect(createdSupplier.name).toEqual(result.name);
|
||||
expect(createdSupplier.payDemFk).toEqual(7);
|
||||
expect(createdSupplier.nickname).toEqual(result.name);
|
||||
expect(result.name).toEqual('newSupplier');
|
||||
} catch (e) {
|
||||
await tx.rollback();
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
<vn-watcher
|
||||
vn-id="watcher"
|
||||
url="suppliers/newSupplier"
|
||||
url="Suppliers/newSupplier"
|
||||
data="$ctrl.supplier"
|
||||
params="$ctrl.supplier"
|
||||
insert-mode="true"
|
||||
form="form">
|
||||
</vn-watcher>
|
||||
|
@ -9,8 +10,8 @@
|
|||
<vn-card class="vn-pa-lg">
|
||||
<vn-horizontal>
|
||||
<vn-textfield
|
||||
label="Supplier name"
|
||||
ng-model="$ctrl.supplier.name"
|
||||
label="Supplier name"
|
||||
ng-model="$ctrl.supplier.name"
|
||||
vn-focus>
|
||||
</vn-textfield>
|
||||
</vn-horizontal>
|
||||
|
|
|
@ -0,0 +1,132 @@
|
|||
const UserError = require('vn-loopback/util/user-error');
|
||||
|
||||
module.exports = Self => {
|
||||
Self.remoteMethodCtx('saveSign', {
|
||||
description: 'Save sign',
|
||||
accessType: 'WRITE',
|
||||
accepts:
|
||||
[
|
||||
{
|
||||
arg: 'tickets',
|
||||
type: ['number'],
|
||||
required: true,
|
||||
description: 'The tickets'
|
||||
},
|
||||
{
|
||||
arg: 'location',
|
||||
type: 'object',
|
||||
description: 'The employee location the moment the sign is saved'
|
||||
},
|
||||
{
|
||||
arg: 'signedTime',
|
||||
type: 'date',
|
||||
description: 'The signed time'
|
||||
}
|
||||
],
|
||||
http: {
|
||||
path: `/saveSign`,
|
||||
verb: 'POST'
|
||||
}
|
||||
});
|
||||
|
||||
Self.saveSign = async(ctx, options) => {
|
||||
const args = Object.assign({}, ctx.args);
|
||||
const models = Self.app.models;
|
||||
const myOptions = {};
|
||||
let tx;
|
||||
|
||||
if (typeof options == 'object')
|
||||
Object.assign(myOptions, options);
|
||||
|
||||
if (!myOptions.transaction) {
|
||||
tx = await Self.beginTransaction({});
|
||||
myOptions.transaction = tx;
|
||||
}
|
||||
|
||||
async function setLocation(ticketId) {
|
||||
await models.Delivery.create({
|
||||
ticketFk: ticketId,
|
||||
longitude: args.location.Longitude,
|
||||
latitude: args.location.Latitude,
|
||||
dated: args.signedTime || new Date()
|
||||
}, myOptions);
|
||||
}
|
||||
|
||||
async function gestDocExists(ticketId) {
|
||||
const ticketDms = await models.TicketDms.findOne({
|
||||
where: {ticketFk: ticketId},
|
||||
fields: ['dmsFk']
|
||||
}, myOptions);
|
||||
|
||||
if (!ticketDms) return false;
|
||||
|
||||
const ticket = await models.Ticket.findById(ticketId, {fields: ['isSigned']}, myOptions);
|
||||
if (ticket.isSigned == true)
|
||||
return true;
|
||||
else
|
||||
await models.Dms.destroyAll({where: {reference: ticketId}}, myOptions);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
async function createGestDoc(id) {
|
||||
const ticket = await models.Ticket.findById(id,
|
||||
{include: [
|
||||
{
|
||||
relation: 'warehouse',
|
||||
scope: {
|
||||
fields: ['id']
|
||||
}
|
||||
}, {
|
||||
relation: 'client',
|
||||
scope: {
|
||||
fields: ['name']
|
||||
}
|
||||
}, {
|
||||
relation: 'route',
|
||||
scope: {
|
||||
fields: ['id']
|
||||
}
|
||||
}
|
||||
]
|
||||
}, myOptions);
|
||||
const dmsType = await models.DmsType.findOne({where: {code: 'Ticket'}, fields: ['id']}, myOptions);
|
||||
const ctxUploadFile = Object.assign({}, ctx);
|
||||
ctxUploadFile.args = {
|
||||
warehouseId: ticket.warehouseFk,
|
||||
companyId: ticket.companyFk,
|
||||
dmsTypeId: dmsType.id,
|
||||
reference: id,
|
||||
description: `Ticket ${id} Cliente ${ticket.client().name} Ruta ${ticket.route().id}`,
|
||||
hasFile: true
|
||||
};
|
||||
await models.Ticket.uploadFile(ctxUploadFile, id, myOptions);
|
||||
}
|
||||
|
||||
try {
|
||||
for (let i = 0; i < args.tickets.length; i++) {
|
||||
const ticketState = await models.TicketState.findOne(
|
||||
{where: {ticketFk: args.tickets[i]},
|
||||
fields: ['alertLevel']
|
||||
}, myOptions);
|
||||
|
||||
const packedAlertLevel = await models.AlertLevel.findOne({where: {code: 'PACKED'},
|
||||
fields: ['id']
|
||||
}, myOptions);
|
||||
|
||||
if (ticketState.alertLevel < packedAlertLevel.id)
|
||||
throw new UserError('This ticket cannot be signed because it has not been boxed');
|
||||
else if (!await gestDocExists(args.tickets[i])) {
|
||||
if (args.location) setLocation(args.tickets[i]);
|
||||
await createGestDoc(args.tickets[i]);
|
||||
await Self.rawSql(`CALL vn.ticket_setState(?, ?)`, [args.tickets[i], 'DELIVERED'], myOptions);
|
||||
}
|
||||
}
|
||||
|
||||
if (tx) await tx.commit();
|
||||
} catch (e) {
|
||||
if (tx) await tx.rollback();
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
};
|
|
@ -0,0 +1,32 @@
|
|||
const models = require('vn-loopback/server/server').models;
|
||||
|
||||
describe('Ticket saveSign()', () => {
|
||||
const FormData = require('form-data');
|
||||
const data = new FormData();
|
||||
let ctx = {req: {
|
||||
accessToken: {userId: 9},
|
||||
headers: {
|
||||
...data.getHeaders()
|
||||
}
|
||||
|
||||
}};
|
||||
|
||||
it(`should throw error if the ticket's alert level is lower than 2`, async() => {
|
||||
const tx = await models.TicketDms.beginTransaction({});
|
||||
const ticketWithOkState = 12;
|
||||
let error;
|
||||
try {
|
||||
const options = {transaction: tx};
|
||||
ctx.args = {tickets: [ticketWithOkState]};
|
||||
|
||||
await models.Ticket.saveSign(ctx, options);
|
||||
|
||||
await tx.rollback();
|
||||
} catch (e) {
|
||||
error = e;
|
||||
await tx.rollback();
|
||||
}
|
||||
|
||||
expect(error).toBeDefined();
|
||||
});
|
||||
});
|
|
@ -39,4 +39,5 @@ module.exports = function(Self) {
|
|||
require('../methods/ticket/isRoleAdvanced')(Self);
|
||||
require('../methods/ticket/collectionLabel')(Self);
|
||||
require('../methods/ticket/expeditionPalletLabel')(Self);
|
||||
require('../methods/ticket/saveSign')(Self);
|
||||
};
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
"type": "number"
|
||||
},
|
||||
"updated": {
|
||||
"type": "date",
|
||||
"type": "date",
|
||||
"mysql": {
|
||||
"columnName": "created"
|
||||
}
|
||||
|
@ -44,6 +44,9 @@
|
|||
"isDeleted": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"isSigned": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"priority": {
|
||||
"type": "number"
|
||||
},
|
||||
|
@ -136,4 +139,4 @@
|
|||
"foreignKey": "zoneFk"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -94,6 +94,9 @@
|
|||
},
|
||||
"WorkerTimeControlMail": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"Operator": {
|
||||
"dataSource": "vn"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
{
|
||||
"name": "Operator",
|
||||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "operator"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"workerFk": {
|
||||
"id": true,
|
||||
"type": "number",
|
||||
"required": true
|
||||
},
|
||||
"numberOfWagons": {
|
||||
"type": "number"
|
||||
},
|
||||
"trainFk": {
|
||||
"type": "number",
|
||||
"required": true
|
||||
},
|
||||
"itemPackingTypeFk": {
|
||||
"type": "string",
|
||||
"required": true
|
||||
},
|
||||
"warehouseFk": {
|
||||
"type": "number",
|
||||
"required": true
|
||||
},
|
||||
"sectorFk ": {
|
||||
"type": "number"
|
||||
},
|
||||
"labelerFk ": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"relations": {
|
||||
"sector": {
|
||||
"type": "belongsTo",
|
||||
"model": "Sector",
|
||||
"foreignKey": "sectorFk"
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue