Merge branch 'dev' into 6434-signIn_issue
gitea/salix/pipeline/head There was a failure building this commit Details

This commit is contained in:
Javier Segarra 2023-12-19 07:06:36 +00:00
commit 5151cdca48
22 changed files with 286 additions and 172 deletions

View File

@ -11,6 +11,9 @@
"[javascript]": {
"editor.defaultFormatter": "dbaeumer.vscode-eslint"
},
"[json]": {
"editor.defaultFormatter": "vscode.json-language-features"
},
"cSpell.words": [
"salix",
"fdescribe"

View File

@ -22,8 +22,8 @@ module.exports = Self => {
Self.removeFile = async(ctx, id, options) => {
const models = Self.app.models;
let tx;
const myOptions = {};
let tx;
if (typeof options == 'object')
Object.assign(myOptions, options);

View File

@ -0,0 +1,46 @@
DELIMITER $$
CREATE OR REPLACE DEFINER=`root`@`localhost` TRIGGER `vn`.`delivery_beforeInsert`
BEFORE INSERT ON `delivery`
FOR EACH ROW
BEGIN
IF (NEW.longitude IS NOT NULL AND NEW.latitude IS NOT NULL AND NEW.ticketFK IS NOT NULL)
THEN
UPDATE address
SET longitude = NEW.longitude,
latitude = NEW.latitude
WHERE id IN (
SELECT addressFK
FROM ticket
WHERE id = NEW.ticketFk
);
END IF;
END$$
DELIMITER ;
DELIMITER $$
CREATE OR REPLACE DEFINER=`root`@`localhost` TRIGGER `vn`.`delivery_beforeUpdate`
BEFORE UPDATE ON `delivery`
FOR EACH ROW
BEGIN
IF (NEW.longitude IS NOT NULL AND NEW.latitude IS NOT NULL AND NEW.ticketFK IS NOT NULL)
THEN
UPDATE address
SET longitude = NEW.longitude,
latitude = NEW.latitude
WHERE id IN (
SELECT addressFK
FROM ticket
WHERE id = NEW.ticketFk
);
END IF;
END$$
DELIMITER ;
ALTER TABLE `vn`.`address` MODIFY COLUMN longitude decimal(11,7) DEFAULT NULL NULL COMMENT 'Indica la última longitud proporcionada por tabla delivery';
ALTER TABLE `vn`.`address` MODIFY COLUMN latitude decimal(11,7) DEFAULT NULL NULL COMMENT 'Indica la última latitud proporcionada por tabla delivery';

View File

@ -26,7 +26,7 @@ describe('Route create path', () => {
await page.waitToClick(selectors.createRouteView.submitButton);
const message = await page.waitForSnackbar();
expect(message.text).toContain('Access denied');
expect(message.text).toContain('Access Denied');
});
});

View File

@ -3,4 +3,4 @@ Could not contact the server: Could not contact the server, make sure you have a
Please enter your username: Please enter your username
It seems that the server has fall down: It seems that the server has fall down, wait a few minutes and try again
Session has expired: Your session has expired, please login again
Access denied: Access denied
Access Denied: Access Denied

View File

@ -3,5 +3,5 @@ Could not contact the server: No se ha podido contactar con el servidor, asegura
Please enter your username: Por favor introduce tu nombre de usuario
It seems that the server has fall down: Parece que el servidor se ha caído, espera unos minutos e inténtalo de nuevo
Session has expired: Tu sesión ha expirado, por favor vuelve a iniciar sesión
Access denied: Acción no permitida
Access Denied: Acción no permitida
Direction not found: Dirección no encontrada

View File

@ -120,7 +120,7 @@ function $exceptionHandler(vnApp, $window, $state, $injector) {
messageT = 'Invalid login';
break;
case 403:
messageT = exception.data?.error?.message || 'Access denied';
messageT = exception.data?.error?.message || 'Access Denied';
break;
case 502:
messageT = 'It seems that the server has fall down';

View File

@ -1,3 +1,5 @@
const UserError = require('vn-loopback/util/user-error');
module.exports = Self => {
Self.remoteMethodCtx('removeFile', {
description: 'Removes a claim document',
@ -19,8 +21,8 @@ module.exports = Self => {
});
Self.removeFile = async(ctx, id, options) => {
let tx;
const myOptions = {};
let tx;
if (typeof options == 'object')
Object.assign(myOptions, options);
@ -31,19 +33,18 @@ module.exports = Self => {
}
try {
const models = Self.app.models;
const targetClaimDms = await models.ClaimDms.findById(id, null, myOptions);
const targetDms = await models.Dms.findById(targetClaimDms.dmsFk, null, myOptions);
const trashDmsType = await models.DmsType.findOne({where: {code: 'trash'}}, myOptions);
const claimDms = await Self.findById(id, null, myOptions);
await models.Dms.removeFile(ctx, targetClaimDms.dmsFk, myOptions);
await targetClaimDms.destroy(myOptions);
const targetDms = await Self.app.models.Dms.removeFile(ctx, claimDms.dmsFk, myOptions);
await targetDms.updateAttribute('dmsTypeFk', trashDmsType.id, myOptions);
if (!targetDms || ! claimDms)
throw new UserError('Try again');
const claimDmsDestroyed = await claimDms.destroy(myOptions);
if (tx) await tx.commit();
return targetDms;
return claimDmsDestroyed;
} catch (e) {
if (tx) await tx.rollback();
throw e;

View File

@ -1,6 +1,3 @@
const UserError = require('vn-loopback/util/user-error');
const fs = require('fs-extra');
const path = require('path');
module.exports = Self => {
Self.remoteMethodCtx('uploadFile', {
@ -57,96 +54,33 @@ module.exports = Self => {
});
Self.uploadFile = async(ctx, id, options) => {
const tx = await Self.beginTransaction({});
const {Dms, ClaimDms} = Self.app.models;
const myOptions = {};
let tx;
if (typeof options == 'object')
Object.assign(myOptions, options);
if (!myOptions.transaction)
if (!myOptions.transaction) {
tx = await Self.beginTransaction({});
myOptions.transaction = tx;
const models = Self.app.models;
const promises = [];
const TempContainer = models.TempContainer;
const ClaimContainer = models.ClaimContainer;
const fileOptions = {};
const args = ctx.args;
let srcFile;
try {
const hasWriteRole = await models.DmsType.hasWriteRole(ctx, args.dmsTypeId, myOptions);
if (!hasWriteRole)
throw new UserError(`You don't have enough privileges`);
// Upload file to temporary path
const tempContainer = await TempContainer.container('dms');
const uploaded = await TempContainer.upload(tempContainer.name, ctx.req, ctx.result, fileOptions);
const files = Object.values(uploaded.files).map(file => {
return file[0];
});
const addedDms = [];
for (const uploadedFile of files) {
const newDms = await createDms(ctx, uploadedFile, myOptions);
const pathHash = ClaimContainer.getHash(newDms.id);
const file = await TempContainer.getFile(tempContainer.name, uploadedFile.name);
srcFile = path.join(file.client.root, file.container, file.name);
const claimContainer = await ClaimContainer.container(pathHash);
const dstFile = path.join(claimContainer.client.root, pathHash, newDms.file);
await fs.move(srcFile, dstFile, {
overwrite: true
});
addedDms.push(newDms);
}
addedDms.forEach(dms => {
const newClaimDms = models.ClaimDms.create({
try {
const uploadedFiles = await Dms.uploadFile(ctx, myOptions);
const promises = uploadedFiles.map(dms => ClaimDms.create({
claimFk: id,
dmsFk: dms.id
}, myOptions);
promises.push(newClaimDms);
});
const resolvedPromises = await Promise.all(promises);
}, myOptions));
await Promise.all(promises);
if (tx) await tx.commit();
return resolvedPromises;
return uploadedFiles;
} catch (e) {
if (tx) await tx.rollback();
if (fs.existsSync(srcFile))
await fs.unlink(srcFile);
throw e;
}
};
async function createDms(ctx, file, myOptions) {
const models = Self.app.models;
const myUserId = ctx.req.accessToken.userId;
const args = ctx.args;
const newDms = await models.Dms.create({
workerFk: myUserId,
dmsTypeFk: args.dmsTypeId,
companyFk: args.companyId,
warehouseFk: args.warehouseId,
reference: args.reference,
description: args.description,
contentType: file.type,
hasFile: args.hasFile
}, myOptions);
let fileName = file.name;
const extension = models.DmsContainer.getFileExtension(fileName);
fileName = `${newDms.id}.${extension}`;
return newDms.updateAttribute('file', fileName, myOptions);
}
};

View File

@ -19,9 +19,8 @@ module.exports = Self => {
});
Self.removeFile = async(ctx, id, options) => {
const models = Self.app.models;
let tx;
const myOptions = {};
let tx;
if (typeof options == 'object')
Object.assign(myOptions, options);
@ -34,13 +33,16 @@ module.exports = Self => {
try {
const clientDms = await Self.findById(id, null, myOptions);
await models.Dms.removeFile(ctx, clientDms.dmsFk, myOptions);
const targetDms = await Self.app.models.Dms.removeFile(ctx, clientDms.dmsFk, myOptions);
const destroyedClient = await clientDms.destroy(myOptions);
if (!targetDms || !clientDms)
throw new UserError('Try again');
const clientDmsDestroyed = await clientDms.destroy(myOptions);
if (tx) await tx.commit();
return destroyedClient;
return clientDmsDestroyed;
} catch (e) {
if (tx) await tx.rollback();
throw e;

View File

@ -107,17 +107,29 @@ module.exports = Self => {
return {or: [
{'c.phone': {like: `%${value}%`}},
{'c.mobile': {like: `%${value}%`}},
{'a.phone': {like: `%${value}%`}},
]};
case 'zoneFk':
param = 'a.postalCode';
return {[param]: {inq: postalCode}};
return {'a.postalCode': {inq: postalCode}};
case 'city':
return {or: [
{'c.city': {like: `%${value}%`}},
{'a.city': {like: `%${value}%`}}
]};
case 'postcode':
return {or: [
{'c.postcode': value},
{'a.postalCode': value}
]};
case 'provinceFk':
return {or: [
{'p.id': value},
{'a.provinceFk': value}
]};
case 'name':
case 'salesPersonFk':
case 'fi':
case 'socialName':
case 'city':
case 'postcode':
case 'provinceFk':
case 'email':
param = `c.${param}`;
return {[param]: {like: `%${value}%`}};
@ -134,24 +146,29 @@ module.exports = Self => {
c.fi,
c.socialName,
c.phone,
a.phone,
c.mobile,
c.city,
a.city,
c.postcode,
a.postalCode,
c.email,
c.isActive,
c.isFreezed,
p.id AS provinceFk,
p.id AS provinceClientFk,
a.provinceFk AS provinceAddressFk,
p.name AS province,
u.id AS salesPersonFk,
u.name AS salesPerson
FROM client c
LEFT JOIN account.user u ON u.id = c.salesPersonFk
LEFT JOIN province p ON p.id = c.provinceFk
JOIN vn.address a ON a.clientFk = c.id
JOIN address a ON a.clientFk = c.id
`
);
stmt.merge(conn.makeWhere(filter.where));
stmt.merge('GROUP BY c.id');
stmt.merge(conn.makePagination(filter));
const clientsIndex = stmts.push(stmt) - 1;

View File

@ -55,9 +55,9 @@ module.exports = Self => {
});
Self.uploadFile = async(ctx, id, options) => {
const models = Self.app.models;
let tx;
const {Dms, ClientDms} = Self.app.models;
const myOptions = {};
let tx;
if (typeof options == 'object')
Object.assign(myOptions, options);
@ -67,23 +67,20 @@ module.exports = Self => {
myOptions.transaction = tx;
}
const promises = [];
try {
const uploadedFiles = await models.Dms.uploadFile(ctx, myOptions);
uploadedFiles.forEach(dms => {
const newClientDms = models.ClientDms.create({
const uploadedFiles = await Dms.uploadFile(ctx, myOptions);
const promises = uploadedFiles.map(dms =>
ClientDms.create({
clientFk: id,
dmsFk: dms.id
}, myOptions);
}, myOptions)
promises.push(newClientDms);
});
const resolvedPromises = await Promise.all(promises);
);
await Promise.all(promises);
if (tx) await tx.commit();
return resolvedPromises;
return uploadedFiles;
} catch (e) {
if (tx) await tx.rollback();
throw e;

View File

@ -62,7 +62,7 @@
<vn-worker-autocomplete
vn-one
ng-model="$ctrl.client.salesPersonFk"
departments="['VT']"
departments="['VT', 'shopping']"
show-field="nickname"
label="Salesperson"
vn-acl="salesAssistant">

View File

@ -0,0 +1,64 @@
module.exports = Self => {
Self.remoteMethod('getExpeditionSummary', {
description: 'Get summary of expeditions for a given route',
accepts: [
{
arg: 'routeFk',
type: 'number',
required: true,
description: 'Foreign key for Route'
}
],
returns: {
type: 'object',
root: true
},
http: {
path: '/getExpeditionSummary',
verb: 'get'
}
});
Self.getExpeditionSummary = async(routeFk, options) => {
const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
const query = `
SELECT routeFk,
addressFk,
SUM(total) total,
SUM(delivery) delivery,
SUM(lost) lost,
SUM(delivered) delivered,
GROUP_CONCAT(totalPacking ORDER BY total DESC SEPARATOR ' ') itemPackingType
FROM (
SELECT r.id AS routeFk,
t.addressFk,
CONCAT (IFNULL(e.itemPackingTypeFk,'-'), '', COUNT(*)) totalPacking,
COUNT(*) total,
SUM(est.code = 'ON DELIVERY') delivery,
SUM(est.code = 'LOST') lost,
SUM(est.code = 'DELIVERED') delivered,
t.priority
FROM vn.ticket t
JOIN vn.route r ON r.id = t.routeFk
JOIN vn.expedition e ON e.ticketFk = t.id
LEFT JOIN vn.expeditionStateType est ON est.id = e.stateTypeFk
JOIN vn.agencyMode am ON am.id = r.agencyModeFk
JOIN vn.agency ag ON ag.id = am.agencyFk
LEFT JOIN vn.userConfig uc ON uc.userFk = account.myUser_getId()
WHERE (r.created = util.VN_CURDATE() OR r.created = util.yesterday())
AND t.routeFk = ?
GROUP BY t.addressFk, e.itemPackingTypeFk
) sub
GROUP BY addressFk
ORDER BY priority DESC
`;
const results = await Self.rawSql(query, [routeFk], myOptions);
return results;
};
};

View File

@ -3,7 +3,7 @@ const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
module.exports = Self => {
Self.remoteMethod('getTickets', {
description: 'Return the tickets information displayed on the route module',
description: 'Find all instances of the model matched by filter from the data source.',
accessType: 'READ',
accepts: [
{
@ -40,22 +40,32 @@ module.exports = Self => {
t.clientFk,
t.priority,
t.addressFk,
st.code AS ticketStateCode,
st.name AS ticketStateName,
wh.name AS warehouseName,
tob.description AS ticketObservation,
st.code ticketStateCode,
st.name ticketStateName,
wh.name warehouseName,
tob.description ticketObservation,
a.street,
a.postalCode,
a.city,
am.name AS agencyModeName,
u.nickname AS userNickname,
vn.ticketTotalVolume(t.id) AS volume,
am.name agencyModeName,
u.nickname userNickname,
vn.ticketTotalVolume(t.id) volume,
tob.description,
GROUP_CONCAT(DISTINCT i.itemPackingTypeFk ORDER BY i.itemPackingTypeFk) ipt
GROUP_CONCAT(DISTINCT i.itemPackingTypeFk ORDER BY i.itemPackingTypeFk) ipt,
c.phone clientPhone,
c.mobile clientMobile,
a.phone addressPhone,
a.mobile addressMobile,
a.longitude,
a.latitude,
wm.mediaValue salePersonPhone,
t.cmrFk,
t.isSigned signed
FROM vn.route r
JOIN ticket t ON t.routeFk = r.id
JOIN vn.sale s ON s.ticketFk = t.id
JOIN vn.item i ON i.id = s.itemFk
JOIN client c ON t.clientFk = c.id
LEFT JOIN vn.sale s ON s.ticketFk = t.id
LEFT JOIN vn.item i ON i.id = s.itemFk
LEFT JOIN ticketState ts ON ts.ticketFk = t.id
LEFT JOIN state st ON st.id = ts.stateFk
LEFT JOIN warehouse wh ON wh.id = t.warehouseFk
@ -65,7 +75,8 @@ module.exports = Self => {
LEFT JOIN address a ON a.id = t.addressFk
LEFT JOIN agencyMode am ON am.id = t.agencyModeFk
LEFT JOIN account.user u ON u.id = r.workerFk
LEFT JOIN vehicle v ON v.id = r.vehicleFk`
LEFT JOIN vehicle v ON v.id = r.vehicleFk
LEFT JOIN workerMedia wm ON wm.workerFk = c.salesPersonFk`
);
if (!filter.where) filter.where = {};

View File

@ -0,0 +1,10 @@
const app = require('vn-loopback/server/server');
describe('route getExpeditionSummary()', () => {
const routeId = 1;
it('should return a summary of expeditions for a route', async() => {
const result = await app.models.Route.getExpeditionSummary(routeId);
expect(result.every(route => route.id = routeId)).toBeTruthy();
});
});

View File

@ -17,6 +17,7 @@ module.exports = Self => {
require('../methods/route/cmr')(Self);
require('../methods/route/getExternalCmrs')(Self);
require('../methods/route/downloadCmrsZip')(Self);
require('../methods/route/getExpeditionSummary')(Self);
require('../methods/route/getByWorker')(Self);
Self.validate('kmStart', validateDistance, {

View File

@ -19,7 +19,6 @@ module.exports = Self => {
});
Self.removeFile = async(ctx, id, options) => {
const models = Self.app.models;
const myOptions = {};
let tx;
@ -32,18 +31,18 @@ module.exports = Self => {
}
try {
const targetTicketDms = await models.TicketDms.findById(id, null, myOptions);
const targetDms = await models.Dms.findById(targetTicketDms.dmsFk, null, myOptions);
const trashDmsType = await models.DmsType.findOne({where: {code: 'trash'}}, myOptions);
const ticketDms = await Self.findById(id, null, myOptions);
await models.Dms.removeFile(ctx, targetTicketDms.dmsFk, myOptions);
await targetTicketDms.destroy(myOptions);
const targetDms = await Self.app.models.Dms.removeFile(ctx, ticketDms.dmsFk, myOptions);
await targetDms.updateAttribute('dmsTypeFk', trashDmsType.id, myOptions);
if (!targetDms || !ticketDms)
throw new UserError('Try again');
const ticketDmsDestroyed = await ticketDms.destroy(myOptions);
if (tx) await tx.commit();
return targetDms;
return ticketDmsDestroyed;
} catch (e) {
if (tx) await tx.rollback();
throw e;

View File

@ -47,7 +47,7 @@ module.exports = Self => {
});
Self.uploadFile = async(ctx, id, options) => {
const models = Self.app.models;
const {Dms, TicketDms} = Self.app.models;
const myOptions = {};
let tx;
@ -59,22 +59,19 @@ module.exports = Self => {
myOptions.transaction = tx;
}
const promises = [];
try {
const uploadedFiles = await models.Dms.uploadFile(ctx, myOptions);
uploadedFiles.forEach(dms => {
const newTicketDms = models.TicketDms.create({
const uploadedFiles = await Dms.uploadFile(ctx, myOptions);
const promises = uploadedFiles.map(dms => TicketDms.create({
ticketFk: id,
dmsFk: dms.id
}, myOptions);
}, myOptions));
promises.push(newTicketDms);
});
const resolvedPromises = await Promise.all(promises);
await Promise.all(promises);
if (tx) await tx.commit();
return resolvedPromises;
return uploadedFiles;
} catch (e) {
if (tx) await tx.rollback();
throw e;

View File

@ -24,5 +24,12 @@
"userFk": {
"type": "number"
}
},
"relations": {
"expeditionStateType": {
"type": "belongsTo",
"model": "ExpeditionStateType",
"foreignKey": "typeFk"
}
}
}

View File

@ -18,13 +18,35 @@ module.exports = Self => {
}
});
Self.removeFile = async(ctx, id) => {
const models = Self.app.models;
const workerDms = await Self.findById(id);
Self.removeFile = async(ctx, dmsFk, options) => {
const myOptions = {};
let tx;
if (typeof options == 'object')
Object.assign(myOptions, options);
await models.Dms.removeFile(ctx, workerDms.dmsFk);
if (!myOptions.transaction) {
tx = await Self.beginTransaction({});
myOptions.transaction = tx;
}
return workerDms.destroy();
try {
const WorkerDms = await Self.findOne({
where: {document: dmsFk}
}, myOptions);
const targetDms = await Self.app.models.Dms.removeFile(ctx, dmsFk, myOptions);
if (!targetDms || !WorkerDms)
throw new UserError('Try again');
const workerDmsDestroyed = await WorkerDms.destroy(myOptions);
if (tx) await tx.commit();
return workerDmsDestroyed;
} catch (e) {
await tx.rollback();
throw e;
}
};
};

View File

@ -47,30 +47,33 @@ module.exports = Self => {
});
Self.uploadFile = async(ctx, id) => {
const models = Self.app.models;
const promises = [];
const tx = await Self.beginTransaction({});
const {Dms, WorkerDms} = 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;
}
try {
const options = {transaction: tx};
const uploadedFiles = await models.Dms.uploadFile(ctx, options);
uploadedFiles.forEach(dms => {
const newWorkerDms = models.WorkerDms.create({
const uploadedFiles = await Dms.uploadFile(ctx, myOptions);
const promises = uploadedFiles.map(dms =>
WorkerDms.create({
workerFk: id,
dmsFk: dms.id
}, options);
}, myOptions));
await Promise.all(promises);
promises.push(newWorkerDms);
});
const resolvedPromises = await Promise.all(promises);
if (tx) await tx.commit();
await tx.commit();
return resolvedPromises;
} catch (err) {
await tx.rollback();
throw err;
return uploadedFiles;
} catch (e) {
if (tx) await tx.rollback();
throw e;
}
};
};