Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix into 4033-route
gitea/salix/pipeline/head This commit looks good
Details
gitea/salix/pipeline/head This commit looks good
Details
This commit is contained in:
commit
68e4f3a8bc
|
@ -8,7 +8,7 @@ module.exports = Self => {
|
|||
},
|
||||
http: {
|
||||
path: `/notifyIssues`,
|
||||
verb: 'GET'
|
||||
verb: 'POST'
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ module.exports = Self => {
|
|||
},
|
||||
http: {
|
||||
path: `/sendQueued`,
|
||||
verb: 'GET'
|
||||
verb: 'POST'
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -2,10 +2,10 @@ const models = require('vn-loopback/server/server').models;
|
|||
|
||||
describe('ticket getCollection()', () => {
|
||||
it('should return a list of collections', async() => {
|
||||
let ctx = {req: {accessToken: {userId: 1106}}};
|
||||
let ctx = {req: {accessToken: {userId: 1107}}};
|
||||
let response = await models.Collection.getCollection(ctx);
|
||||
|
||||
expect(response.length).toBeGreaterThan(0);
|
||||
expect(response[0].collectionFk).toEqual(1);
|
||||
expect(response[0].collectionFk).toEqual(3);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -12,7 +12,7 @@ module.exports = Self => {
|
|||
},
|
||||
http: {
|
||||
path: `/deleteTrashFiles`,
|
||||
verb: 'GET'
|
||||
verb: 'POST'
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -53,8 +53,12 @@ module.exports = Self => {
|
|||
const pathHash = DmsContainer.getHash(dms.id);
|
||||
const dmsContainer = await DmsContainer.container(pathHash);
|
||||
const dstFile = path.join(dmsContainer.client.root, pathHash, dms.file);
|
||||
try {
|
||||
await fs.unlink(dstFile);
|
||||
} catch (err) {
|
||||
continue;
|
||||
}
|
||||
const dstFolder = path.join(dmsContainer.client.root, pathHash);
|
||||
await fs.unlink(dstFile);
|
||||
try {
|
||||
await fs.rmdir(dstFolder);
|
||||
await dms.destroy(myOptions);
|
||||
|
|
|
@ -12,7 +12,7 @@ module.exports = Self => {
|
|||
},
|
||||
http: {
|
||||
path: `/updateData`,
|
||||
verb: 'GET'
|
||||
verb: 'POST'
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -0,0 +1,118 @@
|
|||
const jsdom = require('jsdom');
|
||||
const mysql = require('mysql');
|
||||
|
||||
module.exports = Self => {
|
||||
Self.remoteMethodCtx('closeTicket', {
|
||||
description: 'Close tickets without response from the user',
|
||||
accessType: 'READ',
|
||||
returns: {
|
||||
type: 'Object',
|
||||
root: true
|
||||
},
|
||||
http: {
|
||||
path: `/closeTicket`,
|
||||
verb: 'POST'
|
||||
}
|
||||
});
|
||||
|
||||
Self.closeTicket = async ctx => {
|
||||
const models = Self.app.models;
|
||||
const config = await models.OsTicketConfig.findOne();
|
||||
const ostUri = `${config.host}/login.php`;
|
||||
|
||||
if (!config.user || !config.password || !config.userDb || !config.passwordDb)
|
||||
return false;
|
||||
|
||||
const con = mysql.createConnection({
|
||||
host: `${config.hostDb}`,
|
||||
user: `${config.userDb}`,
|
||||
password: `${config.passwordDb}`,
|
||||
port: `${config.portDb}`
|
||||
});
|
||||
|
||||
const sql = `SELECT ot.ticket_id, ot.number
|
||||
FROM osticket.ost_ticket ot
|
||||
JOIN osticket.ost_ticket_status ots ON ots.id = ot.status_id
|
||||
JOIN osticket.ost_thread ot2 ON ot2.object_id = ot.ticket_id AND ot2.object_type = 'T'
|
||||
JOIN (
|
||||
SELECT ote.thread_id, MAX(ote.created) created, MAX(ote.updated) updated
|
||||
FROM osticket.ost_thread_entry ote
|
||||
WHERE ote.staff_id != 0 AND ote.type = 'R'
|
||||
GROUP BY ote.thread_id
|
||||
) sub ON sub.thread_id = ot2.id
|
||||
WHERE ot.isanswered = 1
|
||||
AND ots.state = '${config.oldStatus}'
|
||||
AND IF(sub.updated > sub.created, sub.updated, sub.created) < DATE_SUB(CURDATE(), INTERVAL ${config.day} DAY)`;
|
||||
|
||||
let ticketsId = [];
|
||||
con.connect(err => {
|
||||
if (err) throw err;
|
||||
con.query(sql, (err, results) => {
|
||||
if (err) throw err;
|
||||
for (const result of results)
|
||||
ticketsId.push(result.ticket_id);
|
||||
});
|
||||
});
|
||||
|
||||
await requestToken();
|
||||
|
||||
async function requestToken() {
|
||||
const response = await fetch(ostUri);
|
||||
|
||||
const result = response.headers.get('set-cookie');
|
||||
const [firtHeader] = result.split(' ');
|
||||
const firtCookie = firtHeader.substring(0, firtHeader.length - 1);
|
||||
const body = await response.text();
|
||||
const dom = new jsdom.JSDOM(body);
|
||||
const token = dom.window.document.querySelector('[name="__CSRFToken__"]').value;
|
||||
|
||||
await login(token, firtCookie);
|
||||
}
|
||||
|
||||
async function login(token, firtCookie) {
|
||||
const data = {
|
||||
__CSRFToken__: token,
|
||||
do: 'scplogin',
|
||||
userid: config.user,
|
||||
passwd: config.password,
|
||||
ajax: 1
|
||||
};
|
||||
const params = {
|
||||
method: 'POST',
|
||||
body: new URLSearchParams(data),
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
|
||||
'Cookie': firtCookie
|
||||
}
|
||||
};
|
||||
const response = await fetch(ostUri, params);
|
||||
const result = response.headers.get('set-cookie');
|
||||
const [firtHeader] = result.split(' ');
|
||||
const secondCookie = firtHeader.substring(0, firtHeader.length - 1);
|
||||
|
||||
await close(token, secondCookie);
|
||||
}
|
||||
|
||||
async function close(token, secondCookie) {
|
||||
for (const ticketId of ticketsId) {
|
||||
const ostUri = `${config.host}/ajax.php/tickets/${ticketId}/status`;
|
||||
const data = {
|
||||
status_id: config.newStatusId,
|
||||
comments: config.comment,
|
||||
undefined: config.action
|
||||
};
|
||||
const params = {
|
||||
method: 'POST',
|
||||
body: new URLSearchParams(data),
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
|
||||
'X-CSRFToken': token,
|
||||
'Cookie': secondCookie
|
||||
}
|
||||
};
|
||||
|
||||
return fetch(ostUri, params);
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
|
@ -116,6 +116,9 @@
|
|||
"OsTicket": {
|
||||
"dataSource": "osticket"
|
||||
},
|
||||
"OsTicketConfig": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"Edi": {
|
||||
"dataSource": "vn"
|
||||
}
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
{
|
||||
"name": "OsTicketConfig",
|
||||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "osTicketConfig"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "number",
|
||||
"id": true,
|
||||
"description": "Identifier"
|
||||
},
|
||||
"host": {
|
||||
"type": "string"
|
||||
},
|
||||
"user": {
|
||||
"type": "string"
|
||||
},
|
||||
"password": {
|
||||
"type": "string"
|
||||
},
|
||||
"oldStatus": {
|
||||
"type": "string"
|
||||
},
|
||||
"newStatusId": {
|
||||
"type": "number"
|
||||
},
|
||||
"action": {
|
||||
"type": "string"
|
||||
},
|
||||
"day": {
|
||||
"type": "number"
|
||||
},
|
||||
"comment": {
|
||||
"type": "string"
|
||||
},
|
||||
"hostDb": {
|
||||
"type": "string"
|
||||
},
|
||||
"userDb": {
|
||||
"type": "string"
|
||||
},
|
||||
"passwordDb": {
|
||||
"type": "string"
|
||||
},
|
||||
"portDb": {
|
||||
"type": "number"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
module.exports = Self => {
|
||||
require('../methods/osticket/closeTicket')(Self);
|
||||
};
|
|
@ -0,0 +1,3 @@
|
|||
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
|
||||
VALUES
|
||||
('OsTicket', '*', '*', 'ALLOW', 'ROLE', 'employee');
|
|
@ -0,0 +1,3 @@
|
|||
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
|
||||
VALUES
|
||||
('OsTicketConfig', '*', '*', 'ALLOW', 'ROLE', 'it');
|
|
@ -0,0 +1,20 @@
|
|||
CREATE TABLE `vn`.`osTicketConfig` (
|
||||
`id` int(11) NOT NULL,
|
||||
`host` varchar(100) COLLATE utf8mb3_unicode_ci DEFAULT NULL,
|
||||
`user` varchar(100) COLLATE utf8mb3_unicode_ci DEFAULT NULL,
|
||||
`password` varchar(100) COLLATE utf8mb3_unicode_ci DEFAULT NULL,
|
||||
`oldStatus` varchar(100) COLLATE utf8mb3_unicode_ci DEFAULT NULL,
|
||||
`newStatusId` int(11) DEFAULT NULL,
|
||||
`action` varchar(100) COLLATE utf8mb3_unicode_ci DEFAULT NULL,
|
||||
`day` int(11) DEFAULT NULL,
|
||||
`comment` varchar(100) COLLATE utf8mb3_unicode_ci DEFAULT NULL,
|
||||
`hostDb` varchar(100) COLLATE utf8mb3_unicode_ci DEFAULT NULL,
|
||||
`userDb` varchar(100) COLLATE utf8mb3_unicode_ci DEFAULT NULL,
|
||||
`passwordDb` varchar(100) COLLATE utf8mb3_unicode_ci DEFAULT NULL,
|
||||
`portDb` int(11) DEFAULT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
|
||||
|
||||
INSERT INTO `vn`.`osTicketConfig`(`id`, `host`, `user`, `password`, `oldStatus`, `newStatusId`, `action`, `day`, `comment`, `hostDb`, `userDb`, `passwordDb`, `portDb`)
|
||||
VALUES
|
||||
(0, 'https://cau.verdnatura.es/scp', NULL, NULL, 'open', 3, 'Cerrar', 60, 'Este CAU se ha cerrado automáticamente', NULL, NULL, NULL, NULL);
|
|
@ -0,0 +1,4 @@
|
|||
INSERT INTO `salix`.`ACL` (model,property,accessType,permission,principalType,principalId)
|
||||
VALUES ('Sector','*','READ','ALLOW','ROLE','employee');
|
||||
INSERT INTO `salix`.`ACL` (model,property,accessType,permission,principalType,principalId)
|
||||
VALUES ('Sector','*','WRITE','ALLOW','ROLE','employee');
|
File diff suppressed because one or more lines are too long
|
@ -583,7 +583,6 @@ INSERT INTO `vn`.`expence`(`id`, `name`, `isWithheld`)
|
|||
(7001000000, 'Mercaderia', 0),
|
||||
(7050000000, 'Prestacion de servicios', 1);
|
||||
|
||||
|
||||
INSERT INTO `vn`.`invoiceOutExpence`(`id`, `invoiceOutFk`, `amount`, `expenceFk`, `created`)
|
||||
VALUES
|
||||
(1, 1, 813.06, 2000000000, util.VN_CURDATE()),
|
||||
|
@ -862,25 +861,25 @@ INSERT INTO `vn`.`itemFamily`(`code`, `description`)
|
|||
('VT', 'Sales');
|
||||
|
||||
INSERT INTO `vn`.`item`(`id`, `typeFk`, `size`, `inkFk`, `stems`, `originFk`, `description`, `producerFk`, `intrastatFk`, `expenceFk`,
|
||||
`comment`, `relevancy`, `image`, `subName`, `minPrice`, `stars`, `family`, `isFloramondo`, `genericFk`, `itemPackingTypeFk`, `hasMinPrice`, `packingShelve`)
|
||||
`comment`, `relevancy`, `image`, `subName`, `minPrice`, `stars`, `family`, `isFloramondo`, `genericFk`, `itemPackingTypeFk`, `hasMinPrice`, `packingShelve`, `weightByPiece`)
|
||||
VALUES
|
||||
(1, 2, 70, 'YEL', 1, 1, NULL, 1, 06021010, 2000000000, NULL, 0, '1', NULL, 0, 1, 'VT', 0, NULL, 'V', 0, 15),
|
||||
(2, 2, 70, 'BLU', 1, 2, NULL, 1, 06021010, 2000000000, NULL, 0, '2', NULL, 0, 2, 'VT', 0, NULL, 'H', 0, 10),
|
||||
(3, 1, 60, 'YEL', 1, 3, NULL, 1, 05080000, 4751000000, NULL, 0, '3', NULL, 0, 5, 'VT', 0, NULL, NULL, 0, 5),
|
||||
(4, 1, 60, 'YEL', 1, 1, 'Increases block', 1, 05080000, 4751000000, NULL, 0, '4', NULL, 0, 3, 'VT', 0, NULL, NULL, 0, NULL),
|
||||
(5, 3, 30, 'RED', 1, 2, NULL, 2, 06021010, 4751000000, NULL, 0, '5', NULL, 0, 3, 'VT', 0, NULL, NULL, 0, NULL),
|
||||
(6, 5, 30, 'RED', 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '6', NULL, 0, 4, 'VT', 0, NULL, NULL, 0, NULL),
|
||||
(7, 5, 90, 'BLU', 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '7', NULL, 0, 4, 'VT', 0, NULL, NULL, 0, NULL),
|
||||
(8, 2, 70, 'YEL', 1, 1, NULL, 1, 06021010, 2000000000, NULL, 0, '8', NULL, 0, 5, 'VT', 0, NULL, NULL, 0, NULL),
|
||||
(9, 2, 70, 'BLU', 1, 2, NULL, 1, 06021010, 2000000000, NULL, 0, '9', NULL, 0, 4, 'VT', 1, NULL, NULL, 0, NULL),
|
||||
(10, 1, 60, 'YEL', 1, 3, NULL, 1, 05080000, 4751000000, NULL, 0, '10', NULL, 0, 4, 'VT', 0, NULL, NULL, 0, NULL),
|
||||
(11, 1, 60, 'YEL', 1, 1, NULL, 1, 05080000, 4751000000, NULL, 0, '11', NULL, 0, 4, 'VT', 0, NULL, NULL, 0, NULL),
|
||||
(12, 3, 30, 'RED', 1, 2, NULL, 2, 06021010, 4751000000, NULL, 0, '12', NULL, 0, 3, 'VT', 0, NULL, NULL, 0, NULL),
|
||||
(13, 5, 30, 'RED', 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '13', NULL, 1, 2, 'VT', 1, NULL, NULL, 1, NULL),
|
||||
(14, 5, 90, 'BLU', 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 4, 'VT', 1, NULL, NULL, 0, NULL),
|
||||
(15, 4, NULL, NULL, NULL, 1, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 0, 'EMB', 0, NULL, NULL, 0, NULL),
|
||||
(16, 6, NULL, NULL, NULL, 1, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 0, 'EMB', 0, NULL, NULL, 0, NULL),
|
||||
(71, 6, NULL, NULL, NULL, 1, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 0, 'VT', 0, NULL, NULL, 0, NULL);
|
||||
(1, 2, 70, 'YEL', 1, 1, NULL, 1, 06021010, 2000000000, NULL, 0, '1', NULL, 0, 1, 'VT', 0, NULL, 'V', 0, 15,3),
|
||||
(2, 2, 70, 'BLU', 1, 2, NULL, 1, 06021010, 2000000000, NULL, 0, '2', NULL, 0, 2, 'VT', 0, NULL, 'H', 0, 10,2),
|
||||
(3, 1, 60, 'YEL', 1, 3, NULL, 1, 05080000, 4751000000, NULL, 0, '3', NULL, 0, 5, 'VT', 0, NULL, NULL, 0, 5,5),
|
||||
(4, 1, 60, 'YEL', 1, 1, 'Increases block', 1, 05080000, 4751000000, NULL, 0, '4', NULL, 0, 3, 'VT', 0, NULL, NULL, 0, NULL,NULL),
|
||||
(5, 3, 30, 'RED', 1, 2, NULL, 2, 06021010, 4751000000, NULL, 0, '5', NULL, 0, 3, 'VT', 0, NULL, NULL, 0, NULL,NULL),
|
||||
(6, 5, 30, 'RED', 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '6', NULL, 0, 4, 'VT', 0, NULL, NULL, 0, NULL,NULL),
|
||||
(7, 5, 90, 'BLU', 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '7', NULL, 0, 4, 'VT', 0, NULL, NULL, 0, NULL,NULL),
|
||||
(8, 2, 70, 'YEL', 1, 1, NULL, 1, 06021010, 2000000000, NULL, 0, '8', NULL, 0, 5, 'VT', 0, NULL, NULL, 0, NULL,NULL),
|
||||
(9, 2, 70, 'BLU', 1, 2, NULL, 1, 06021010, 2000000000, NULL, 0, '9', NULL, 0, 4, 'VT', 1, NULL, NULL, 0, NULL,NULL),
|
||||
(10, 1, 60, 'YEL', 1, 3, NULL, 1, 05080000, 4751000000, NULL, 0, '10', NULL, 0, 4, 'VT', 0, NULL, NULL, 0, NULL,NULL),
|
||||
(11, 1, 60, 'YEL', 1, 1, NULL, 1, 05080000, 4751000000, NULL, 0, '11', NULL, 0, 4, 'VT', 0, NULL, NULL, 0, NULL,NULL),
|
||||
(12, 3, 30, 'RED', 1, 2, NULL, 2, 06021010, 4751000000, NULL, 0, '12', NULL, 0, 3, 'VT', 0, NULL, NULL, 0, NULL,NULL),
|
||||
(13, 5, 30, 'RED', 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '13', NULL, 1, 2, 'VT', 1, NULL, NULL, 1, NULL,NULL),
|
||||
(14, 5, 90, 'BLU', 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 4, 'VT', 1, NULL, NULL, 0, NULL,NULL),
|
||||
(15, 4, NULL, NULL, NULL, 1, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 0, 'EMB', 0, NULL, NULL, 0, NULL,NULL),
|
||||
(16, 6, NULL, NULL, NULL, 1, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 0, 'EMB', 0, NULL, NULL, 0, NULL,NULL),
|
||||
(71, 6, NULL, NULL, NULL, 1, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 0, 'VT', 0, NULL, NULL, 0, NULL,NULL);
|
||||
|
||||
-- Update the taxClass after insert of the items
|
||||
UPDATE `vn`.`itemTaxCountry` SET `taxClassFk` = 2
|
||||
|
@ -1877,59 +1876,47 @@ INSERT INTO `pbx`.`sip`(`user_id`, `extension`)
|
|||
(5, 1102),
|
||||
(9, 1201);
|
||||
|
||||
INSERT INTO `postgresql`.`profile`(`profile_id`, `workerFk`, `profile_type_id`)
|
||||
SELECT w.id, w.id, 1
|
||||
FROM `vn`.`worker` `w`;
|
||||
DROP TEMPORARY TABLE IF EXISTS tmp.worker;
|
||||
CREATE TEMPORARY TABLE tmp.worker
|
||||
(PRIMARY KEY (id))
|
||||
ENGINE = MEMORY
|
||||
SELECT w.id, w.id as `workerFk`, 'VNL', CONCAT(YEAR(DATE_ADD(CURDATE(), INTERVAL -1 YEAR)), '-12-25'), CONCAT(YEAR(DATE_ADD(CURDATE(), INTERVAL +1 YEAR)), '-12-25'), CONCAT('E-46-', RPAD(CONCAT(w.id, 9), 8, w.id)), NULL as `notes`, NULL as `departmentFk`, 23, 1 as `workerBusinessProfessionalCategoryFk`, 1 as `calendarTypeFk`, 1 as `isHourlyLabor`, 1 as `workerBusinessAgreementFk`, 1 as `workcenterFk`
|
||||
FROM `vn`.`worker` `w`;
|
||||
|
||||
INSERT INTO `postgresql`.`business`(`business_id`, `client_id`, `companyCodeFk`, `date_start`, `date_end`, `workerBusiness`, `reasonEndFk`)
|
||||
SELECT p.profile_id, p.profile_id, 'VNL', CONCAT(YEAR(DATE_ADD(CURDATE(), INTERVAL -1 YEAR)), '-12-25'), CONCAT(YEAR(DATE_ADD(CURDATE(), INTERVAL +1 YEAR)), '-01-25'), CONCAT('E-46-',RPAD(CONCAT(p.profile_id,9),8,p.profile_id)), NULL
|
||||
FROM `postgresql`.`profile` `p`;
|
||||
INSERT INTO `vn`.`business`(`id`, `workerFk`, `companyCodeFk`, `started`, `ended`, `workerBusiness`, `reasonEndFk`, `notes`, `departmentFk`, `workerBusinessProfessionalCategoryFk`, `calendarTypeFk`, `isHourlyLabor`, `workerBusinessAgreementFk`, `workcenterFk`)
|
||||
SELECT * FROM tmp.worker;
|
||||
|
||||
INSERT INTO `postgresql`.`business_labour`(`business_id`, `notes`, `department_id`, `professional_category_id`, `incentivo`, `calendar_labour_type_id`, `porhoras`, `labour_agreement_id`, `workcenter_id`)
|
||||
SELECT b.business_id, NULL, 23, 1, 0, 1, 1, 1, 1
|
||||
FROM `postgresql`.`business` `b`;
|
||||
DROP TEMPORARY TABLE IF EXISTS tmp.worker;
|
||||
CREATE TEMPORARY TABLE tmp.worker
|
||||
(PRIMARY KEY (id))
|
||||
ENGINE = MEMORY
|
||||
SELECT '1111' as 'id', w.id as `workerFk`, 'VNL', CONCAT(YEAR(DATE_ADD(CURDATE(), INTERVAL -2 YEAR)), '-12-25'), CONCAT(YEAR(DATE_ADD(CURDATE(), INTERVAL -1 YEAR)), '-12-24'), CONCAT('E-46-', RPAD(CONCAT(w.id, 9), 8, w.id)), NULL as `notes`, NULL as `departmentFk`, 23, 1 as `workerBusinessProfessionalCategoryFk`, 1 as `calendarTypeFk`, 1 as `isHourlyLabor`, 1 as `workerBusinessAgreementFk`, 1 as `workcenterFk`
|
||||
FROM `vn`.`worker` `w`
|
||||
WHERE `w`.`id` = 1109;
|
||||
|
||||
INSERT INTO `postgresql`.`business` (`client_id`, `companyCodeFk`, `date_start`, `date_end`, `workerBusiness`, `reasonEndFk`)
|
||||
SELECT p.profile_id, 'VNL', CONCAT(YEAR(DATE_ADD(CURDATE(), INTERVAL -2 YEAR)), '-12-25'), CONCAT(YEAR(DATE_ADD(CURDATE(), INTERVAL -1 YEAR)), '-12-24'), CONCAT('E-46-',RPAD(CONCAT(p.profile_id,9),8,p.profile_id)), NULL
|
||||
FROM `postgresql`.`profile` `p`
|
||||
WHERE `p`.`profile_id` = 1109;
|
||||
INSERT INTO `vn`.`business` (`id`, `workerFk`, `companyCodeFk`, `started`, `ended`, `workerBusiness`, `reasonEndFk`, `notes`, `departmentFk`, `workerBusinessProfessionalCategoryFk`, `calendarTypeFk`, `isHourlyLabor`, `workerBusinessAgreementFk`, `workcenterFk`)
|
||||
SELECT * FROM tmp.worker;
|
||||
|
||||
UPDATE `postgresql`.`business`
|
||||
DROP TEMPORARY TABLE IF EXISTS tmp.worker;
|
||||
|
||||
UPDATE `vn`.`business`
|
||||
SET `payedHolidays`= 8
|
||||
WHERE `business_id`= 1106;
|
||||
WHERE `id`= 1106;
|
||||
|
||||
INSERT INTO `postgresql`.`business_labour` (`business_id`, `notes`, `department_id`, `professional_category_id`, `incentivo`, `calendar_labour_type_id`, `porhoras`, `labour_agreement_id`, `workcenter_id`)
|
||||
VALUES
|
||||
(1111, NULL, 23, 1, 0.0, 1, 1, 1, 1);
|
||||
UPDATE `vn`.`business` b
|
||||
SET b.`workerBusinessProfessionalCategoryFk` = 31
|
||||
WHERE b.`workerFk` = 1110;
|
||||
|
||||
UPDATE `postgresql`.`business_labour` bl
|
||||
JOIN `postgresql`.`business` b ON b.business_id = bl.business_id
|
||||
JOIN `postgresql`.`profile` pr ON pr.profile_id = b.client_id
|
||||
SET bl.`professional_category_id` = 31
|
||||
WHERE pr.`workerFk` = 1110;
|
||||
|
||||
UPDATE `postgresql`.`business_labour` bl
|
||||
SET bl.`department_id` = 43
|
||||
WHERE business_id IN(18, 19);
|
||||
|
||||
INSERT INTO `postgresql`.`media`(`media_id`, `media_type_id`, `value`, `sort`)
|
||||
VALUES
|
||||
(1, 10, 600123321, 0),
|
||||
(2, 10, 700987987, 0);
|
||||
|
||||
INSERT INTO `postgresql`.`profile_media`(`profile_media_id`, `profile_id`, `media_id`)
|
||||
VALUES
|
||||
(1, 1106, 1),
|
||||
(2, 1107, 2);
|
||||
UPDATE `vn`.`business` b
|
||||
SET b.`departmentFk` = 43
|
||||
WHERE b.id IN(18, 19);
|
||||
|
||||
INSERT INTO `vn`.`workCenterHoliday` (`workCenterFk`, `days`, `year`)
|
||||
VALUES
|
||||
('1', '27.5', YEAR(util.VN_CURDATE())),
|
||||
('5', '22', YEAR(util.VN_CURDATE())),
|
||||
('1', '24.5', YEAR(DATE_ADD(util.VN_CURDATE(), INTERVAL -1 YEAR))),
|
||||
('5', '23', YEAR(DATE_ADD(util.VN_CURDATE(), INTERVAL -1 YEAR)));
|
||||
|
||||
ALTER TABLE `postgresql`.`business_labour_payroll` DROP FOREIGN KEY `business_labour_payroll_cod_categoria`;
|
||||
('1', '27.5', YEAR(util.VN_CURDATE())),
|
||||
('5', '22', YEAR(util.VN_CURDATE())),
|
||||
('1', '24.5', YEAR(DATE_ADD(util.VN_CURDATE(), INTERVAL -1 YEAR))),
|
||||
('5', '23', YEAR(DATE_ADD(util.VN_CURDATE(), INTERVAL -1 YEAR)));
|
||||
|
||||
INSERT INTO `vn`.`workerBusinessType` (`id`, `name`, `isFullTime`, `isPermanent`, `hasHolidayEntitlement`)
|
||||
VALUES
|
||||
|
@ -1937,12 +1924,33 @@ INSERT INTO `vn`.`workerBusinessType` (`id`, `name`, `isFullTime`, `isPermanent`
|
|||
(100, 'INDEFINIDO A TIEMPO COMPLETO', 1, 1, 1),
|
||||
(109, 'CONVERSION DE TEMPORAL EN INDEFINIDO T.COMPLETO', 1, 1, 1);
|
||||
|
||||
INSERT INTO `postgresql`.`business_labour_payroll` (`business_id`, `cod_tarifa`, `cod_categoria`, `cod_contrato`, `importepactado`)
|
||||
VALUES
|
||||
(1, 7, 12, 100, 900.50),
|
||||
(1106, 7, 12, 100, 1263.03),
|
||||
(1107, 7, 12, 100, 2000),
|
||||
(1108, 7, 12, 100, 1500);
|
||||
UPDATE `vn`.`business` b
|
||||
SET `rate` = 7,
|
||||
`workerBusinessCategoryFk` = 12,
|
||||
`workerBusinessTypeFk` = 100,
|
||||
`amount` = 900.50
|
||||
WHERE b.id = 1;
|
||||
|
||||
UPDATE `vn`.`business` b
|
||||
SET `rate` = 7,
|
||||
`workerBusinessCategoryFk` = 12,
|
||||
`workerBusinessTypeFk` = 100,
|
||||
`amount` = 1263.03
|
||||
WHERE b.id = 1106;
|
||||
|
||||
UPDATE `vn`.`business` b
|
||||
SET `rate` = 7,
|
||||
`workerBusinessCategoryFk` = 12,
|
||||
`workerBusinessTypeFk` = 100,
|
||||
`amount` = 2000
|
||||
WHERE b.id = 1107;
|
||||
|
||||
UPDATE `vn`.`business` b
|
||||
SET `rate` = 7,
|
||||
`workerBusinessCategoryFk` = 12,
|
||||
`workerBusinessTypeFk` = 100,
|
||||
`amount` = 1500
|
||||
WHERE b.id = 1108;
|
||||
|
||||
INSERT INTO `vn`.`absenceType` (`id`, `name`, `rgb`, `code`, `holidayEntitlementRate`, `discountRate`)
|
||||
VALUES
|
||||
|
@ -1953,7 +1961,7 @@ INSERT INTO `vn`.`absenceType` (`id`, `name`, `rgb`, `code`, `holidayEntitlement
|
|||
(20, 'Furlough', '#97B92F', 'furlough', 1, 1),
|
||||
(21, 'Furlough half day', '#778899', 'halfFurlough', 0.5, 1);
|
||||
|
||||
INSERT INTO `postgresql`.`calendar_employee` (`business_id`, `calendar_state_id`, `date`)
|
||||
INSERT INTO `postgresql`.`calendar_employee` (`businessFk`, `calendar_state_id`, `date`)
|
||||
VALUES
|
||||
(1, 6, IF(MONTH(util.VN_CURDATE()) = 12 AND DAY(util.VN_CURDATE()) > 10, DATE_ADD(util.VN_CURDATE(), INTERVAL -10 DAY), DATE_ADD(util.VN_CURDATE(), INTERVAL 10 DAY))),
|
||||
(1106, 1, IF(MONTH(util.VN_CURDATE()) = 12 AND DAY(util.VN_CURDATE()) > 10, DATE_ADD(util.VN_CURDATE(), INTERVAL -10 DAY), DATE_ADD(util.VN_CURDATE(), INTERVAL 10 DAY))),
|
||||
|
@ -2448,18 +2456,18 @@ INSERT INTO `vn`.`duaInvoiceIn`(`id`, `duaFk`, `invoiceInFk`)
|
|||
|
||||
INSERT INTO `vn`.`invoiceInTax` (`invoiceInFk`, `taxableBase`, `expenceFk`, `foreignValue`, `taxTypeSageFk`, `transactionTypeSageFk`)
|
||||
VALUES
|
||||
(1, 99.99, '2000000000', null, null, null),
|
||||
(2, 999.99, '2000000000', null, null, null),
|
||||
(3, 1000.50, '2000000000', null, null, null),
|
||||
(4, 0.50, '2000000000', null, null, null),
|
||||
(5, 150.50, '2000000000', null, null, null),
|
||||
(1, 252.25, '4751000000', NULL, 7, 61),
|
||||
(2, 223.17, '6210000567', NULL, 8, 20),
|
||||
(3, 95.60, '7001000000', NULL, 8, 35),
|
||||
(4, 446.63, '7001000000', NULL, 6, 61),
|
||||
(5, 64.23, '6210000567', NULL, 8, 20),
|
||||
(6, 29.95, '7001000000', NULL, 7, 20),
|
||||
(7, 58.64, '6210000567', NULL, 8, 20);
|
||||
(1, 99.99, '2000000000', NULL, NULL, NULL),
|
||||
(2, 999.99, '2000000000', NULL, NULL, NULL),
|
||||
(3, 1000.50, '2000000000', NULL, NULL, NULL),
|
||||
(4, 0.50, '2000000000', NULL, NULL, NULL),
|
||||
(5, 150.50, '2000000000', NULL, NULL, NULL),
|
||||
(1, 252.25, '4751000000', NULL, 7, 61),
|
||||
(2, 223.17, '6210000567', NULL, 8, 20),
|
||||
(3, 95.60, '7001000000', NULL, 8, 35),
|
||||
(4, 446.63, '7001000000', NULL, 6, 61),
|
||||
(5, 64.23, '6210000567', NULL, 8, 20),
|
||||
(6, 29.95, '7001000000', NULL, 7, 20),
|
||||
(7, 58.64, '6210000567', NULL, 8, 20);
|
||||
|
||||
INSERT INTO `vn`.`invoiceInIntrastat` (`invoiceInFk`, `net`, `intrastatFk`, `amount`, `stems`, `countryFk`)
|
||||
VALUES
|
||||
|
@ -2635,3 +2643,15 @@ INSERT INTO `vn`.`workerTimeControlConfig` (`id`, `dayBreak`, `dayBreakDriver`,
|
|||
INSERT INTO `vn`.`routeConfig` (`id`, `defaultWorkCenterFk`)
|
||||
VALUES
|
||||
(1, 9);
|
||||
|
||||
INSERT INTO `vn`.`productionConfig` (`isPreviousPreparationRequired`, `ticketPrintedMax`, `ticketTrolleyMax`, `rookieDays`, `notBuyingMonths`, `id`, `isZoneClosedByExpeditionActivated`, `maxNotReadyCollections`, `minTicketsToCloseZone`, `movingTicketDelRoute`, `defaultZone`, `defautlAgencyMode`, `hasUniqueCollectionTime`, `maxCollectionWithoutUser`, `pendingCollectionsOrder`, `pendingCollectionsAge`)
|
||||
VALUES
|
||||
(0, 8, 80, 0, 0, 1, 0, 15, 25, -1, 697, 1328, 0, 1, 8, 6);
|
||||
|
||||
INSERT INTO `vn`.`collection` (`id`, `created`, `workerFk`, `stateFk`, `itemPackingTypeFk`, `saleTotalCount`, `salePickedCount`, `trainFk`, `sectorFk`, `wagons`)
|
||||
VALUES
|
||||
(3, util.VN_NOW(), 1107, 5, NULL, 0, 0, 1, NULL, NULL);
|
||||
|
||||
INSERT INTO `vn`.`ticketCollection` (`ticketFk`, `collectionFk`, `created`, `level`, `wagon`, `smartTagFk`, `usedShelves`, `itemCount`, `liters`)
|
||||
VALUES
|
||||
(9, 3, util.VN_NOW(), NULL, 0, NULL, NULL, NULL, NULL);
|
||||
|
|
16183
db/dump/structure.sql
16183
db/dump/structure.sql
File diff suppressed because it is too large
Load Diff
|
@ -239,7 +239,7 @@ xdescribe('worker workerTimeControl_check()', () => {
|
|||
|
||||
stmts.push('START TRANSACTION');
|
||||
|
||||
stmt = new ParameterizedSQL(`INSERT INTO postgresql.calendar_employee(business_id,calendar_state_id,date)
|
||||
stmt = new ParameterizedSQL(`INSERT INTO postgresql.calendar_employee(businessFk,calendar_state_id,date)
|
||||
VALUES
|
||||
(?,1,CURDATE())`, [
|
||||
workerId
|
||||
|
@ -282,7 +282,7 @@ xdescribe('worker workerTimeControl_check()', () => {
|
|||
|
||||
stmts.push('START TRANSACTION');
|
||||
|
||||
stmt = new ParameterizedSQL(`UPDATE postgresql.business SET date_end=DATE_ADD(CURDATE(), INTERVAL -1 DAY) WHERE business_id=?`, [
|
||||
stmt = new ParameterizedSQL(`UPDATE vn.business SET ended = DATE_ADD(CURDATE(), INTERVAL -1 DAY) WHERE id = ?`, [
|
||||
workerId
|
||||
]);
|
||||
stmts.push(stmt);
|
||||
|
|
|
@ -391,7 +391,7 @@ export default {
|
|||
intrastadCheckbox: '.vn-popover.shown vn-horizontal:nth-child(3) > vn-check[label="Intrastat"]',
|
||||
originCheckbox: '.vn-popover.shown vn-horizontal:nth-child(3) > vn-check[label="Origin"]',
|
||||
buyerCheckbox: '.vn-popover.shown vn-horizontal:nth-child(3) > vn-check[label="Buyer"]',
|
||||
densityCheckbox: '.vn-popover.shown vn-horizontal:nth-child(3) > vn-check[label="Density"]',
|
||||
weightByPieceCheckbox: '.vn-popover.shown vn-horizontal:nth-child(3) > vn-check[label="Weight/Piece"]',
|
||||
saveFieldsButton: '.vn-popover.shown vn-button[label="Save"] > button'
|
||||
},
|
||||
itemFixedPrice: {
|
||||
|
@ -1018,9 +1018,9 @@ export default {
|
|||
save: 'vn-travel-create vn-submit > button'
|
||||
},
|
||||
travelExtraCommunity: {
|
||||
anySearchResult: 'vn-travel-extra-community > vn-data-viewer div > vn-tbody > vn-tr',
|
||||
firstTravelReference: 'vn-travel-extra-community vn-tbody:nth-child(2) vn-td-editable[name="reference"]',
|
||||
firstTravelLockedKg: 'vn-travel-extra-community vn-tbody:nth-child(2) vn-td-editable[name="lockedKg"]',
|
||||
anySearchResult: 'vn-travel-extra-community > vn-card div > tbody > tr[ng-attr-id="{{::travel.id}}"]',
|
||||
firstTravelReference: 'vn-travel-extra-community tbody:nth-child(2) vn-textfield[ng-model="travel.ref"]',
|
||||
firstTravelLockedKg: 'vn-travel-extra-community tbody:nth-child(2) vn-input-number[ng-model="travel.kg"]',
|
||||
removeContinentFilter: 'vn-searchbar > form > vn-textfield > div.container > div.prepend > prepend > div > span:nth-child(3) > vn-icon > i'
|
||||
},
|
||||
travelBasicData: {
|
||||
|
|
|
@ -31,7 +31,7 @@ describe('Item index path', () => {
|
|||
await page.waitToClick(selectors.itemsIndex.intrastadCheckbox);
|
||||
await page.waitToClick(selectors.itemsIndex.originCheckbox);
|
||||
await page.waitToClick(selectors.itemsIndex.buyerCheckbox);
|
||||
await page.waitToClick(selectors.itemsIndex.densityCheckbox);
|
||||
await page.waitToClick(selectors.itemsIndex.weightByPieceCheckbox);
|
||||
await page.waitToClick(selectors.itemsIndex.saveFieldsButton);
|
||||
const message = await page.waitForSnackbar();
|
||||
|
||||
|
@ -64,7 +64,7 @@ describe('Item index path', () => {
|
|||
await page.waitToClick(selectors.itemsIndex.intrastadCheckbox);
|
||||
await page.waitToClick(selectors.itemsIndex.originCheckbox);
|
||||
await page.waitToClick(selectors.itemsIndex.buyerCheckbox);
|
||||
await page.waitToClick(selectors.itemsIndex.densityCheckbox);
|
||||
await page.waitToClick(selectors.itemsIndex.weightByPieceCheckbox);
|
||||
await page.waitToClick(selectors.itemsIndex.saveFieldsButton);
|
||||
const message = await page.waitForSnackbar();
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ describe('InvoiceOut manual invoice path', () => {
|
|||
});
|
||||
|
||||
it('should create an invoice from a ticket', async() => {
|
||||
await page.autocompleteSearch(selectors.invoiceOutIndex.manualInvoiceTicket, '7');
|
||||
await page.autocompleteSearch(selectors.invoiceOutIndex.manualInvoiceTicket, '15');
|
||||
await page.autocompleteSearch(selectors.invoiceOutIndex.manualInvoiceSerial, 'Global nacional');
|
||||
await page.autocompleteSearch(selectors.invoiceOutIndex.manualInvoiceTaxArea, 'national');
|
||||
await page.waitToClick(selectors.invoiceOutIndex.saveInvoice);
|
||||
|
|
|
@ -19,18 +19,22 @@ describe('Travel extra community path', () => {
|
|||
it('should edit the travel reference and the locked kilograms', async() => {
|
||||
await page.waitToClick(selectors.travelExtraCommunity.removeContinentFilter);
|
||||
await page.waitForSpinnerLoad();
|
||||
await page.writeOnEditableTD(selectors.travelExtraCommunity.firstTravelReference, 'edited reference');
|
||||
await page.waitForSpinnerLoad();
|
||||
await page.writeOnEditableTD(selectors.travelExtraCommunity.firstTravelLockedKg, '1500');
|
||||
await page.clearInput(selectors.travelExtraCommunity.firstTravelReference);
|
||||
await page.write(selectors.travelExtraCommunity.firstTravelReference, 'edited reference');
|
||||
await page.clearInput(selectors.travelExtraCommunity.firstTravelLockedKg);
|
||||
await page.write(selectors.travelExtraCommunity.firstTravelLockedKg, '1500');
|
||||
const message = await page.waitForSnackbar();
|
||||
|
||||
expect(message.text).toContain('Data saved!');
|
||||
});
|
||||
|
||||
it('should reload the index and confirm the reference and locked kg were edited', async() => {
|
||||
await page.accessToSection('travel.index');
|
||||
await page.accessToSection('travel.extraCommunity');
|
||||
await page.waitToClick(selectors.travelExtraCommunity.removeContinentFilter);
|
||||
await page.waitForTextInElement(selectors.travelExtraCommunity.firstTravelReference, 'edited reference');
|
||||
const reference = await page.getProperty(selectors.travelExtraCommunity.firstTravelReference, 'innerText');
|
||||
const lockedKg = await page.getProperty(selectors.travelExtraCommunity.firstTravelLockedKg, 'innerText');
|
||||
|
||||
const reference = await page.waitToGetProperty(selectors.travelExtraCommunity.firstTravelReference, 'value');
|
||||
const lockedKg = await page.waitToGetProperty(selectors.travelExtraCommunity.firstTravelLockedKg, 'value');
|
||||
|
||||
expect(reference).toContain('edited reference');
|
||||
expect(lockedKg).toContain(1500);
|
||||
|
|
|
@ -150,10 +150,12 @@ describe('Account create and basic data path', () => {
|
|||
|
||||
describe('Set password', () => {
|
||||
it('should set the password using the descriptor menu', async() => {
|
||||
const newPassword = 'quantum.12345';
|
||||
|
||||
await page.waitToClick(selectors.accountDescriptor.menuButton);
|
||||
await page.waitToClick(selectors.accountDescriptor.setPassword);
|
||||
await page.write(selectors.accountDescriptor.newPassword, 'quantum.crypt0graphy');
|
||||
await page.write(selectors.accountDescriptor.repeatPassword, 'quantum.crypt0graphy');
|
||||
await page.write(selectors.accountDescriptor.newPassword, newPassword);
|
||||
await page.write(selectors.accountDescriptor.repeatPassword, newPassword);
|
||||
await page.waitToClick(selectors.accountDescriptor.acceptButton);
|
||||
const message = await page.waitForSnackbar();
|
||||
|
||||
|
|
|
@ -23,12 +23,15 @@ export default class InputTime extends Field {
|
|||
let date = null;
|
||||
let value = this.input.value;
|
||||
|
||||
if (this.field && !this.modelDate)
|
||||
this.modelDate = this.field;
|
||||
|
||||
if (value) {
|
||||
let split = value.split(':').map(i => parseInt(i) || null);
|
||||
|
||||
date = this.field instanceof Date
|
||||
? this.field
|
||||
: new Date(this.field || null);
|
||||
date = this.modelDate
|
||||
? new Date(this.modelDate)
|
||||
: new Date();
|
||||
date.setHours(split[0], split[1], 0, 0);
|
||||
}
|
||||
|
||||
|
|
|
@ -130,5 +130,6 @@
|
|||
"Descanso diario 12h.": "Daily rest 12h.",
|
||||
"Fichadas impares": "Odd signs",
|
||||
"Descanso diario 9h.": "Daily rest 9h.",
|
||||
"Descanso semanal 36h. / 72h.": "Weekly rest 36h. / 72h."
|
||||
"Descanso semanal 36h. / 72h.": "Weekly rest 36h. / 72h.",
|
||||
"Password does not meet requirements": "Password does not meet requirements"
|
||||
}
|
|
@ -146,7 +146,7 @@
|
|||
"Choose a date range or days forward": "Selecciona un rango de fechas o días en adelante",
|
||||
"ORDER_ALREADY_CONFIRMED": "ORDER_ALREADY_CONFIRMED",
|
||||
"Invalid password": "Invalid password",
|
||||
"Password does not meet requirements": "Password does not meet requirements",
|
||||
"Password does not meet requirements": "La contraseña no cumple los requisitos",
|
||||
"Role already assigned": "Role already assigned",
|
||||
"Invalid role name": "Invalid role name",
|
||||
"Role name must be written in camelCase": "Role name must be written in camelCase",
|
||||
|
@ -208,7 +208,7 @@
|
|||
"Wasn't able to invoice the following clients": "No se han podido facturar los siguientes clientes",
|
||||
"Can't verify data unless the client has a business type": "No se puede verificar datos de un cliente que no tiene tipo de negocio",
|
||||
"You don't have enough privileges to set this credit amount": "No tienes suficientes privilegios para establecer esta cantidad de crédito",
|
||||
"You can't change the credit set to zero from a manager": "No puedes cambiar el cŕedito establecido a cero por un gerente",
|
||||
"You can't change the credit set to zero from a financialBoss": "No puedes cambiar el cŕedito establecido a cero por un jefe de finanzas",
|
||||
"Amounts do not match": "Las cantidades no coinciden",
|
||||
"The PDF document does not exists": "El documento PDF no existe. Prueba a regenerarlo desde la opción 'Regenerar PDF factura'",
|
||||
"The type of business must be filled in basic data": "El tipo de negocio debe estar rellenado en datos básicos",
|
||||
|
|
|
@ -402,8 +402,8 @@ module.exports = Self => {
|
|||
const models = Self.app.models;
|
||||
const userId = ctx.options.accessToken.userId;
|
||||
|
||||
const isManager = await models.Account.hasRole(userId, 'manager', ctx.options);
|
||||
if (!isManager) {
|
||||
const isFinancialBoss = await models.Account.hasRole(userId, 'financialBoss', ctx.options);
|
||||
if (!isFinancialBoss) {
|
||||
const lastCredit = await models.ClientCredit.findOne({
|
||||
where: {
|
||||
clientFk: finalState.id
|
||||
|
@ -413,10 +413,10 @@ module.exports = Self => {
|
|||
|
||||
const lastAmount = lastCredit && lastCredit.amount;
|
||||
const lastWorkerId = lastCredit && lastCredit.workerFk;
|
||||
const lastWorkerIsManager = await models.Account.hasRole(lastWorkerId, 'manager', ctx.options);
|
||||
const lastWorkerIsFinancialBoss = await models.Account.hasRole(lastWorkerId, 'financialBoss', ctx.options);
|
||||
|
||||
if (lastAmount == 0 && lastWorkerIsManager)
|
||||
throw new UserError(`You can't change the credit set to zero from a manager`);
|
||||
if (lastAmount == 0 && lastWorkerIsFinancialBoss)
|
||||
throw new UserError(`You can't change the credit set to zero from a financialBoss`);
|
||||
|
||||
const creditLimits = await models.ClientCreditLimit.find({
|
||||
fields: ['roleFk'],
|
||||
|
|
|
@ -53,7 +53,7 @@ describe('Client Model', () => {
|
|||
});
|
||||
|
||||
describe('changeCredit()', () => {
|
||||
it('should fail to change the credit as a salesAssistant set to zero by a manager', async() => {
|
||||
it('should fail to change the credit as a salesAssistant set to zero by a financialBoss', async() => {
|
||||
const tx = await models.Client.beginTransaction({});
|
||||
|
||||
let error;
|
||||
|
@ -62,7 +62,7 @@ describe('Client Model', () => {
|
|||
const options = {transaction: tx};
|
||||
const context = {options};
|
||||
|
||||
// Set credit to zero by a manager
|
||||
// Set credit to zero by a financialBoss
|
||||
const financialBoss = await models.Account.findOne({
|
||||
where: {name: 'financialBoss'}
|
||||
}, options);
|
||||
|
@ -83,7 +83,7 @@ describe('Client Model', () => {
|
|||
await tx.rollback();
|
||||
}
|
||||
|
||||
expect(error.message).toEqual(`You can't change the credit set to zero from a manager`);
|
||||
expect(error.message).toEqual(`You can't change the credit set to zero from a financialBoss`);
|
||||
});
|
||||
|
||||
it('should fail to change to a high credit amount as a salesAssistant', async() => {
|
||||
|
|
|
@ -52,7 +52,7 @@ module.exports = Self => {
|
|||
|
||||
switch (field) {
|
||||
case 'size':
|
||||
case 'density':
|
||||
case 'weightByPiece':
|
||||
case 'description':
|
||||
case 'packingOut':
|
||||
modelName = 'Item';
|
||||
|
|
|
@ -157,7 +157,7 @@ module.exports = Self => {
|
|||
i.image,
|
||||
i.id AS itemFk,
|
||||
i.size,
|
||||
i.density,
|
||||
i.weightByPiece,
|
||||
it.code,
|
||||
i.typeFk,
|
||||
i.family,
|
||||
|
|
|
@ -37,7 +37,7 @@ describe('Buy editLatestsBuys()', () => {
|
|||
const options = {transaction: tx};
|
||||
|
||||
try {
|
||||
const filter = {typeFk: 1};
|
||||
const filter = {'i.typeFk': 1};
|
||||
const ctx = {
|
||||
args: {
|
||||
filter: filter
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
order="itemFk DESC"
|
||||
limit="20"
|
||||
data="$ctrl.buys"
|
||||
on-data-change="$ctrl.reCheck()"
|
||||
auto-load="true">
|
||||
</vn-crud-model>
|
||||
<vn-portal slot="topbar">
|
||||
|
@ -67,8 +68,8 @@
|
|||
<th field="origin">
|
||||
<span translate>Origin</span>
|
||||
</th>
|
||||
<th field="density">
|
||||
<span translate>Density</span>
|
||||
<th field="weightByPiece">
|
||||
<span translate>Weight/Piece</span>
|
||||
</th>
|
||||
<th field="isActive">
|
||||
<span translate>Active</span>
|
||||
|
@ -129,6 +130,7 @@
|
|||
<td>
|
||||
<vn-check
|
||||
ng-model="buy.checked"
|
||||
on-change="$ctrl.saveChecked(buy.id)"
|
||||
vn-click-stop>
|
||||
</vn-check>
|
||||
</td>
|
||||
|
@ -181,7 +183,7 @@
|
|||
{{::buy.intrastat}}
|
||||
</td>
|
||||
<td>{{::buy.origin}}</td>
|
||||
<td>{{::buy.density}}</td>
|
||||
<td>{{::buy.weightByPiece}}</td>
|
||||
<td>
|
||||
<vn-check
|
||||
disabled="true"
|
||||
|
|
|
@ -7,6 +7,7 @@ export default class Controller extends Section {
|
|||
super($element, $);
|
||||
this.editedColumn;
|
||||
this.checkAll = false;
|
||||
this.checkedBuys = [];
|
||||
|
||||
this.smartTableOptions = {
|
||||
activeButtons: {
|
||||
|
@ -79,7 +80,7 @@ export default class Controller extends Section {
|
|||
{field: 'weight', displayName: this.$t('Weight')},
|
||||
{field: 'description', displayName: this.$t('Description')},
|
||||
{field: 'size', displayName: this.$t('Size')},
|
||||
{field: 'density', displayName: this.$t('Density')},
|
||||
{field: 'weightByPiece', displayName: this.$t('weight/Piece')},
|
||||
{field: 'packingOut', displayName: this.$t('PackingOut')},
|
||||
{field: 'landing', displayName: this.$t('Landing')}
|
||||
];
|
||||
|
@ -102,7 +103,7 @@ export default class Controller extends Section {
|
|||
switch (param) {
|
||||
case 'id':
|
||||
case 'size':
|
||||
case 'density':
|
||||
case 'weightByPiece':
|
||||
case 'isActive':
|
||||
case 'family':
|
||||
case 'minPrice':
|
||||
|
@ -139,6 +140,7 @@ export default class Controller extends Section {
|
|||
|
||||
uncheck() {
|
||||
this.checkAll = false;
|
||||
this.checkedBuys = [];
|
||||
}
|
||||
|
||||
get totalChecked() {
|
||||
|
@ -148,6 +150,23 @@ export default class Controller extends Section {
|
|||
return this.checked.length;
|
||||
}
|
||||
|
||||
saveChecked(buyId) {
|
||||
const index = this.checkedBuys.indexOf(buyId);
|
||||
if (index !== -1)
|
||||
return this.checkedBuys.splice(index, 1);
|
||||
return this.checkedBuys.push(buyId);
|
||||
}
|
||||
|
||||
reCheck() {
|
||||
if (!this.$.model.data) return;
|
||||
if (!this.checkedBuys.length) return;
|
||||
|
||||
this.$.model.data.forEach(buy => {
|
||||
if (this.checkedBuys.includes(buy.id))
|
||||
buy.checked = true;
|
||||
});
|
||||
}
|
||||
|
||||
onEditAccept() {
|
||||
const rowsToEdit = [];
|
||||
for (let row of this.checked)
|
||||
|
|
|
@ -57,5 +57,44 @@ describe('Entry', () => {
|
|||
expect(result.length).toEqual(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('reCheck()', () => {
|
||||
it(`should recheck buys`, () => {
|
||||
controller.$.model.data = [
|
||||
{checked: false, id: 1},
|
||||
{checked: false, id: 2},
|
||||
{checked: false, id: 3},
|
||||
{checked: false, id: 4},
|
||||
];
|
||||
controller.checkedBuys = [1, 2];
|
||||
|
||||
controller.reCheck();
|
||||
|
||||
expect(controller.$.model.data[0].checked).toEqual(true);
|
||||
expect(controller.$.model.data[1].checked).toEqual(true);
|
||||
expect(controller.$.model.data[2].checked).toEqual(false);
|
||||
expect(controller.$.model.data[3].checked).toEqual(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('saveChecked()', () => {
|
||||
it(`should check buy`, () => {
|
||||
const buyCheck = 3;
|
||||
controller.checkedBuys = [1, 2];
|
||||
|
||||
controller.saveChecked(buyCheck);
|
||||
|
||||
expect(controller.checkedBuys[2]).toEqual(buyCheck);
|
||||
});
|
||||
|
||||
it(`should uncheck buy`, () => {
|
||||
const buyUncheck = 3;
|
||||
controller.checkedBuys = [1, 2, 3];
|
||||
|
||||
controller.saveChecked(buyUncheck);
|
||||
|
||||
expect(controller.checkedBuys[2]).toEqual(undefined);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -12,7 +12,7 @@ module.exports = Self => {
|
|||
},
|
||||
http: {
|
||||
path: `/downloadImages`,
|
||||
verb: 'GET'
|
||||
verb: 'POST'
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -42,7 +42,6 @@ module.exports = Self => {
|
|||
|
||||
origin.itemTag = undefined;
|
||||
origin.description = undefined;
|
||||
origin.image = undefined;
|
||||
origin.comment = undefined;
|
||||
origin.size = undefined;
|
||||
|
||||
|
|
|
@ -160,7 +160,7 @@ module.exports = Self => {
|
|||
i.subName,
|
||||
i.isActive,
|
||||
i.stems,
|
||||
i.density,
|
||||
i.weightByPiece,
|
||||
i.stemMultiplier,
|
||||
i.typeFk,
|
||||
i.isFloramondo,
|
||||
|
|
|
@ -30,11 +30,24 @@ module.exports = Self => {
|
|||
sum(ws.saleWaste) AS dwindle
|
||||
FROM bs.waste ws
|
||||
WHERE year = YEAR(TIMESTAMPADD(WEEK,-1, ?))
|
||||
AND week = WEEK(TIMESTAMPADD(WEEK,-1, ?), 1)
|
||||
AND week = WEEK(TIMESTAMPADD(WEEK,-1, ?), 1)
|
||||
GROUP BY buyer, family
|
||||
) sub
|
||||
ORDER BY percentage DESC`, [date, date], myOptions);
|
||||
|
||||
const wastesTotal = await Self.rawSql(`
|
||||
SELECT *, 100 * dwindle / total AS percentage
|
||||
FROM (
|
||||
SELECT buyer,
|
||||
sum(ws.saleTotal) AS total,
|
||||
sum(ws.saleWaste) AS dwindle
|
||||
FROM bs.waste ws
|
||||
WHERE year = YEAR(TIMESTAMPADD(WEEK,-1, ?))
|
||||
AND week = WEEK(TIMESTAMPADD(WEEK,-1, ?), 1)
|
||||
GROUP BY buyer
|
||||
) sub
|
||||
ORDER BY percentage DESC`, [date, date], myOptions);
|
||||
|
||||
const details = [];
|
||||
|
||||
for (let waste of wastes) {
|
||||
|
@ -55,6 +68,14 @@ module.exports = Self => {
|
|||
buyerDetail.lines.push(waste);
|
||||
}
|
||||
|
||||
for (let waste of details) {
|
||||
let buyerTotal = wastesTotal.find(totals => {
|
||||
return waste.buyer == totals.buyer;
|
||||
});
|
||||
|
||||
Object.assign(waste, buyerTotal);
|
||||
}
|
||||
|
||||
return details;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -21,7 +21,7 @@ describe('item clone()', () => {
|
|||
const result = await models.Item.clone(itemFk, options);
|
||||
|
||||
expect(result.id).toEqual(nextItemId);
|
||||
expect(result.image).toBeUndefined();
|
||||
expect(result.image).toBeDefined();
|
||||
expect(result.itemTag).toBeUndefined();
|
||||
expect(result.comment).toBeUndefined();
|
||||
expect(result.description).toBeUndefined();
|
||||
|
|
|
@ -12,6 +12,7 @@ describe('Item getWasteByWorker()', () => {
|
|||
const anyResult = result[Math.floor(Math.random() * Math.floor(length))];
|
||||
|
||||
expect(anyResult.buyer).toMatch(/(CharlesXavier|HankPym|DavidCharlesHaller)/);
|
||||
expect(anyResult.total).toBeGreaterThanOrEqual(1000);
|
||||
expect(anyResult.lines.length).toBeGreaterThanOrEqual(3);
|
||||
|
||||
await tx.rollback();
|
||||
|
|
|
@ -53,9 +53,9 @@
|
|||
"type": "number",
|
||||
"description": "Relevancy"
|
||||
},
|
||||
"density": {
|
||||
"weightByPiece": {
|
||||
"type": "number",
|
||||
"description": "Density"
|
||||
"description": "WeightByPiece"
|
||||
},
|
||||
"stemMultiplier": {
|
||||
"type": "number",
|
||||
|
|
|
@ -124,9 +124,8 @@
|
|||
<vn-input-number
|
||||
vn-one
|
||||
min="0"
|
||||
step="0.01"
|
||||
label="Density"
|
||||
ng-model="$ctrl.item.density"
|
||||
label="Weight/Piece"
|
||||
ng-model="$ctrl.item.weightByPiece"
|
||||
rule>
|
||||
</vn-input-number>
|
||||
<vn-autocomplete
|
||||
|
|
|
@ -45,8 +45,8 @@
|
|||
<th field="buyerFk">
|
||||
<span translate>Buyer</span>
|
||||
</th>
|
||||
<th field="density">
|
||||
<span translate>Density</span>
|
||||
<th field="weightByPiece">
|
||||
<span translate>Weight/Piece</span>
|
||||
</th>
|
||||
<th field="stemMultiplier">
|
||||
<span translate>Multiplier</span>
|
||||
|
@ -117,7 +117,7 @@
|
|||
{{::item.userName}}
|
||||
</span>
|
||||
</td>
|
||||
<td>{{::item.density}}</td>
|
||||
<td>{{::item.weightByPiece}}</td>
|
||||
<td>{{::item.stemMultiplier}}</td>
|
||||
<td>
|
||||
<vn-check
|
||||
|
|
|
@ -87,7 +87,7 @@ class Controller extends Section {
|
|||
case 'size':
|
||||
case 'subname':
|
||||
case 'isActive':
|
||||
case 'density':
|
||||
case 'weightByPiece':
|
||||
case 'stemMultiplier':
|
||||
case 'stems':
|
||||
return {[`i.${param}`]: value};
|
||||
|
|
|
@ -40,7 +40,7 @@ Create: Crear
|
|||
Client card: Ficha del cliente
|
||||
Shipped: F. envío
|
||||
stems: Tallos
|
||||
Density: Densidad
|
||||
Weight/Piece: Peso/tallo
|
||||
Search items by id, name or barcode: Buscar articulos por identificador, nombre o codigo de barras
|
||||
SalesPerson: Comercial
|
||||
Concept: Concepto
|
||||
|
|
|
@ -91,8 +91,8 @@
|
|||
<vn-label-value label="Relevancy"
|
||||
value="{{$ctrl.summary.item.relevancy}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value label="Density"
|
||||
value="{{$ctrl.summary.item.density}}">
|
||||
<vn-label-value label="Weight/Piece"
|
||||
value="{{$ctrl.summary.item.weightByPiece}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value label="Expense"
|
||||
value="{{$ctrl.summary.item.expense.name}}">
|
||||
|
|
|
@ -4,39 +4,46 @@
|
|||
data="details">
|
||||
</vn-crud-model>
|
||||
<vn-data-viewer model="model">
|
||||
<section ng-repeat="detail in details" class="vn-pa-md">
|
||||
<vn-horizontal class="header">
|
||||
<h5><span translate>{{detail.buyer}}</span></h5>
|
||||
<vn-none>
|
||||
<vn-icon
|
||||
ng-class="{'hidden': !$ctrl.wasteConfig[detail.buyer].hidden}"
|
||||
class="arrow pointer"
|
||||
icon="keyboard_arrow_up"
|
||||
vn-tooltip="Minimize/Maximize"
|
||||
ng-click="$ctrl.toggleHidePanel(detail)">
|
||||
</vn-icon>
|
||||
</vn-none>
|
||||
</vn-horizontal>
|
||||
<vn-card ng-class="{'hidden': !$ctrl.wasteConfig[detail.buyer].hidden}">
|
||||
<vn-table>
|
||||
<vn-thead>
|
||||
<vn-tr>
|
||||
<vn-th class="waste-family">Family</vn-th>
|
||||
<vn-th number>Percentage</vn-th>
|
||||
<vn-th number>Dwindle</vn-th>
|
||||
<vn-th number>Total</vn-th>
|
||||
</vn-tr>
|
||||
</vn-thead>
|
||||
<vn-tbody>
|
||||
<a ng-repeat="waste in detail.lines" class="clickable vn-tr"
|
||||
ui-sref="item.waste.detail({buyer: waste.buyer, family: waste.family})">
|
||||
<vn-td class="waste-family">{{::waste.family}}</vn-td>
|
||||
<vn-td number>{{::(waste.percentage / 100) | percentage: 2}}</vn-td>
|
||||
<vn-td number>{{::waste.dwindle | currency: 'EUR'}}</vn-td>
|
||||
<vn-td number>{{::waste.total | currency: 'EUR'}}</vn-td>
|
||||
</vn-tr>
|
||||
</vn-tbody>
|
||||
</vn-table>
|
||||
</vn-card>
|
||||
</section>
|
||||
<vn-card>
|
||||
<vn-table>
|
||||
<vn-thead>
|
||||
<vn-tr class="header">
|
||||
<vn-th class="waste-family">Buyer</vn-th>
|
||||
<vn-th class="waste-family">Family</vn-th>
|
||||
<vn-th number>Percentage</vn-th>
|
||||
<vn-th number>Dwindle</vn-th>
|
||||
<vn-th number>Total</vn-th>
|
||||
<vn-th shrink></vn-th>
|
||||
</vn-tr>
|
||||
</vn-thead>
|
||||
<vn-tbody ng-repeat="detail in details" class="vn-mb-md">
|
||||
<vn-tr class="header">
|
||||
<vn-td>{{::detail.buyer}}</vn-td>
|
||||
<vn-td>{{::detail.family}}</vn-td>
|
||||
<vn-td number>{{::(detail.percentage / 100) | percentage: 2}}</vn-td>
|
||||
<vn-td number>{{::detail.dwindle | currency: 'EUR'}}</vn-td>
|
||||
<vn-td number>{{::detail.total | currency: 'EUR'}}</vn-td>
|
||||
<vn-td shrink>
|
||||
<vn-icon-button
|
||||
ng-class="{'hidden': !$ctrl.wasteConfig[detail.buyer].hidden}"
|
||||
class="arrow pointer"
|
||||
icon="keyboard_arrow_up"
|
||||
vn-tooltip="Minimize/Maximize"
|
||||
ng-click="$ctrl.toggleHidePanel(detail)">
|
||||
</vn-icon-button>
|
||||
</vn-td>
|
||||
</vn-tr>
|
||||
<vn-tr ng-repeat="waste in detail.lines" class="clickable vn-tr"
|
||||
ui-sref="item.waste.detail({buyer: waste.buyer, family: waste.family})"
|
||||
ng-class="{'hidden': !$ctrl.wasteConfig[detail.buyer].hidden}">
|
||||
<vn-td></vn-td>
|
||||
<vn-td>{{::waste.family}}</vn-td>
|
||||
<vn-td number>{{::(waste.percentage / 100) | percentage: 2}}</vn-td>
|
||||
<vn-td number>{{::waste.dwindle | currency: 'EUR'}}</vn-td>
|
||||
<vn-td number>{{::waste.total | currency: 'EUR'}}</vn-td>
|
||||
<vn-td shrink></vn-td>
|
||||
</vn-tr>
|
||||
</vn-tbody>
|
||||
</vn-table>
|
||||
</vn-card>
|
||||
</vn-data-viewer>
|
|
@ -5,20 +5,9 @@ vn-item-waste-index,
|
|||
vn-item-waste-detail {
|
||||
.header {
|
||||
padding: 12px 0 5px 0;
|
||||
color: gray;
|
||||
background-color: $color-bg;
|
||||
font-size: 1.2rem;
|
||||
border-bottom: $border;
|
||||
margin-bottom: 10px;
|
||||
|
||||
& > vn-none > vn-icon {
|
||||
@extend %clickable-light;
|
||||
color: $color-button;
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
vn-none > .arrow {
|
||||
transition: transform 200ms;
|
||||
}
|
||||
}
|
||||
|
||||
vn-table vn-th.waste-family,
|
||||
|
@ -26,11 +15,12 @@ vn-item-waste-detail {
|
|||
max-width: 64px;
|
||||
width: 64px
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
|
||||
}
|
||||
.header > vn-none > .arrow.hidden {
|
||||
|
||||
.arrow.hidden {
|
||||
display: block;
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
|
|
@ -210,6 +210,9 @@
|
|||
</slot-table>
|
||||
</smart-table>
|
||||
</vn-card>
|
||||
<vn-ticket-descriptor-popover
|
||||
vn-id="ticketDescriptor">
|
||||
</vn-ticket-descriptor-popover>
|
||||
<vn-worker-descriptor-popover
|
||||
vn-id="workerDescriptor">
|
||||
</vn-worker-descriptor-popover>
|
||||
|
|
|
@ -50,8 +50,10 @@
|
|||
},
|
||||
"scope": {
|
||||
"where": {
|
||||
"isActive": true
|
||||
}
|
||||
"isActive": {
|
||||
"neq": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"acls": [
|
||||
{
|
||||
|
|
|
@ -7,5 +7,8 @@
|
|||
},
|
||||
"ShelvingLog": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"Sector": {
|
||||
"dataSource": "vn"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
{
|
||||
"name": "Sector",
|
||||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "sector"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "number",
|
||||
"id": true,
|
||||
"description": "Identifier"
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"required": true
|
||||
},
|
||||
"warehouseFk": {
|
||||
"type": "number",
|
||||
"required": true
|
||||
},
|
||||
"isPreviousPreparedByPacking": {
|
||||
"type": "boolean",
|
||||
"required": true
|
||||
},
|
||||
"code": {
|
||||
"type": "string",
|
||||
"required": false
|
||||
},
|
||||
"isPreviousPrepared": {
|
||||
"type": "boolean",
|
||||
"required": true
|
||||
},
|
||||
"isPackagingArea": {
|
||||
"type": "boolean",
|
||||
"required": true
|
||||
},
|
||||
"reportFk": {
|
||||
"type": "number",
|
||||
"required": false
|
||||
},
|
||||
"sonFk": {
|
||||
"type": "number",
|
||||
"required": false
|
||||
},
|
||||
"isMain": {
|
||||
"type": "boolean",
|
||||
"required": true
|
||||
},
|
||||
"itemPackingTypeFk": {
|
||||
"type": "string",
|
||||
"required": false
|
||||
},
|
||||
"workerFk": {
|
||||
"type": "number",
|
||||
"required": false
|
||||
},
|
||||
"printerFk": {
|
||||
"type": "number",
|
||||
"required": false
|
||||
},
|
||||
"isHideForPickers": {
|
||||
"type": "boolean",
|
||||
"required": true
|
||||
},
|
||||
"isReserve": {
|
||||
"type": "boolean",
|
||||
"required": true
|
||||
}
|
||||
}
|
||||
}
|
|
@ -82,6 +82,9 @@ describe('ticket setDeleted()', () => {
|
|||
ctx.req.__ = value => {
|
||||
return value;
|
||||
};
|
||||
const [ticketCollectionOld] = await models.Ticket.rawSql(
|
||||
`SELECT COUNT(*) numberRows
|
||||
FROM vn.ticketCollection`, [], options);
|
||||
const ticketId = 23;
|
||||
|
||||
await models.Ticket.setDeleted(ctx, ticketId, options);
|
||||
|
@ -90,7 +93,7 @@ describe('ticket setDeleted()', () => {
|
|||
`SELECT COUNT(*) numberRows
|
||||
FROM vn.ticketCollection`, [], options);
|
||||
|
||||
expect(ticketCollection.numberRows).toEqual(3);
|
||||
expect(ticketCollection.numberRows).toBeLessThan(ticketCollectionOld.numberRows);
|
||||
|
||||
await tx.rollback();
|
||||
} catch (e) {
|
||||
|
|
|
@ -128,10 +128,10 @@ module.exports = Self => {
|
|||
w.name AS warehouseInFk,
|
||||
w.name AS warehouseInName,
|
||||
SUM(b.stickers) AS stickers,
|
||||
s.id AS supplierFk,
|
||||
s.id AS cargoSupplierFk,
|
||||
s.nickname AS cargoSupplierNickname,
|
||||
CAST(SUM(i.density * b.stickers * IF(pkg.volume, pkg.volume, pkg.width * pkg.depth * pkg.height) / 1000000 ) as DECIMAL(10,0)) as loadedKg,
|
||||
CAST(SUM(167.5 * b.stickers * IF(pkg.volume, pkg.volume, pkg.width * pkg.depth * pkg.height) / 1000000 ) as DECIMAL(10,0)) as volumeKg
|
||||
CAST(SUM(b.weight * b.stickers) as DECIMAL(10,0)) as loadedKg,
|
||||
CAST(SUM(vc.aerealVolumetricDensity * b.stickers * IF(pkg.volume, pkg.volume, pkg.width * pkg.depth * pkg.height) / 1000000) as DECIMAL(10,0)) as volumeKg
|
||||
FROM travel t
|
||||
LEFT JOIN supplier s ON s.id = t.cargoSupplierFk
|
||||
LEFT JOIN entry e ON e.travelFk = t.id
|
||||
|
@ -143,7 +143,8 @@ module.exports = Self => {
|
|||
JOIN warehouse wo ON wo.id = t.warehouseOutFk
|
||||
JOIN country c ON c.id = wo.countryFk
|
||||
LEFT JOIN continent cnt ON cnt.id = c.continentFk
|
||||
JOIN agencyMode am ON am.id = t.agencyModeFk`
|
||||
JOIN agencyMode am ON am.id = t.agencyModeFk
|
||||
JOIN vn.volumeConfig vc`
|
||||
);
|
||||
|
||||
stmt.merge(conn.makeWhere(filter.where));
|
||||
|
@ -160,19 +161,21 @@ module.exports = Self => {
|
|||
e.travelFk,
|
||||
e.ref,
|
||||
e.loadPriority,
|
||||
s.id AS supplierFk,
|
||||
s.name AS supplierName,
|
||||
SUM(b.stickers) AS stickers,
|
||||
e.evaNotes,
|
||||
e.notes,
|
||||
CAST(SUM(i.density * b.stickers * IF(pkg.volume, pkg.volume, pkg.width * pkg.depth * pkg.height) / 1000000 ) as DECIMAL(10,0)) as loadedkg,
|
||||
CAST(SUM(167.5 * b.stickers * IF(pkg.volume, pkg.volume, pkg.width * pkg.depth * pkg.height) / 1000000 ) as DECIMAL(10,0)) as volumeKg
|
||||
CAST(SUM(b.weight * b.stickers) AS DECIMAL(10,0)) as loadedkg,
|
||||
CAST(SUM(vc.aerealVolumetricDensity * b.stickers * IF(pkg.volume, pkg.volume, pkg.width * pkg.depth * pkg.height) / 1000000) AS DECIMAL(10,0)) as volumeKg
|
||||
FROM tmp.travel tr
|
||||
JOIN entry e ON e.travelFk = tr.id
|
||||
JOIN buy b ON b.entryFk = e.id
|
||||
JOIN packaging pkg ON pkg.id = b.packageFk
|
||||
JOIN item i ON i.id = b.itemFk
|
||||
JOIN itemType it ON it.id = i.typeFk
|
||||
JOIN supplier s ON s.id = e.supplierFk`
|
||||
JOIN supplier s ON s.id = e.supplierFk
|
||||
JOIN vn.volumeConfig vc`
|
||||
);
|
||||
|
||||
stmt.merge(conn.makeGroupBy('e.id'));
|
||||
|
|
|
@ -50,15 +50,15 @@
|
|||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-autocomplete vn-one
|
||||
label="Warehouse In"
|
||||
ng-model="filter.warehouseInFk"
|
||||
label="Warehouse Out"
|
||||
ng-model="filter.warehouseOutFk"
|
||||
url="Warehouses"
|
||||
show-field="name"
|
||||
value-field="id">
|
||||
</vn-autocomplete>
|
||||
<vn-autocomplete vn-one
|
||||
label="Warehouse Out"
|
||||
ng-model="filter.warehouseOutFk"
|
||||
label="Warehouse In"
|
||||
ng-model="filter.warehouseInFk"
|
||||
url="Warehouses"
|
||||
show-field="name"
|
||||
value-field="id">
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<vn-crud-model
|
||||
vn-id="model"
|
||||
url="Travels/extraCommunityFilter"
|
||||
filter="::$ctrl.filter"
|
||||
data="travels"
|
||||
order="shipped ASC, landed ASC, travelFk, loadPriority, agencyModeFk, evaNotes"
|
||||
limit="20"
|
||||
|
@ -18,112 +19,174 @@
|
|||
model="model">
|
||||
</vn-searchbar>
|
||||
</vn-portal>
|
||||
<vn-data-viewer model="model" class="travel-list">
|
||||
<vn-card>
|
||||
<section class="vn-pa-md">
|
||||
<vn-tool-bar class="vn-mb-md">
|
||||
<vn-button disabled="!$ctrl.hasDateRange"
|
||||
icon="picture_as_pdf"
|
||||
ng-click="$ctrl.showReport()"
|
||||
vn-tooltip="Open as PDF">
|
||||
</vn-button>
|
||||
</vn-tool-bar>
|
||||
<vn-table>
|
||||
<vn-thead>
|
||||
<vn-tr>
|
||||
<vn-th shrink>Id</vn-th>
|
||||
<vn-th expand>Supplier</vn-th>
|
||||
<vn-th expand>Freighter</vn-th>
|
||||
<vn-th>Reference</vn-th>
|
||||
<vn-th number>Packages</vn-th>
|
||||
<vn-th number>Bl. KG</vn-th>
|
||||
<vn-th number>Phy. KG</vn-th>
|
||||
<vn-th number>Vol. KG</vn-th>
|
||||
<vn-th expand translate-attr="{title: 'Warehouse Out'}">
|
||||
Wh. Out
|
||||
</vn-th>
|
||||
<vn-th expand>W. Shipped</vn-th>
|
||||
<vn-th expand translate-attr="{title: 'Warehouse In'}">
|
||||
Wh. In
|
||||
</vn-th>
|
||||
<vn-th expand>W. Landed</vn-th>
|
||||
</vn-tr>
|
||||
</vn-thead>
|
||||
<vn-tbody ng-repeat="travel in travels" class="vn-mb-md" vn-droppable="$ctrl.onDrop($event)" ng-attr-id="{{::travel.id}}">
|
||||
<vn-tr class="header">
|
||||
<vn-td>
|
||||
<span class="link"
|
||||
<vn-card class="travel-list scrollable">
|
||||
<smart-table
|
||||
model="model"
|
||||
options="$ctrl.smartTableOptions">
|
||||
<slot-actions>
|
||||
<section>
|
||||
<vn-tool-bar class="vn-mb-md">
|
||||
<vn-button
|
||||
disabled="!$ctrl.hasDateRange"
|
||||
icon="picture_as_pdf"
|
||||
ng-click="$ctrl.showReport()"
|
||||
vn-tooltip="Open as PDF">
|
||||
</vn-button>
|
||||
</vn-tool-bar>
|
||||
</section>
|
||||
</slot-actions>
|
||||
<slot-table>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th field="id" shrink>
|
||||
<span translate>Id</span>
|
||||
</th>
|
||||
<th field="cargoSupplierFk" expand>
|
||||
<span translate>Supplier</span>
|
||||
</th>
|
||||
<th field="agencyModeFk" expand>
|
||||
<span translate>Agency</span>
|
||||
</th>
|
||||
<th field="ref">
|
||||
<span translate>Reference</span>
|
||||
</th>
|
||||
<th field="stickers" number>
|
||||
<span translate>Packages</span>
|
||||
</th>
|
||||
<th field="kg" number>
|
||||
<span translate>Bl. KG</span>
|
||||
</th>
|
||||
<th field="loadedKg" number>
|
||||
<span translate>Phy. KG</span>
|
||||
</th>
|
||||
<th field="volumeKg" number>
|
||||
<span translate>Vol. KG</span>
|
||||
</th>
|
||||
<th
|
||||
field="warehouseOutFk"
|
||||
translate-attr="{title: 'Warehouse Out'}">
|
||||
<span translate>Wh. Out</span>
|
||||
</th>
|
||||
<th field="shipped">
|
||||
<span translate>W. Shipped</span>
|
||||
</th>
|
||||
<th
|
||||
field="warehouseInFk"
|
||||
translate-attr="{title: 'Warehouse In'}">
|
||||
<span translate>Wh. In</span>
|
||||
</th>
|
||||
<th field="landed">
|
||||
<span translate>W. Landed</span>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody
|
||||
ng-repeat="travel in travels"
|
||||
class="vn-mb-md"
|
||||
vn-droppable="$ctrl.onDrop($event)"
|
||||
ng-attr-id="{{::travel.id}}"
|
||||
vn-stop-click>
|
||||
<tr
|
||||
class="header"
|
||||
vn-anchor="::{
|
||||
state: 'travel.card.basicData',
|
||||
params: {id: travel.id}
|
||||
}">
|
||||
<td vn-click-stop>
|
||||
<span
|
||||
class="link"
|
||||
ng-click="travelDescriptor.show($event, travel.id)">
|
||||
{{::travel.id}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td expand>{{::travel.agencyModeName}}</vn-td>
|
||||
<vn-td expand>{{::travel.cargoSupplierNickname}}</vn-td>
|
||||
<vn-td-editable name="reference" expand>
|
||||
<text>{{travel.ref}}</text>
|
||||
<field>
|
||||
<vn-textfield class="dense" vn-focus
|
||||
ng-model="travel.ref"
|
||||
on-change="$ctrl.save(travel.id, {ref: value})">
|
||||
</vn-textfield>
|
||||
</field>
|
||||
</vn-td-editable>
|
||||
<vn-td number>{{::travel.stickers}}</vn-td>
|
||||
<vn-td-editable name="lockedKg" expand style="text-align: right">
|
||||
<text number>{{travel.kg}}</text>
|
||||
<field>
|
||||
<vn-input-number class="dense" vn-focus
|
||||
ng-model="travel.kg"
|
||||
on-change="$ctrl.save(travel.id, {kg: value})"
|
||||
min="0">
|
||||
</vn-input-number>
|
||||
</field>
|
||||
</vn-td-editable>
|
||||
<vn-td number>{{::travel.loadedKg}}</vn-td>
|
||||
<vn-td number>{{::travel.volumeKg}}</vn-td>
|
||||
<vn-td expand>{{::travel.warehouseOutName}}</vn-td>
|
||||
<vn-td expand>{{::travel.shipped | date: 'dd/MM/yyyy'}}</vn-td>
|
||||
<vn-td expand>{{::travel.warehouseInName}}</vn-td>
|
||||
<vn-td expand>{{::travel.landed | date: 'dd/MM/yyyy'}}</vn-td>
|
||||
</vn-tr>
|
||||
<a href="#" ng-repeat="entry in travel.entries" class="vn-tr" draggable
|
||||
</td>
|
||||
<td expand vn-click-stop>
|
||||
<span
|
||||
class="link"
|
||||
ng-click="supplierDescriptor.show($event, travel.cargoSupplierFk)">
|
||||
{{::travel.cargoSupplierNickname}}
|
||||
</span>
|
||||
</td>
|
||||
<td expand>{{::travel.agencyModeName}}</td>
|
||||
<td
|
||||
name="reference"
|
||||
expand
|
||||
vn-click-stop>
|
||||
<vn-textfield
|
||||
class="dense td-editable"
|
||||
ng-model="travel.ref"
|
||||
on-change="$ctrl.save(travel.id, {ref: value})">
|
||||
</vn-textfield>
|
||||
</vn-icon>
|
||||
</td>
|
||||
<td number>{{::travel.stickers}}</td>
|
||||
<td
|
||||
name="lockedKg"
|
||||
expand
|
||||
vn-click-stop>
|
||||
<vn-input-number
|
||||
number
|
||||
class="td-editable number"
|
||||
ng-model="travel.kg"
|
||||
on-change="$ctrl.save(travel.id, {kg: value})"
|
||||
min="0">
|
||||
</vn-input-number>
|
||||
</td>
|
||||
<td number>{{::travel.loadedKg}}</td>
|
||||
<td number>{{::travel.volumeKg}}</td>
|
||||
<td expand>{{::travel.warehouseOutName}}</td>
|
||||
<td expand>{{::travel.shipped | date: 'dd/MM/yyyy'}}</td>
|
||||
<td expand>{{::travel.warehouseInName}}</td>
|
||||
<td expand>{{::travel.landed | date: 'dd/MM/yyyy'}}</td>
|
||||
</tr>
|
||||
<tr
|
||||
ng-repeat="entry in travel.entries"
|
||||
draggable
|
||||
ng-attr-id="{{::entry.id}}"
|
||||
ng-click="$event.preventDefault()">
|
||||
<vn-td>
|
||||
<td>
|
||||
<span class="link"
|
||||
ng-click="entryDescriptor.show($event, entry.id)">
|
||||
{{::entry.id}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td>{{::entry.supplierName}}</vn-td>
|
||||
<vn-td></vn-td>
|
||||
<vn-td expand>{{::entry.ref}}</vn-td>
|
||||
<vn-td number>{{::entry.stickers}}</vn-td>
|
||||
<vn-td number></vn-td>
|
||||
<vn-td number>{{::entry.loadedkg}}</vn-td>
|
||||
<vn-td number>{{::entry.volumeKg}}</vn-td>
|
||||
<vn-td>
|
||||
</td>
|
||||
<td>
|
||||
<span
|
||||
class="link"
|
||||
ng-click="supplierDescriptor.show($event, entry.supplierFk)">
|
||||
{{::entry.supplierName}}
|
||||
</span>
|
||||
</td>
|
||||
<td></td>
|
||||
<td expand>{{::entry.ref}}</td>
|
||||
<td number>{{::entry.stickers}}</td>
|
||||
<td number></td>
|
||||
<td number>{{::entry.loadedkg}}</td>
|
||||
<td number>{{::entry.volumeKg}}</td>
|
||||
<td>
|
||||
<span ng-if="::entry.notes" vn-tooltip="{{::entry.notes}}">
|
||||
{{::entry.notes}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td>
|
||||
</td>
|
||||
<td>
|
||||
<span ng-if="::entry.evaNotes" vn-tooltip="{{::entry.evaNotes}}">
|
||||
{{::entry.evaNotes}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td></vn-td>
|
||||
<vn-td></vn-td>
|
||||
</a>
|
||||
</vn-tbody>
|
||||
</vn-table>
|
||||
</section>
|
||||
</vn-card>
|
||||
</vn-data-viewer>
|
||||
</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</slot-table>
|
||||
</smart-table>
|
||||
</vn-card>
|
||||
<vn-travel-descriptor-popover
|
||||
vn-id="travelDescriptor">
|
||||
</vn-travel-descriptor-popover>
|
||||
<vn-entry-descriptor-popover
|
||||
vn-id="entryDescriptor">
|
||||
</vn-entry-descriptor-popover>
|
||||
|
||||
<vn-supplier-descriptor-popover
|
||||
vn-id="supplierDescriptor">
|
||||
</vn-supplier-descriptor-popover>
|
||||
|
|
|
@ -14,8 +14,15 @@ class Controller extends Section {
|
|||
draggable.addEventListener('dragend',
|
||||
event => this.dragEnd(event));
|
||||
|
||||
this.draggableElement = 'a[draggable]';
|
||||
this.droppableElement = 'vn-tbody[vn-droppable]';
|
||||
draggable.addEventListener('dragover',
|
||||
event => this.dragOver(event));
|
||||
draggable.addEventListener('dragenter',
|
||||
event => this.dragEnter(event));
|
||||
draggable.addEventListener('dragleave',
|
||||
event => this.dragLeave(event));
|
||||
|
||||
this.draggableElement = 'tr[draggable]';
|
||||
this.droppableElement = 'tbody[vn-droppable]';
|
||||
|
||||
const twoDays = 2;
|
||||
const shippedFrom = new Date();
|
||||
|
@ -32,6 +39,8 @@ class Controller extends Section {
|
|||
landedTo: landedTo,
|
||||
continent: 'AM'
|
||||
};
|
||||
|
||||
this.smartTableOptions = {};
|
||||
}
|
||||
|
||||
get hasDateRange() {
|
||||
|
@ -44,6 +53,15 @@ class Controller extends Section {
|
|||
return hasLanded || hasShipped || hasContinent || hasWarehouseOut;
|
||||
}
|
||||
|
||||
onDragInterval() {
|
||||
if (this.dragClientY > 0 && this.dragClientY < 75)
|
||||
this.$window.scrollTo(0, this.$window.scrollY - 10);
|
||||
|
||||
const maxHeight = window.screen.availHeight - (window.outerHeight - window.innerHeight);
|
||||
if (this.dragClientY > maxHeight - 75 && this.dragClientY < maxHeight)
|
||||
this.$window.scrollTo(0, this.$window.scrollY + 10);
|
||||
}
|
||||
|
||||
findDraggable($event) {
|
||||
const target = $event.target;
|
||||
const draggable = target.closest(this.draggableElement);
|
||||
|
@ -65,6 +83,7 @@ class Controller extends Section {
|
|||
const id = parseInt(draggable.id);
|
||||
this.entryId = id;
|
||||
this.entry = draggable;
|
||||
this.interval = setInterval(() => this.onDragInterval(), 50);
|
||||
}
|
||||
|
||||
dragEnd($event) {
|
||||
|
@ -72,6 +91,8 @@ class Controller extends Section {
|
|||
draggable.classList.remove('dragging');
|
||||
this.entryId = null;
|
||||
this.entry = null;
|
||||
|
||||
clearInterval(this.interval);
|
||||
}
|
||||
|
||||
onDrop($event) {
|
||||
|
@ -91,6 +112,37 @@ class Controller extends Section {
|
|||
}
|
||||
}
|
||||
|
||||
undrop() {
|
||||
if (!this.dropping) return;
|
||||
this.dropping.classList.remove('dropping');
|
||||
this.dropping = null;
|
||||
}
|
||||
|
||||
dragOver($event) {
|
||||
this.dragClientY = $event.clientY;
|
||||
$event.preventDefault();
|
||||
}
|
||||
|
||||
dragEnter($event) {
|
||||
let element = this.findDroppable($event);
|
||||
if (element) this.dropCount++;
|
||||
|
||||
if (element != this.dropping) {
|
||||
this.undrop();
|
||||
if (element) element.classList.add('dropping');
|
||||
this.dropping = element;
|
||||
}
|
||||
}
|
||||
|
||||
dragLeave($event) {
|
||||
let element = this.findDroppable($event);
|
||||
|
||||
if (element) {
|
||||
this.dropCount--;
|
||||
if (this.dropCount == 0) this.undrop();
|
||||
}
|
||||
}
|
||||
|
||||
save(id, data) {
|
||||
const endpoint = `Travels/${id}`;
|
||||
this.$http.patch(endpoint, data)
|
||||
|
|
|
@ -27,7 +27,7 @@ describe('Travel Component vnTravelExtraCommunity', () => {
|
|||
|
||||
describe('findDraggable()', () => {
|
||||
it('should find the draggable element', () => {
|
||||
const draggable = document.createElement('a');
|
||||
const draggable = document.createElement('tr');
|
||||
draggable.setAttribute('draggable', true);
|
||||
|
||||
const $event = new Event('dragstart');
|
||||
|
@ -43,7 +43,7 @@ describe('Travel Component vnTravelExtraCommunity', () => {
|
|||
|
||||
describe('findDroppable()', () => {
|
||||
it('should find the droppable element', () => {
|
||||
const droppable = document.createElement('vn-tbody');
|
||||
const droppable = document.createElement('tbody');
|
||||
droppable.setAttribute('vn-droppable', true);
|
||||
|
||||
const $event = new Event('drop');
|
||||
|
@ -60,7 +60,7 @@ describe('Travel Component vnTravelExtraCommunity', () => {
|
|||
describe('dragStart()', () => {
|
||||
it(`should add the class "dragging" to the draggable element
|
||||
and then set the entryId controller property`, () => {
|
||||
const draggable = document.createElement('a');
|
||||
const draggable = document.createElement('tr');
|
||||
draggable.setAttribute('draggable', true);
|
||||
draggable.setAttribute('id', 3);
|
||||
|
||||
|
@ -80,7 +80,7 @@ describe('Travel Component vnTravelExtraCommunity', () => {
|
|||
describe('dragEnd()', () => {
|
||||
it(`should remove the class "dragging" from the draggable element
|
||||
and then set the entryId controller property to null`, () => {
|
||||
const draggable = document.createElement('a');
|
||||
const draggable = document.createElement('tr');
|
||||
draggable.setAttribute('draggable', true);
|
||||
draggable.setAttribute('id', 3);
|
||||
draggable.classList.add('dragging');
|
||||
|
@ -100,13 +100,13 @@ describe('Travel Component vnTravelExtraCommunity', () => {
|
|||
|
||||
describe('onDrop()', () => {
|
||||
it('should make an HTTP patch query', () => {
|
||||
const droppable = document.createElement('vn-tbody');
|
||||
const droppable = document.createElement('tbody');
|
||||
droppable.setAttribute('vn-droppable', true);
|
||||
droppable.setAttribute('id', 1);
|
||||
|
||||
jest.spyOn(controller, 'findDroppable').mockReturnValue(droppable);
|
||||
|
||||
const oldDroppable = document.createElement('vn-tbody');
|
||||
const oldDroppable = document.createElement('tbody');
|
||||
oldDroppable.setAttribute('vn-droppable', true);
|
||||
const entry = document.createElement('div');
|
||||
oldDroppable.appendChild(entry);
|
||||
|
|
|
@ -15,41 +15,44 @@ vn-travel-extra-community {
|
|||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
vn-td-editable text {
|
||||
background-color: transparent;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
border-bottom: 1px dashed $color-active;
|
||||
border-radius: 0;
|
||||
color: $color-active
|
||||
}
|
||||
|
||||
vn-td-editable:hover text:after {
|
||||
font-family: 'Material Icons';
|
||||
content: 'edit';
|
||||
position: absolute;
|
||||
right: -15px;
|
||||
color: $color-spacer
|
||||
}
|
||||
|
||||
vn-table[vn-droppable] {
|
||||
table[vn-droppable] {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
a[draggable] {
|
||||
tr[draggable] {
|
||||
transition: all .5s;
|
||||
cursor: move;
|
||||
overflow: auto;
|
||||
outline: 0;
|
||||
height: 65px;
|
||||
pointer-events: fill;
|
||||
user-select:all;
|
||||
}
|
||||
|
||||
a[draggable]:hover {
|
||||
background-color: $color-hover-cd
|
||||
tr[draggable] *::selection{
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
a[draggable].dragging {
|
||||
background-color: $color-success-light;
|
||||
font-weight:bold
|
||||
tr[draggable]:hover {
|
||||
background-color: $color-hover-cd;
|
||||
}
|
||||
|
||||
tr[draggable].dragging {
|
||||
background-color: $color-primary-light;
|
||||
color: $color-font-light;
|
||||
font-weight:bold;
|
||||
}
|
||||
|
||||
.td-editable{
|
||||
input{
|
||||
font-size: 1.25rem!important;
|
||||
}
|
||||
}
|
||||
|
||||
.number *{
|
||||
text-align: right;
|
||||
}
|
||||
}
|
|
@ -33,7 +33,7 @@ describe('Worker absences()', () => {
|
|||
const worker = await app.models.WorkerLabour.findById(businessId, null, options);
|
||||
|
||||
await app.models.WorkerLabour.rawSql(
|
||||
`UPDATE postgresql.business SET date_end = ? WHERE business_id = ?`,
|
||||
`UPDATE vn.business SET ended = ? WHERE id = ?`,
|
||||
[null, worker.businessFk], options);
|
||||
|
||||
const [absences] = await app.models.Calendar.absences(ctx, worker.id, businessId, year, options);
|
||||
|
@ -98,7 +98,7 @@ describe('Worker absences()', () => {
|
|||
startingContract.setDate(1);
|
||||
|
||||
await app.models.WorkerLabour.rawSql(
|
||||
`UPDATE postgresql.business SET date_start = ?, date_end = ? WHERE business_id = ?`,
|
||||
`UPDATE vn.business SET started = ?, ended = ? WHERE id = ?`,
|
||||
[startingContract, yearEnd, contract.businessFk], options
|
||||
);
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ module.exports = Self => {
|
|||
},
|
||||
http: {
|
||||
path: `/checkInbox`,
|
||||
verb: 'GET'
|
||||
verb: 'POST'
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -58,8 +58,8 @@ module.exports = Self => {
|
|||
emailBody = bufferCopy.toUpperCase().trim();
|
||||
|
||||
const bodyPositionOK = emailBody.match(/\bOK\b/i);
|
||||
|
||||
if (bodyPositionOK != null && (bodyPositionOK.index == 0 || bodyPositionOK.index == 122))
|
||||
const bodyPositionIndex = (bodyPositionOK.index == 0 || bodyPositionOK.index == 122);
|
||||
if (bodyPositionOK != null && bodyPositionIndex)
|
||||
isEmailOk = true;
|
||||
else
|
||||
isEmailOk = false;
|
||||
|
|
|
@ -86,10 +86,9 @@ module.exports = Self => {
|
|||
const [result] = await Self.rawSql(
|
||||
`SELECT COUNT(*) halfHolidayCounter
|
||||
FROM vn.calendar c
|
||||
JOIN postgresql.business b ON b.business_id = c.businessFk
|
||||
JOIN postgresql.profile p ON p.profile_id = b.client_id
|
||||
JOIN vn.business b ON b.id = c.businessFk
|
||||
WHERE c.dayOffTypeFk = 6
|
||||
AND p.workerFk = ?
|
||||
AND b.workerFk = ?
|
||||
AND c.dated BETWEEN util.firstDayOfYear(?)
|
||||
AND LAST_DAY(DATE_ADD(?, INTERVAL 12 - MONTH(?) MONTH))`, [id, date, now, now]);
|
||||
|
||||
|
|
|
@ -20,9 +20,6 @@
|
|||
"EducationLevel": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"Sector": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"WorkCenter": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
{
|
||||
"name": "Sector",
|
||||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "sector"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "number",
|
||||
"id": true,
|
||||
"description": "Identifier"
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"required": true
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,10 @@
|
|||
{
|
||||
"name": "ZoneExclusion",
|
||||
"base": "VnModel",
|
||||
"base": "Loggable",
|
||||
"log": {
|
||||
"model":"ZoneLog",
|
||||
"relation": "zone"
|
||||
},
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "zoneExclusion"
|
||||
|
|
|
@ -91,7 +91,7 @@
|
|||
</vn-data-viewer>
|
||||
</vn-side-menu>
|
||||
<vn-float-button
|
||||
ng-click="$ctrl.create('weekday')"
|
||||
ng-click="$ctrl.createInclusion('weekday')"
|
||||
icon="add"
|
||||
vn-tooltip="Add event"
|
||||
vn-bind="+"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "salix-back",
|
||||
"version": "8.6.0",
|
||||
"version": "8.8.0",
|
||||
"author": "Verdnatura Levante SL",
|
||||
"description": "Salix backend",
|
||||
"license": "GPL-3.0",
|
||||
|
@ -22,6 +22,7 @@
|
|||
"i18n": "^0.8.4",
|
||||
"image-type": "^4.1.0",
|
||||
"imap": "^0.8.19",
|
||||
"jsdom": "^16.7.0",
|
||||
"jszip": "^3.10.0",
|
||||
"ldapjs": "^2.2.0",
|
||||
"loopback": "^3.26.0",
|
||||
|
@ -36,7 +37,7 @@
|
|||
"node-ssh": "^11.0.0",
|
||||
"object-diff": "0.0.4",
|
||||
"object.pick": "^1.3.0",
|
||||
"puppeteer": "^7.1.0",
|
||||
"puppeteer": "^18.0.5",
|
||||
"read-chunk": "^3.2.0",
|
||||
"require-yaml": "0.0.1",
|
||||
"sharp": "^0.27.1",
|
||||
|
|
|
@ -29,7 +29,7 @@ module.exports = {
|
|||
for (let attachment of options.attachments) {
|
||||
const fileName = attachment.filename;
|
||||
const filePath = attachment.path;
|
||||
if (fileName.includes('.png')) return;
|
||||
if (fileName.includes('.png')) continue;
|
||||
|
||||
if (fileName || filePath)
|
||||
attachments.push(filePath ? filePath : fileName);
|
||||
|
|
|
@ -3,13 +3,24 @@ const closure = require('./closure');
|
|||
|
||||
module.exports = async function(request, response, next) {
|
||||
try {
|
||||
const reqArgs = request.query;
|
||||
if (!reqArgs.to)
|
||||
throw new Error('The argument to is required');
|
||||
const reqArgs = request.body;
|
||||
|
||||
response.status(200).json({
|
||||
message: 'Success'
|
||||
});
|
||||
let toDate = new Date();
|
||||
toDate.setDate(toDate.getDate() - 1);
|
||||
|
||||
if (reqArgs.to) toDate = reqArgs.to;
|
||||
|
||||
const todayMinDate = new Date();
|
||||
todayMinDate.setHours(0, 0, 0, 0);
|
||||
|
||||
const todayMaxDate = new Date();
|
||||
todayMinDate.setHours(23, 59, 59, 59);
|
||||
|
||||
// Prevent closure for current day
|
||||
if (toDate >= todayMinDate && toDate <= todayMaxDate)
|
||||
throw new Error('You cannot close tickets for today');
|
||||
|
||||
console.log(`Making closure up to ${toDate}...`);
|
||||
|
||||
const tickets = await db.rawSql(`
|
||||
SELECT
|
||||
|
@ -36,7 +47,7 @@ module.exports = async function(request, response, next) {
|
|||
AND DATE(t.shipped) BETWEEN DATE_ADD(?, INTERVAL -2 DAY)
|
||||
AND util.dayEnd(?)
|
||||
AND t.refFk IS NULL
|
||||
GROUP BY t.id`, [reqArgs.to, reqArgs.to]);
|
||||
GROUP BY t.id`, [toDate, toDate]);
|
||||
|
||||
await closure.start(tickets, response.locals);
|
||||
|
||||
|
@ -52,7 +63,11 @@ module.exports = async function(request, response, next) {
|
|||
AND util.dayEnd(?)
|
||||
AND al.code NOT IN('DELIVERED','PACKED')
|
||||
AND t.routeFk
|
||||
AND z.name LIKE '%MADRID%'`, [reqArgs.to, reqArgs.to]);
|
||||
AND z.name LIKE '%MADRID%'`, [toDate, toDate]);
|
||||
|
||||
response.status(200).json({
|
||||
message: 'Success'
|
||||
});
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ const closure = require('./closure');
|
|||
|
||||
module.exports = async function(request, response, next) {
|
||||
try {
|
||||
const reqArgs = request.query;
|
||||
const reqArgs = request.body;
|
||||
|
||||
if (!reqArgs.agencyModeId)
|
||||
throw new Error('The argument agencyModeId is required');
|
||||
|
@ -14,10 +14,6 @@ module.exports = async function(request, response, next) {
|
|||
if (!reqArgs.to)
|
||||
throw new Error('The argument to is required');
|
||||
|
||||
response.status(200).json({
|
||||
message: 'Success'
|
||||
});
|
||||
|
||||
const agencyIds = reqArgs.agencyModeId.split(',');
|
||||
const tickets = await db.rawSql(`
|
||||
SELECT
|
||||
|
@ -53,6 +49,10 @@ module.exports = async function(request, response, next) {
|
|||
]);
|
||||
|
||||
await closure.start(tickets, response.locals);
|
||||
|
||||
response.status(200).json({
|
||||
message: 'Success'
|
||||
});
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
|
|
|
@ -4,15 +4,11 @@ const closure = require('./closure');
|
|||
|
||||
module.exports = async function(request, response, next) {
|
||||
try {
|
||||
const reqArgs = request.query;
|
||||
const reqArgs = request.body;
|
||||
|
||||
if (!reqArgs.routeId)
|
||||
throw new Error('The argument routeId is required');
|
||||
|
||||
response.status(200).json({
|
||||
message: 'Success'
|
||||
});
|
||||
|
||||
const tickets = await db.rawSql(`
|
||||
SELECT
|
||||
t.id,
|
||||
|
@ -56,6 +52,10 @@ module.exports = async function(request, response, next) {
|
|||
const email = new Email('driver-route', args);
|
||||
await email.send();
|
||||
}
|
||||
|
||||
response.status(200).json({
|
||||
message: 'Success'
|
||||
});
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
|
|
|
@ -3,15 +3,11 @@ const closure = require('./closure');
|
|||
|
||||
module.exports = async function(request, response, next) {
|
||||
try {
|
||||
const reqArgs = request.query;
|
||||
const reqArgs = request.body;
|
||||
|
||||
if (!reqArgs.ticketId)
|
||||
throw new Error('The argument ticketId is required');
|
||||
|
||||
response.status(200).json({
|
||||
message: 'Success'
|
||||
});
|
||||
|
||||
const tickets = await db.rawSql(`
|
||||
SELECT
|
||||
t.id,
|
||||
|
@ -38,6 +34,10 @@ module.exports = async function(request, response, next) {
|
|||
GROUP BY e.ticketFk`, [reqArgs.ticketId]);
|
||||
|
||||
await closure.start(tickets, response.locals);
|
||||
|
||||
response.status(200).json({
|
||||
message: 'Success'
|
||||
});
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
|
|
|
@ -7,11 +7,13 @@ const storage = require('vn-print/core/storage');
|
|||
|
||||
module.exports = {
|
||||
async start(tickets, reqArgs) {
|
||||
console.log(tickets);
|
||||
if (tickets.length == 0) return;
|
||||
|
||||
const failedtickets = [];
|
||||
for (const ticket of tickets) {
|
||||
try {
|
||||
console.log(`Closing ticket id ${ticket.id}...`);
|
||||
await db.rawSql(`CALL vn.ticket_closeByTicket(?)`, [ticket.id]);
|
||||
|
||||
const invoiceOut = await db.findOne(`
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
const express = require('express');
|
||||
const router = new express.Router();
|
||||
|
||||
router.get('/all', require('./closeAll'));
|
||||
router.get('/by-ticket', require('./closeByTicket'));
|
||||
router.get('/by-agency', require('./closeByAgency'));
|
||||
router.get('/by-route', require('./closeByRoute'));
|
||||
router.post('/all', require('./closeAll'));
|
||||
router.post('/by-ticket', require('./closeByTicket'));
|
||||
router.post('/by-agency', require('./closeByAgency'));
|
||||
router.post('/by-route', require('./closeByRoute'));
|
||||
|
||||
module.exports = router;
|
||||
|
|
|
@ -1,17 +1,18 @@
|
|||
SELECT
|
||||
e.id,
|
||||
e.travelFk,
|
||||
e.ref,
|
||||
s.name AS supplierName,
|
||||
SUM(b.stickers) AS stickers,
|
||||
CAST(SUM(i.density * b.stickers * IF(pkg.volume, pkg.volume, pkg.width * pkg.depth * pkg.height) / 1000000 ) as DECIMAL(10,0)) as loadedKg,
|
||||
CAST(SUM(167.5 * b.stickers * IF(pkg.volume, pkg.volume, pkg.width * pkg.depth * pkg.height) / 1000000 ) as DECIMAL(10,0)) as volumeKg
|
||||
FROM travel t
|
||||
JOIN entry e ON e.travelFk = t.id
|
||||
JOIN buy b ON b.entryFk = e.id
|
||||
JOIN packaging pkg ON pkg.id = b.packageFk
|
||||
JOIN item i ON i.id = b.itemFk
|
||||
JOIN itemType it ON it.id = i.typeFk
|
||||
JOIN supplier s ON s.id = e.supplierFk
|
||||
WHERE t.id IN(?)
|
||||
GROUP BY e.id
|
||||
e.id,
|
||||
e.travelFk,
|
||||
e.ref,
|
||||
s.name AS supplierName,
|
||||
SUM(b.stickers) AS stickers,
|
||||
CAST(SUM(b.weight * b.stickers) as DECIMAL(10,0)) as loadedKg,
|
||||
CAST(SUM(vc.aerealVolumetricDensity * b.stickers * IF(pkg.volume, pkg.volume, pkg.width * pkg.depth * pkg.height) / 1000000) as DECIMAL(10,0)) as volumeKg
|
||||
FROM travel t
|
||||
JOIN entry e ON e.travelFk = t.id
|
||||
JOIN buy b ON b.entryFk = e.id
|
||||
JOIN packaging pkg ON pkg.id = b.packageFk
|
||||
JOIN item i ON i.id = b.itemFk
|
||||
JOIN itemType it ON it.id = i.typeFk
|
||||
JOIN supplier s ON s.id = e.supplierFk
|
||||
JOIN vn.volumeConfig vc
|
||||
WHERE t.id IN(?)
|
||||
GROUP BY e.id
|
|
@ -6,9 +6,10 @@ SELECT
|
|||
t.kg,
|
||||
am.id AS agencyModeFk,
|
||||
SUM(b.stickers) AS stickers,
|
||||
CAST(SUM(i.density * b.stickers * IF(pkg.volume, pkg.volume, pkg.width * pkg.depth * pkg.height) / 1000000 ) as DECIMAL(10,0)) as loadedKg,
|
||||
CAST(SUM(167.5 * b.stickers * IF(pkg.volume, pkg.volume, pkg.width * pkg.depth * pkg.height) / 1000000 ) as DECIMAL(10,0)) as volumeKg
|
||||
CAST(SUM(b.weight * b.stickers) as DECIMAL(10,0)) as loadedKg,
|
||||
CAST(SUM(vc.aerealVolumetricDensity * b.stickers * IF(pkg.volume, pkg.volume, pkg.width * pkg.depth * pkg.height) / 1000000) as DECIMAL(10,0)) as volumeKg
|
||||
FROM travel t
|
||||
JOIN volumeConfig vc
|
||||
LEFT JOIN supplier s ON s.id = t.cargoSupplierFk
|
||||
LEFT JOIN entry e ON e.travelFk = t.id
|
||||
LEFT JOIN buy b ON b.entryFk = e.id
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
const Stylesheet = require(`${appPath}/core/stylesheet`);
|
||||
|
||||
module.exports = new Stylesheet([
|
||||
`${appPath}/common/css/spacing.css`,
|
||||
`${appPath}/common/css/misc.css`,
|
||||
`${appPath}/common/css/layout.css`,
|
||||
`${appPath}/common/css/report.css`,
|
||||
`${__dirname}/style.css`])
|
||||
.mergeStyles();
|
|
@ -0,0 +1,19 @@
|
|||
.column-oriented {
|
||||
margin-top: 50px !important;
|
||||
}
|
||||
|
||||
.bottom-line > tr {
|
||||
border-bottom: 1px solid #ccc;
|
||||
}
|
||||
|
||||
.bottom-line tr:nth-last-child() {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.report-info {
|
||||
font-size: 20px
|
||||
}
|
||||
|
||||
.description strong {
|
||||
text-transform: uppercase;
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
title: Expiración Tarjetas Vehículos
|
||||
Plate: Matrícula
|
||||
Concept: Concepto
|
||||
expirationDate: Fecha caducidad
|
|
@ -0,0 +1,7 @@
|
|||
SELECT
|
||||
v.numberPlate,
|
||||
ve.description,
|
||||
ve.finished
|
||||
FROM vehicleEvent ve
|
||||
JOIN vehicle v ON v.id = ve.vehicleFk
|
||||
WHERE ve.id IN (?)
|
|
@ -0,0 +1,39 @@
|
|||
<!DOCTYPE html>
|
||||
<html v-bind:lang="$i18n.locale">
|
||||
<body>
|
||||
<table class="grid">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<!-- Header block -->
|
||||
<report-header v-bind="$props"></report-header>
|
||||
<!-- Block -->
|
||||
<div class="grid-row">
|
||||
<div class="grid-block">
|
||||
<div class="content">
|
||||
<h1 class="title centered uppercase">{{$t('title')}}</h1>
|
||||
</div>
|
||||
<table class="column-oriented">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{$t('Plate')}}</th>
|
||||
<th>{{$t('Concept')}}</th>
|
||||
<th>{{$t('expirationDate')}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody v-for="vehicleEvent in vehicleEvents">
|
||||
<tr>
|
||||
<td>{{vehicleEvent.numberPlate}}</td>
|
||||
<td>{{vehicleEvent.description}}</td>
|
||||
<td>{{vehicleEvent.finished | date('%d-%m-%Y')}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,28 @@
|
|||
const Component = require(`${appPath}/core/component`);
|
||||
const reportHeader = new Component('report-header');
|
||||
const reportFooter = new Component('report-footer');
|
||||
|
||||
module.exports = {
|
||||
name: 'vehicle-event-expired',
|
||||
async serverPrefetch() {
|
||||
this.vehicleEvents = await this.fetchVehicleEvent(this.eventIds);
|
||||
|
||||
if (!this.vehicleEvents)
|
||||
throw new Error('Something went wrong');
|
||||
},
|
||||
methods: {
|
||||
fetchVehicleEvent(vehicleEventIds) {
|
||||
return this.rawSqlFromDef('vehicleEvents', [vehicleEventIds]);
|
||||
},
|
||||
},
|
||||
components: {
|
||||
'report-header': reportHeader.build(),
|
||||
'report-footer': reportFooter.build()
|
||||
},
|
||||
props: {
|
||||
eventIds: {
|
||||
type: [Array],
|
||||
required: true
|
||||
}
|
||||
}
|
||||
};
|
Loading…
Reference in New Issue