diff --git a/CHANGELOG.md b/CHANGELOG.md
index c4eb7d29af..5aabb93057 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,77 @@
+# Version 25.04 - 2025-01-28
+
+### Added 🆕
+
+- feat: refs #7202 added new field by:Jon
+- feat: refs #7343 delete sending to user by:ivanm
+- feat: refs #7569 refs#7569 sendEmailNotification by:sergiodt
+- feat: refs #7569 refs#7569 sendMail by:sergiodt
+- feat: refs #7584 changes request by:robert
+- feat: refs #7584 workerTimeControl_afterDelete by:robert
+- feat: refs #7832 implement refund ticket restrictions and add unit tests for ticket service updates by:jgallego
+- feat: refs #7882 Added coords to create a address by:guillermo
+- feat: refs #8073 change names and primary key by:ivanm
+- feat: refs #8073 new comment message by:ivanm
+- feat: refs #8073 #refs 8073 create vn.productionCountryVolume by:ivanm
+- feat: refs #8117 add worker first and last name to item type query by:jtubau
+- feat: refs #8247 added new acl for VnUser model by:Jon
+- feat: refs #8258 added uppercase validation on supplier create (origin/8258-uppercaseInputs) by:provira
+- feat: refs #8298 add priceOptimum and packagesDiscountFactor to zone and client tables by:jgallego
+- feat: refs #8298 add priceOptimum column to zoneEvent and update zone fixture data by:jgallego
+- feat: refs #8298 update price calculation logic and add packagesDiscountFactor column to client table by:jgallego
+- feat: refs #8357 Agregados triggers para manejar exclusiones de trabajadores en la tabla workerMana by:guillermo
+- feat: refs #8361 add hasToDownloadRate field to currency model and update exchange rate logic by:jgallego
+- feat: refs #8381 add initial and final temperature fields to entry model and queries by:jgallego
+
+### Changed 📦
+
+- refactor: order by id by:alexm
+- refactor: refs #7202 modified new invoice procedure and incoterms sql by:Jon
+- refactor: refs #7202 modified procedure to include customsAgent field when creating an invoice by:Jon
+- refactor: refs #8378 deprecate bi.f_tvc by:ivanm
+
+### Fixed 🛠️
+
+- feat: refs #8298 add priceOptimum column to zoneEvent and update zone fixture data by:jgallego
+- fix: prevent slow update (HEAD -> 8452-testToMaster, origin/test, origin/8452-testToMaster, test) by:alexm
+- fix: refs #7202 fixed back test by:Jon
+- fix: refs #7202 fixed sql by:Jon
+- fix: refs #7569 refs·6861 ticketOrderReserve by:sergiodt
+- fix: refs #7569 refs·6861 ticketOrderReserve (origin/7569-sendEmailOrderTicket) by:sergiodt
+- fix: refs #7569 refs#8188 add IfNotExists by:sergiodt
+- fix: refs #7832 update ticketService model test suite to correct describe block by:jgallego
+- fix: refs #8298 remove duplicate entry in English locale file by:jgallego
+- fix: refs #8361 streamline transaction handling in exchangeRateUpdate by:jgallego
+- test: refs #8448 fix e2e by:alexm
+
+# Version 25.00 - 2025-01-14
+
+### Added 🆕
+
+- feat: refs #7235 add serialType parameter to getInvoiceDate and implement corresponding tests by:jgallego
+- feat: refs #7301 update lastEntriesFilter to include landedDate and enhance test cases (origin/7301-removeRedundantInventories) by:pablone
+- feat: refs #7880 error code and translations by:ivanm
+- feat: refs #7924 add isCustomInspectionRequired field to item and update related logic by:jgallego
+- feat: refs #8167 update canBeInvoiced method to include active status check and improve test cases by:jgallego
+- feat: refs #8167 update locale and improve invoicing logic with error handling by:jgallego
+- feat: refs #8246 added relation for the front's new field by:Jon
+- feat: refs #8266 added itemFk and needed fixtures by:jtubau
+- feat: refs #8324 country unique by:Carlos Andrés
+
+### Changed 📦
+
+
+### Fixed 🛠️
+
+- feat: refs #8266 added itemFk and needed fixtures by:jtubau
+- fix: add isCustomInspectionRequired column to item table for customs inspection indication by:jgallego
+- fix: canBeInvoiced only in makeInvoice by:alexm
+- fix: hotFix getMondayWeekYear by:alexm
+- fix: refs #6598 update ACL property assignment by:jorgep
+- fix: refs #6861 refs#6861 addPrevOK by:sergiodt
+- fix: refs #7301 remove debug console log and update test cases in lastEntriesFilter by:pablone
+- fix: refs #7301 update SQL fixtures and improve lastEntriesFilter logic by:pablone
+
# Version 24.52 - 2024-01-07
### Added 🆕
diff --git a/back/methods/chat/sendCheckingPresence.js b/back/methods/chat/sendCheckingPresence.js
index 7ab5d63fef..955ed0240a 100644
--- a/back/methods/chat/sendCheckingPresence.js
+++ b/back/methods/chat/sendCheckingPresence.js
@@ -27,38 +27,46 @@ module.exports = Self => {
});
Self.sendCheckingPresence = async(ctx, recipientId, message) => {
- if (!recipientId) return false;
- const models = Self.app.models;
-
const userId = ctx.req.accessToken.userId;
- const sender = await models.VnUser.findById(userId, {fields: ['id']});
- const recipient = await models.VnUser.findById(recipientId, null);
-
- // Prevent sending messages to yourself
- if (recipientId == userId) return false;
- if (!recipient)
- throw new Error(`Could not send message "${message}" to worker id ${recipientId} from user ${userId}`);
-
- if (!isProduction())
- message = `[Test:Environment to user ${userId}] ` + message;
-
- const chat = await models.Chat.create({
- senderFk: sender.id,
- recipient: `@${recipient.name}`,
- dated: Date.vnNew(),
- checkUserStatus: 1,
- message: message,
- status: 'sending',
- attempts: 0
- });
-
try {
- await Self.sendCheckingUserStatus(chat);
- await Self.updateChat(chat, 'sent');
- } catch (error) {
- await Self.updateChat(chat, 'error', error);
- }
+ const models = Self.app.models;
+ const sender = await models.VnUser.findById(userId, {fields: ['id']});
+ const error = `Could not send message from user ${userId}`;
- return true;
+ if (!recipientId) throw new Error(error);
+ const recipient = await models.VnUser.findById(recipientId, null);
+ if (!recipient)
+ throw new Error(error);
+
+ // Prevent sending messages to yourself
+ if (recipientId == userId) return false;
+
+ if (!isProduction())
+ message = `[Test:Environment to user ${userId}] ` + message;
+
+ const chat = await models.Chat.create({
+ senderFk: sender.id,
+ recipient: `@${recipient.name}`,
+ dated: Date.vnNew(),
+ checkUserStatus: 1,
+ message: message,
+ status: 'sending',
+ attempts: 0
+ });
+
+ try {
+ await Self.sendCheckingUserStatus(chat);
+ await Self.updateChat(chat, 'sent');
+ } catch (error) {
+ await Self.updateChat(chat, 'error', error);
+ }
+
+ return true;
+ } catch (e) {
+ await Self.rawSql(`
+ INSERT INTO util.debug (variable, value)
+ VALUES ('sendCheckingPresence_error', ?)
+ `, [`User: ${userId}, recipient: ${recipientId}, message: ${message}, error: ${e}`]);
+ }
};
};
diff --git a/back/methods/collection/getTickets.js b/back/methods/collection/getTickets.js
index 85d1111dfe..dfe86c94c1 100644
--- a/back/methods/collection/getTickets.js
+++ b/back/methods/collection/getTickets.js
@@ -65,7 +65,8 @@ module.exports = Self => {
iss.id itemShelvingSaleFk,
iss.isPicked,
iss.itemShelvingFk,
- st.code stateCode
+ st.code stateCode,
+ ac.username
FROM ticketCollection tc
LEFT JOIN collection c ON c.id = tc.collectionFk
JOIN sale s ON s.ticketFk = tc.ticketFk
@@ -80,6 +81,7 @@ module.exports = Self => {
LEFT JOIN itemColor ic ON ic.itemFk = s.itemFk
LEFT JOIN origin o ON o.id = i.originFk
LEFT JOIN state st ON st.id = sg.stateFk
+ LEFT JOIN account.user ac ON ac.id = iss.userFk
WHERE tc.collectionFk = ?
GROUP BY s.id, ish.id, p.code, p2.code
UNION ALL
@@ -109,7 +111,8 @@ module.exports = Self => {
iss.id itemShelvingSaleFk,
iss.isPicked,
iss.itemShelvingFk,
- st.code stateCode
+ st.code stateCode,
+ ac.username
FROM sectorCollection sc
JOIN sectorCollectionSaleGroup ss ON ss.sectorCollectionFk = sc.id
JOIN saleGroup sg ON sg.id = ss.saleGroupFk
@@ -124,6 +127,7 @@ module.exports = Self => {
LEFT JOIN itemColor ic ON ic.itemFk = s.itemFk
LEFT JOIN origin o ON o.id = i.originFk
LEFT JOIN state st ON st.id = sg.stateFk
+ LEFT JOIN account.user ac ON ac.id = sg.userFk
WHERE sc.id = ?
AND sgd.saleGroupFk
GROUP BY s.id, ish.id, p.code, p2.code`, [id, id], myOptions);
diff --git a/db/dump/.dump/data.sql b/db/dump/.dump/data.sql
index a2df342180..7fa281197d 100644
--- a/db/dump/.dump/data.sql
+++ b/db/dump/.dump/data.sql
@@ -4,7 +4,7 @@ USE `util`;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
-INSERT INTO `version` VALUES ('vn-database','11385','72bf27f08d3ddf646ec0bb6594fc79cecd4b72f2','2025-01-07 07:46:33','11395');
+INSERT INTO `version` VALUES ('vn-database','11410','7a02af9a3acae14a658de1557baa44542c24d480','2025-01-28 07:44:02','11423');
INSERT INTO `versionLog` VALUES ('vn-database','10107','00-firstScript.sql','jenkins@10.0.2.69','2022-04-23 10:53:53',NULL,NULL);
INSERT INTO `versionLog` VALUES ('vn-database','10112','00-firstScript.sql','jenkins@10.0.2.69','2022-05-09 09:14:53',NULL,NULL);
@@ -1041,6 +1041,7 @@ INSERT INTO `versionLog` VALUES ('vn-database','11261','00-firstScript.sql','jen
INSERT INTO `versionLog` VALUES ('vn-database','11262','00-firstScript.sql','jenkins@db-proxy1.servers.dc.verdnatura.es','2024-10-03 07:47:43',NULL,NULL);
INSERT INTO `versionLog` VALUES ('vn-database','11263','00-firstScript.sql','jenkins@db-proxy1.servers.dc.verdnatura.es','2024-09-27 12:05:32',NULL,NULL);
INSERT INTO `versionLog` VALUES ('vn-database','11264','00-firstScript.sql','jenkins@db-proxy2.servers.dc.verdnatura.es','2024-11-12 08:00:15',NULL,NULL);
+INSERT INTO `versionLog` VALUES ('vn-database','11269','00-firstScript.sql','jenkins@db-proxy2.servers.dc.verdnatura.es','2025-01-28 07:43:58',NULL,NULL);
INSERT INTO `versionLog` VALUES ('vn-database','11271','00-firstScript.sql','jenkins@db-proxy2.servers.dc.verdnatura.es','2024-11-12 08:00:15',NULL,NULL);
INSERT INTO `versionLog` VALUES ('vn-database','11272','00-firstScript.sql','jenkins@db-proxy2.servers.dc.verdnatura.es','2024-11-12 08:00:15',NULL,NULL);
INSERT INTO `versionLog` VALUES ('vn-database','11273','00-firstScript.sql','jenkins@db-proxy1.servers.dc.verdnatura.es','2024-10-03 10:50:51',NULL,NULL);
@@ -1078,6 +1079,7 @@ INSERT INTO `versionLog` VALUES ('vn-database','11315','00-firstScript.sql','jen
INSERT INTO `versionLog` VALUES ('vn-database','11316','00-firstScript.sql','jenkins@db-proxy2.servers.dc.verdnatura.es','2024-11-26 07:05:30',NULL,NULL);
INSERT INTO `versionLog` VALUES ('vn-database','11317','00-firstScript.sql','jenkins@db-proxy2.servers.dc.verdnatura.es','2024-11-26 07:05:30',NULL,NULL);
INSERT INTO `versionLog` VALUES ('vn-database','11319','00-firstScript.sql','jenkins@db-proxy2.servers.dc.verdnatura.es','2024-11-26 07:05:30',NULL,NULL);
+INSERT INTO `versionLog` VALUES ('vn-database','11320','00-firstScript.sql','jenkins@db-proxy2.servers.dc.verdnatura.es','2025-01-14 07:32:07',NULL,NULL);
INSERT INTO `versionLog` VALUES ('vn-database','11321','00-firstScript.sql','jenkins@db-proxy2.servers.dc.verdnatura.es','2024-11-26 07:05:30',NULL,NULL);
INSERT INTO `versionLog` VALUES ('vn-database','11322','00-entryAcl.sql','jenkins@db-proxy2.servers.dc.verdnatura.es','2024-12-10 07:20:04',NULL,NULL);
INSERT INTO `versionLog` VALUES ('vn-database','11324','00-firstScript.sql','jenkins@db-proxy2.servers.dc.verdnatura.es','2024-11-13 10:49:47',NULL,NULL);
@@ -1139,6 +1141,24 @@ INSERT INTO `versionLog` VALUES ('vn-database','11379','00-firstScript.sql','jen
INSERT INTO `versionLog` VALUES ('vn-database','11379','01-secScript.sql','jenkins@db-proxy1.servers.dc.verdnatura.es','2025-01-07 07:46:32',NULL,NULL);
INSERT INTO `versionLog` VALUES ('vn-database','11384','00-firstScript.sql','jenkins@db-proxy1.servers.dc.verdnatura.es','2025-01-07 07:46:32',NULL,NULL);
INSERT INTO `versionLog` VALUES ('vn-database','11385','00-firstScript.sql','jenkins@db-proxy1.servers.dc.verdnatura.es','2025-01-07 07:46:33',NULL,NULL);
+INSERT INTO `versionLog` VALUES ('vn-database','11387','00-firstScript.sql','jenkins@db-proxy2.servers.dc.verdnatura.es','2025-01-28 07:43:58',NULL,NULL);
+INSERT INTO `versionLog` VALUES ('vn-database','11390','00-firstScript.sql','jenkins@db-proxy2.servers.dc.verdnatura.es','2025-01-14 07:32:08',NULL,NULL);
+INSERT INTO `versionLog` VALUES ('vn-database','11391','00-itemAlter.sql','jenkins@db-proxy2.servers.dc.verdnatura.es','2025-01-14 07:32:08',NULL,NULL);
+INSERT INTO `versionLog` VALUES ('vn-database','11396','00-firstScript.sql','jenkins@db-proxy2.servers.dc.verdnatura.es','2025-01-28 07:43:58',NULL,NULL);
+INSERT INTO `versionLog` VALUES ('vn-database','11398','00-zoneEventPriceOptimum.sql','jenkins@db-proxy2.servers.dc.verdnatura.es','2025-01-28 07:43:59',NULL,NULL);
+INSERT INTO `versionLog` VALUES ('vn-database','11398','00-zonePriceOptimum.sql','jenkins@db-proxy2.servers.dc.verdnatura.es','2025-01-28 07:43:59',NULL,NULL);
+INSERT INTO `versionLog` VALUES ('vn-database','11398','01-zoneUpdate.sql','jenkins@db-proxy2.servers.dc.verdnatura.es','2025-01-28 07:43:59',NULL,NULL);
+INSERT INTO `versionLog` VALUES ('vn-database','11398','02-clientAlter.sql','jenkins@db-proxy2.servers.dc.verdnatura.es','2025-01-28 07:43:59',NULL,NULL);
+INSERT INTO `versionLog` VALUES ('vn-database','11398','03-clientConfig.sql','jenkins@db-proxy2.servers.dc.verdnatura.es','2025-01-28 07:43:59',NULL,NULL);
+INSERT INTO `versionLog` VALUES ('vn-database','11400','00-firstScript.sql','jenkins@db-proxy1.servers.dc.verdnatura.es','2025-01-09 09:55:24',NULL,NULL);
+INSERT INTO `versionLog` VALUES ('vn-database','11405','00-entryAlter.sql','jenkins@db-proxy2.servers.dc.verdnatura.es','2025-01-28 07:44:00',NULL,NULL);
+INSERT INTO `versionLog` VALUES ('vn-database','11406','00-currrencyAlter.sql','jenkins@db-proxy2.servers.dc.verdnatura.es','2025-01-28 07:44:00',NULL,NULL);
+INSERT INTO `versionLog` VALUES ('vn-database','11406','01-currrencyUpdate.sql','jenkins@db-proxy2.servers.dc.verdnatura.es','2025-01-28 07:44:00',NULL,NULL);
+INSERT INTO `versionLog` VALUES ('vn-database','11407','00-firstScript.sql','jenkins@db-proxy2.servers.dc.verdnatura.es','2025-01-28 07:44:00',NULL,NULL);
+INSERT INTO `versionLog` VALUES ('vn-database','11410','00-firstScript.sql','jenkins@db-proxy2.servers.dc.verdnatura.es','2025-01-28 07:44:00',NULL,NULL);
+INSERT INTO `versionLog` VALUES ('vn-database','11415','00-firstScript.sql','jenkins@db-proxy1.servers.dc.verdnatura.es','2025-01-20 08:12:38',NULL,NULL);
+INSERT INTO `versionLog` VALUES ('vn-database','11418','00-firstScript.sql','jenkins@db-proxy2.servers.dc.verdnatura.es','2025-01-21 11:03:27',NULL,NULL);
+INSERT INTO `versionLog` VALUES ('vn-database','11423','00-firstScript.sql','jenkins@db-proxy2.servers.dc.verdnatura.es','2025-01-23 15:19:32',NULL,NULL);
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
@@ -1237,6 +1257,7 @@ INSERT INTO `role` VALUES (127,'timeControl','Tablet para fichar',1,'2024-01-09
INSERT INTO `role` VALUES (129,'buyerAssistant','Comprador que tienes mas permisos para ayudar al buyerBoss en algunas tareas',1,'2024-02-06 06:59:12','2024-02-06 06:59:12',783);
INSERT INTO `role` VALUES (130,'reviewer','Revisor de producción',1,'2024-06-11 00:00:00','2024-06-11 00:00:00',10578);
INSERT INTO `role` VALUES (131,'supplier','Privilegios básicos de un proveedor',1,'2024-07-05 10:18:58','2024-07-05 10:18:58',19295);
+INSERT INTO `role` VALUES (132,'salesPersonClaim','Departamento de ventas con funciones de reclamaciones',1,'2025-01-17 07:07:40','2025-01-17 07:07:40',19295);
INSERT INTO `roleInherit` VALUES (1,1,2,NULL);
INSERT INTO `roleInherit` VALUES (2,1,3,NULL);
@@ -1248,7 +1269,6 @@ INSERT INTO `roleInherit` VALUES (8,5,33,NULL);
INSERT INTO `roleInherit` VALUES (10,11,6,NULL);
INSERT INTO `roleInherit` VALUES (11,13,1,NULL);
INSERT INTO `roleInherit` VALUES (12,15,35,NULL);
-INSERT INTO `roleInherit` VALUES (16,17,20,NULL);
INSERT INTO `roleInherit` VALUES (17,17,37,NULL);
INSERT INTO `roleInherit` VALUES (18,17,39,NULL);
INSERT INTO `roleInherit` VALUES (19,17,64,NULL);
@@ -1323,7 +1343,6 @@ INSERT INTO `roleInherit` VALUES (105,72,18,NULL);
INSERT INTO `roleInherit` VALUES (106,73,5,NULL);
INSERT INTO `roleInherit` VALUES (107,73,64,NULL);
INSERT INTO `roleInherit` VALUES (108,73,19,NULL);
-INSERT INTO `roleInherit` VALUES (109,59,50,NULL);
INSERT INTO `roleInherit` VALUES (115,39,76,NULL);
INSERT INTO `roleInherit` VALUES (117,65,76,NULL);
INSERT INTO `roleInherit` VALUES (118,30,76,NULL);
@@ -1515,6 +1534,10 @@ INSERT INTO `roleInherit` VALUES (378,101,15,19294);
INSERT INTO `roleInherit` VALUES (379,103,121,19294);
INSERT INTO `roleInherit` VALUES (381,119,123,19295);
INSERT INTO `roleInherit` VALUES (382,48,72,783);
+INSERT INTO `roleInherit` VALUES (383,114,111,19295);
+INSERT INTO `roleInherit` VALUES (384,132,18,19295);
+INSERT INTO `roleInherit` VALUES (385,132,72,19295);
+INSERT INTO `roleInherit` VALUES (386,109,132,19295);
INSERT INTO `userPassword` VALUES (1,7,1,0,2,1);
@@ -2311,9 +2334,9 @@ INSERT INTO `ACL` VALUES (938,'Worker','__get__mail','READ','ALLOW','ROLE','hr',
INSERT INTO `ACL` VALUES (939,'Machine','*','*','ALLOW','ROLE','productionBoss',10578);
INSERT INTO `ACL` VALUES (940,'ItemTypeLog','find','READ','ALLOW','ROLE','employee',10578);
INSERT INTO `ACL` VALUES (941,'Entry','buyLabel','READ','ALLOW','ROLE','employee',10578);
-INSERT INTO `ACL` VALUES (942,'Cmr','filter','READ','ALLOW','ROLE','production',10578);
-INSERT INTO `ACL` VALUES (943,'Cmr','downloadZip','READ','ALLOW','ROLE','production',10578);
-INSERT INTO `ACL` VALUES (944,'Cmr','print','READ','ALLOW','ROLE','production',10578);
+INSERT INTO `ACL` VALUES (942,'Cmr','filter','READ','ALLOW','ROLE','employee',19295);
+INSERT INTO `ACL` VALUES (943,'Cmr','downloadZip','READ','ALLOW','ROLE','employee',19295);
+INSERT INTO `ACL` VALUES (944,'Cmr','print','READ','ALLOW','ROLE','employee',19295);
INSERT INTO `ACL` VALUES (945,'Collection','create','WRITE','ALLOW','ROLE','productionBoss',10578);
INSERT INTO `ACL` VALUES (946,'Collection','upsert','WRITE','ALLOW','ROLE','productionBoss',10578);
INSERT INTO `ACL` VALUES (947,'Collection','replaceById','WRITE','ALLOW','ROLE','productionBoss',10578);
@@ -2327,7 +2350,6 @@ INSERT INTO `ACL` VALUES (954,'RouteComplement','find','READ','ALLOW','ROLE','de
INSERT INTO `ACL` VALUES (955,'RouteComplement','create','WRITE','ALLOW','ROLE','delivery',10578);
INSERT INTO `ACL` VALUES (956,'RouteComplement','deleteById','WRITE','ALLOW','ROLE','delivery',10578);
INSERT INTO `ACL` VALUES (957,'SaleGroup','find','READ','ALLOW','ROLE','production',10578);
-INSERT INTO `ACL` VALUES (958,'Worker','canCreateAbsenceInPast','WRITE','ALLOW','ROLE','hr',10578);
INSERT INTO `ACL` VALUES (959,'WorkerRelative','updateAttributes','*','ALLOW','ROLE','hr',10578);
INSERT INTO `ACL` VALUES (960,'WorkerRelative','crud','WRITE','ALLOW','ROLE','hr',10578);
INSERT INTO `ACL` VALUES (961,'WorkerRelative','findById','*','ALLOW','ROLE','hr',10578);
@@ -2383,6 +2405,9 @@ INSERT INTO `ACL` VALUES (1010,'InventoryConfig','find','READ','ALLOW','ROLE','b
INSERT INTO `ACL` VALUES (1011,'SiiTypeInvoiceIn','find','READ','ALLOW','ROLE','salesPerson',10578);
INSERT INTO `ACL` VALUES (1012,'OsrmConfig','optimize','READ','ALLOW','ROLE','employee',10578);
INSERT INTO `ACL` VALUES (1013,'Route','optimizePriority','*','ALLOW','ROLE','employee',10578);
+INSERT INTO `ACL` VALUES (1014,'Worker','canModifyAbsenceInPast','WRITE','ALLOW','ROLE','hr',10578);
+INSERT INTO `ACL` VALUES (1015,'Worker','__get__sip','READ','ALLOW','ROLE','employee',19294);
+INSERT INTO `ACL` VALUES (1016,'VnUser','adminUser','WRITE','ALLOW','ROLE','sysadmin',10578);
INSERT INTO `fieldAcl` VALUES (1,'Client','name','update','employee');
INSERT INTO `fieldAcl` VALUES (2,'Client','contact','update','employee');
@@ -2681,71 +2706,72 @@ INSERT INTO `continent` VALUES (3,'África','AF');
INSERT INTO `continent` VALUES (4,'Europa','EU');
INSERT INTO `continent` VALUES (5,'Oceanía','OC');
-INSERT INTO `department` VALUES (1,'VN','VERDNATURA',1,130,763,0,0,0,0,26,NULL,'/',NULL,0,NULL,0,0,0,0,NULL,NULL,NULL,NULL);
+INSERT INTO `department` VALUES (1,'VN','VERDNATURA',1,132,763,0,0,0,0,26,NULL,'/',NULL,0,NULL,0,0,0,0,NULL,NULL,NULL,NULL);
INSERT INTO `department` VALUES (22,'shopping','COMPRAS',2,5,NULL,72,0,0,1,1,1,'/1/',NULL,1,NULL,0,0,0,0,NULL,NULL,NULL,NULL);
INSERT INTO `department` VALUES (23,'CMA','CAMARA',15,16,NULL,72,1,1,2,0,37,'/1/37/',NULL,0,NULL,0,1,1,1,NULL,NULL,NULL,'PREVIOUS');
INSERT INTO `department` VALUES (31,'it','INFORMATICA',6,7,NULL,72,0,0,1,0,1,'/1/','informatica-cau',1,NULL,0,0,0,0,NULL,NULL,NULL,NULL);
INSERT INTO `department` VALUES (34,'accounting','CONTABILIDAD',8,9,NULL,0,0,0,1,0,1,'/1/',NULL,1,NULL,1,0,0,0,NULL,NULL,NULL,NULL);
INSERT INTO `department` VALUES (35,'finance','FINANZAS',10,11,NULL,0,0,0,1,0,1,'/1/',NULL,1,'begonya@verdnatura.es',0,0,0,0,NULL,NULL,NULL,NULL);
INSERT INTO `department` VALUES (36,'labor','LABORAL',12,13,NULL,0,0,0,1,0,1,'/1/',NULL,1,NULL,1,0,0,0,NULL,NULL,NULL,NULL);
-INSERT INTO `department` VALUES (37,'PROD','PRODUCCION',14,37,NULL,72,1,1,1,11,1,'/1/',NULL,0,NULL,0,1,1,1,NULL,NULL,NULL,NULL);
+INSERT INTO `department` VALUES (37,'PROD','PRODUCCION',14,39,NULL,72,1,1,1,12,1,'/1/',NULL,0,NULL,0,1,1,1,NULL,NULL,NULL,NULL);
INSERT INTO `department` VALUES (38,'picking','SACADO',17,18,NULL,72,1,0,2,0,37,'/1/37/',NULL,0,NULL,0,1,0,1,NULL,NULL,NULL,'ON_PREPARATION');
INSERT INTO `department` VALUES (39,'packing','ENCAJADO',19,20,NULL,72,1,0,2,0,37,'/1/37/',NULL,0,NULL,0,0,0,1,NULL,NULL,NULL,'PACKING');
-INSERT INTO `department` VALUES (41,'administration','ADMINISTRACION',38,39,NULL,72,0,0,1,0,1,'/1/',NULL,1,NULL,1,0,0,0,NULL,NULL,NULL,NULL);
-INSERT INTO `department` VALUES (43,'VT','VENTAS',40,89,NULL,0,0,0,1,24,1,'/1/',NULL,1,NULL,0,0,0,0,NULL,NULL,NULL,NULL);
-INSERT INTO `department` VALUES (44,'management','GERENCIA',90,91,NULL,72,0,0,1,0,1,'/1/',NULL,0,NULL,0,0,0,0,NULL,NULL,NULL,NULL);
-INSERT INTO `department` VALUES (45,'logistic','LOGISTICA',92,93,NULL,72,0,0,1,0,1,'/1/',NULL,1,NULL,0,0,0,0,NULL,NULL,NULL,NULL);
-INSERT INTO `department` VALUES (46,'delivery','REPARTO',94,95,NULL,72,0,0,1,0,1,'/1/',NULL,0,NULL,0,1,0,0,NULL,NULL,NULL,'DELIVERY');
-INSERT INTO `department` VALUES (48,'storage','ALMACENAJE',96,97,NULL,0,1,0,1,0,1,'/1/',NULL,0,NULL,0,0,0,0,NULL,NULL,NULL,'STORAGE');
-INSERT INTO `department` VALUES (49,NULL,'PROPIEDAD',98,99,NULL,72,0,0,1,0,1,'/1/',NULL,0,NULL,0,0,0,0,NULL,NULL,NULL,NULL);
-INSERT INTO `department` VALUES (52,NULL,'CARGA AEREA',100,101,NULL,72,0,0,1,0,1,'/1/',NULL,0,NULL,0,0,0,0,NULL,NULL,NULL,NULL);
-INSERT INTO `department` VALUES (53,'marketing','MARKETING Y COMUNICACIÓN',41,42,NULL,72,0,0,2,0,43,'/1/43/',NULL,1,NULL,0,0,0,0,NULL,NULL,NULL,NULL);
-INSERT INTO `department` VALUES (54,NULL,'ORNAMENTALES',102,103,NULL,72,0,0,1,0,1,'/1/',NULL,0,NULL,0,0,0,0,NULL,NULL,NULL,NULL);
+INSERT INTO `department` VALUES (41,'administration','ADMINISTRACION',40,41,NULL,72,0,0,1,0,1,'/1/',NULL,1,NULL,1,0,0,0,NULL,NULL,NULL,NULL);
+INSERT INTO `department` VALUES (43,'VT','VENTAS',42,91,NULL,0,0,0,1,24,1,'/1/',NULL,1,NULL,0,0,0,0,NULL,NULL,NULL,NULL);
+INSERT INTO `department` VALUES (44,'management','GERENCIA',92,93,NULL,72,0,0,1,0,1,'/1/',NULL,0,NULL,0,0,0,0,NULL,NULL,NULL,NULL);
+INSERT INTO `department` VALUES (45,'logistic','LOGISTICA',94,95,NULL,72,0,0,1,0,1,'/1/',NULL,1,NULL,0,0,0,0,NULL,NULL,NULL,NULL);
+INSERT INTO `department` VALUES (46,'delivery','REPARTO',96,97,NULL,72,0,0,1,0,1,'/1/',NULL,0,NULL,0,1,0,0,NULL,NULL,NULL,'DELIVERY');
+INSERT INTO `department` VALUES (48,'storage','ALMACENAJE',98,99,NULL,0,1,0,1,0,1,'/1/',NULL,0,NULL,0,0,0,0,NULL,NULL,NULL,'STORAGE');
+INSERT INTO `department` VALUES (49,NULL,'PROPIEDAD',100,101,NULL,72,0,0,1,0,1,'/1/',NULL,0,NULL,0,0,0,0,NULL,NULL,NULL,NULL);
+INSERT INTO `department` VALUES (52,NULL,'CARGA AEREA',102,103,NULL,72,0,0,1,0,1,'/1/',NULL,0,NULL,0,0,0,0,NULL,NULL,NULL,NULL);
+INSERT INTO `department` VALUES (53,'marketing','MARKETING Y COMUNICACIÓN',43,44,NULL,72,0,0,2,0,43,'/1/43/',NULL,1,NULL,0,0,0,0,NULL,NULL,NULL,NULL);
+INSERT INTO `department` VALUES (54,NULL,'ORNAMENTALES',104,105,NULL,72,0,0,1,0,1,'/1/',NULL,0,NULL,0,0,0,0,NULL,NULL,NULL,NULL);
INSERT INTO `department` VALUES (55,NULL,'TALLER NATURAL',21,22,14548,72,0,0,2,0,37,'/1/37/',NULL,0,NULL,0,1,1,0,1118,NULL,NULL,NULL);
INSERT INTO `department` VALUES (56,NULL,'TALLER ARTIFICIAL',23,24,8470,72,0,0,2,0,37,'/1/37/',NULL,0,NULL,0,1,1,0,1927,NULL,NULL,NULL);
-INSERT INTO `department` VALUES (58,'CMP','CAMPOS',104,107,NULL,72,0,0,1,1,1,'/1/',NULL,0,NULL,0,0,0,0,NULL,NULL,NULL,'FIELD');
-INSERT INTO `department` VALUES (59,'maintenance','MANTENIMIENTO',108,109,NULL,72,0,0,1,0,1,'/1/',NULL,0,NULL,0,1,0,0,NULL,NULL,NULL,NULL);
-INSERT INTO `department` VALUES (60,'claims','RECLAMACIONES',43,44,NULL,72,0,0,2,0,43,'/1/43/',NULL,0,NULL,0,1,0,0,NULL,NULL,NULL,'CLAIM');
-INSERT INTO `department` VALUES (61,NULL,'VNH',110,113,NULL,73,0,0,1,1,1,'/1/',NULL,0,NULL,0,0,0,0,NULL,NULL,NULL,NULL);
-INSERT INTO `department` VALUES (66,NULL,'VERDNAMADRID',114,115,NULL,72,0,0,1,0,1,'/1/',NULL,0,NULL,0,0,0,0,NULL,NULL,NULL,NULL);
+INSERT INTO `department` VALUES (58,'CMP','CAMPOS',106,109,NULL,72,0,0,1,1,1,'/1/',NULL,0,NULL,0,0,0,0,NULL,NULL,NULL,'FIELD');
+INSERT INTO `department` VALUES (59,'maintenance','MANTENIMIENTO',110,111,NULL,72,0,0,1,0,1,'/1/',NULL,0,NULL,0,1,0,0,NULL,NULL,NULL,NULL);
+INSERT INTO `department` VALUES (60,'claims','RECLAMACIONES',45,46,NULL,72,0,0,2,0,43,'/1/43/',NULL,0,NULL,0,1,0,0,NULL,NULL,NULL,'CLAIM');
+INSERT INTO `department` VALUES (61,NULL,'VNH',112,115,NULL,73,0,0,1,1,1,'/1/',NULL,0,NULL,0,0,0,0,NULL,NULL,NULL,NULL);
+INSERT INTO `department` VALUES (66,NULL,'VERDNAMADRID',116,117,NULL,72,0,0,1,0,1,'/1/',NULL,0,NULL,0,0,0,0,NULL,NULL,NULL,NULL);
INSERT INTO `department` VALUES (68,NULL,'COMPLEMENTOS',25,26,NULL,72,1,0,2,0,37,'/1/37/',NULL,0,NULL,0,1,0,0,NULL,NULL,NULL,NULL);
-INSERT INTO `department` VALUES (69,NULL,'VERDNABARNA',116,117,NULL,74,0,0,1,0,1,'/1/',NULL,0,NULL,0,0,0,0,NULL,NULL,NULL,NULL);
-INSERT INTO `department` VALUES (80,'spainTeam5','EQUIPO ESPAÑA 5',45,46,4250,0,0,0,2,0,43,'/1/43/',NULL,1,NULL,0,0,0,0,NULL,NULL,NULL,NULL);
-INSERT INTO `department` VALUES (86,NULL,'LIMPIEZA',118,119,NULL,72,0,0,1,0,1,'/1/',NULL,0,NULL,0,0,0,0,NULL,NULL,NULL,NULL);
-INSERT INTO `department` VALUES (89,NULL,'COORDINACION',120,121,NULL,0,1,0,1,0,1,'/1/',NULL,0,NULL,0,0,0,0,NULL,NULL,NULL,NULL);
-INSERT INTO `department` VALUES (90,NULL,'TRAILER',111,112,NULL,0,0,0,2,0,61,'/1/61/',NULL,0,NULL,0,0,0,0,NULL,NULL,NULL,NULL);
+INSERT INTO `department` VALUES (69,NULL,'VERDNABARNA',118,119,NULL,74,0,0,1,0,1,'/1/',NULL,0,NULL,0,0,0,0,NULL,NULL,NULL,NULL);
+INSERT INTO `department` VALUES (80,'spainTeam5','EQUIPO ESPAÑA 5',47,48,4250,0,0,0,2,0,43,'/1/43/',NULL,1,NULL,0,0,0,0,NULL,NULL,NULL,NULL);
+INSERT INTO `department` VALUES (86,NULL,'LIMPIEZA',120,121,NULL,72,0,0,1,0,1,'/1/',NULL,0,NULL,0,0,0,0,NULL,NULL,NULL,NULL);
+INSERT INTO `department` VALUES (89,NULL,'COORDINACION',122,123,NULL,0,1,0,1,0,1,'/1/',NULL,0,NULL,0,0,0,0,NULL,NULL,NULL,NULL);
+INSERT INTO `department` VALUES (90,NULL,'TRAILER',113,114,NULL,0,0,0,2,0,61,'/1/61/',NULL,0,NULL,0,0,0,0,NULL,NULL,NULL,NULL);
INSERT INTO `department` VALUES (91,'artificial','ARTIFICIAL',27,28,NULL,0,1,0,2,0,37,'/1/37/',NULL,0,NULL,0,0,0,0,NULL,NULL,NULL,'PREVIOUS');
-INSERT INTO `department` VALUES (92,NULL,'EQUIPO SILVERIO',47,48,1203,0,0,0,2,0,43,'/1/43/','sdc_equipo',0,'gestioncomercial@verdnatura.es',0,0,0,0,NULL,NULL,NULL,NULL);
-INSERT INTO `department` VALUES (94,'spainTeam2','EQUIPO ESPAÑA 2',49,50,3797,0,0,0,2,0,43,'/1/43/',NULL,1,NULL,0,0,0,0,NULL,NULL,NULL,NULL);
-INSERT INTO `department` VALUES (95,'spainTeam1','EQUIPO ESPAÑA 1',51,52,24065,0,0,0,2,0,43,'/1/43/',NULL,1,NULL,0,0,0,0,NULL,NULL,NULL,NULL);
-INSERT INTO `department` VALUES (96,NULL,'EQUIPO C LOPEZ',53,54,4661,0,0,0,2,0,43,'/1/43/','cla_equipo',0,'gestioncomercial@verdnatura.es',0,0,0,0,NULL,NULL,NULL,NULL);
-INSERT INTO `department` VALUES (115,NULL,'EQUIPO CLAUDI',55,56,3810,0,0,0,2,0,43,'/1/43/','csr_equipo',0,'gestioncomercial@verdnatura.es',0,0,0,0,NULL,NULL,NULL,NULL);
-INSERT INTO `department` VALUES (123,NULL,'EQUIPO ELENA BASCUÑANA',57,58,7102,0,0,0,2,0,43,'/1/43/','ebt_equipo',0,'gestioncomercial@verdnatura.es',0,0,0,0,NULL,NULL,NULL,NULL);
-INSERT INTO `department` VALUES (124,NULL,'CONTROL INTERNO',122,123,NULL,72,0,0,1,0,1,'/1/',NULL,0,NULL,0,0,0,0,NULL,NULL,NULL,NULL);
-INSERT INTO `department` VALUES (125,'spainTeam3','EQUIPO ESPAÑA 3',59,60,1118,0,0,0,2,0,43,'/1/43/',NULL,1,NULL,0,0,0,0,NULL,NULL,NULL,NULL);
+INSERT INTO `department` VALUES (92,NULL,'EQUIPO SILVERIO',49,50,1203,0,0,0,2,0,43,'/1/43/','sdc_equipo',0,'gestioncomercial@verdnatura.es',0,0,0,0,NULL,NULL,NULL,NULL);
+INSERT INTO `department` VALUES (94,'spainTeam2','EQUIPO ESPAÑA 2',51,52,3797,0,0,0,2,0,43,'/1/43/',NULL,1,NULL,0,0,0,0,NULL,NULL,NULL,NULL);
+INSERT INTO `department` VALUES (95,'spainTeam1','EQUIPO ESPAÑA 1',53,54,24065,0,0,0,2,0,43,'/1/43/',NULL,1,NULL,0,0,0,0,NULL,NULL,NULL,NULL);
+INSERT INTO `department` VALUES (96,NULL,'EQUIPO C LOPEZ',55,56,4661,0,0,0,2,0,43,'/1/43/','cla_equipo',0,'gestioncomercial@verdnatura.es',0,0,0,0,NULL,NULL,NULL,NULL);
+INSERT INTO `department` VALUES (115,NULL,'EQUIPO CLAUDI',57,58,3810,0,0,0,2,0,43,'/1/43/','csr_equipo',0,'gestioncomercial@verdnatura.es',0,0,0,0,NULL,NULL,NULL,NULL);
+INSERT INTO `department` VALUES (123,NULL,'EQUIPO ELENA BASCUÑANA',59,60,7102,0,0,0,2,0,43,'/1/43/','ebt_equipo',0,'gestioncomercial@verdnatura.es',0,0,0,0,NULL,NULL,NULL,NULL);
+INSERT INTO `department` VALUES (124,NULL,'CONTROL INTERNO',124,125,NULL,72,0,0,1,0,1,'/1/',NULL,0,NULL,0,0,0,0,NULL,NULL,NULL,NULL);
+INSERT INTO `department` VALUES (125,'spainTeam3','EQUIPO ESPAÑA 3',61,62,1118,0,0,0,2,0,43,'/1/43/',NULL,1,NULL,0,0,0,0,NULL,NULL,NULL,NULL);
INSERT INTO `department` VALUES (126,NULL,'PRESERVADO',29,30,NULL,0,0,0,2,0,37,'/1/37/',NULL,0,NULL,0,1,1,0,NULL,NULL,NULL,NULL);
INSERT INTO `department` VALUES (128,NULL,'PALETIZADO',31,32,NULL,0,1,0,2,0,37,'/1/37/',NULL,0,NULL,0,0,0,0,NULL,NULL,NULL,'PALLETIZING');
-INSERT INTO `department` VALUES (130,NULL,'REVISION',33,34,NULL,0,1,0,2,0,37,'/1/37/',NULL,0,NULL,0,0,0,1,NULL,NULL,NULL,'ON_CHECKING');
-INSERT INTO `department` VALUES (131,'greenhouse','INVERNADERO',105,106,NULL,0,0,0,2,0,58,'/1/58/',NULL,0,NULL,0,1,0,0,NULL,NULL,NULL,NULL);
-INSERT INTO `department` VALUES (132,NULL,'EQUIPO DC',61,62,1731,0,0,0,2,0,43,'/1/43/','dc_equipo',1,'gestioncomercial@verdnatura.es',0,0,0,0,NULL,NULL,NULL,NULL);
-INSERT INTO `department` VALUES (133,'franceTeamManagement','EQUIPO GESTIÓN FRANCIA',63,64,9751,72,0,0,2,0,43,'/1/43/','fr_equipo',1,'gestionfrancia@verdnatura.es',0,0,0,0,NULL,NULL,'3300',NULL);
-INSERT INTO `department` VALUES (134,'portugalTeam','EQUIPO PORTUGAL',65,66,8964,0,0,0,2,0,43,'/1/43/','pt_equipo',1,'portugal@verdnatura.es',0,0,0,0,NULL,NULL,'3500',NULL);
-INSERT INTO `department` VALUES (135,'routers','ENRUTADORES',124,125,NULL,0,0,0,1,0,1,'/1/',NULL,1,NULL,0,0,0,0,NULL,NULL,NULL,NULL);
-INSERT INTO `department` VALUES (136,'heavyVehicles','VEHICULOS PESADOS',126,127,NULL,0,0,0,1,0,1,'/1/',NULL,0,NULL,0,0,0,0,NULL,NULL,NULL,NULL);
-INSERT INTO `department` VALUES (137,'sorter','SORTER',128,129,NULL,0,0,0,1,0,1,'/1/',NULL,0,NULL,0,0,0,0,NULL,NULL,NULL,NULL);
-INSERT INTO `department` VALUES (139,'spainTeam4','EQUIPO ESPAÑA 4',67,68,3803,0,0,0,2,0,43,'/1/43/',NULL,1,NULL,0,0,0,0,NULL,NULL,NULL,NULL);
-INSERT INTO `department` VALUES (140,'internationalTeam','EQUIPO INTERNACIONAL',69,70,24065,0,0,0,2,0,43,'/1/43/','int_equipo',1,'international@verdnatura.es',0,0,0,0,NULL,NULL,NULL,NULL);
+INSERT INTO `department` VALUES (130,'reviewers','REVISION',33,34,NULL,0,1,0,2,0,37,'/1/37/',NULL,0,NULL,0,0,0,1,NULL,NULL,NULL,'ON_CHECKING');
+INSERT INTO `department` VALUES (131,'greenhouse','INVERNADERO',107,108,NULL,0,0,0,2,0,58,'/1/58/',NULL,0,NULL,0,1,0,0,NULL,NULL,NULL,NULL);
+INSERT INTO `department` VALUES (132,NULL,'EQUIPO DC',63,64,1731,0,0,0,2,0,43,'/1/43/','dc_equipo',1,'gestioncomercial@verdnatura.es',0,0,0,0,NULL,NULL,NULL,NULL);
+INSERT INTO `department` VALUES (133,'franceTeamManagement','EQUIPO GESTIÓN FRANCIA',65,66,9751,72,0,0,2,0,43,'/1/43/','fr_equipo',1,'gestionfrancia@verdnatura.es',0,0,0,0,NULL,NULL,'3300',NULL);
+INSERT INTO `department` VALUES (134,'portugalTeam','EQUIPO PORTUGAL',67,68,8964,0,0,0,2,0,43,'/1/43/','pt_equipo',1,'portugal@verdnatura.es',0,0,0,0,NULL,NULL,'3500',NULL);
+INSERT INTO `department` VALUES (135,'routers','ENRUTADORES',126,127,NULL,0,0,0,1,0,1,'/1/',NULL,1,NULL,0,0,0,0,NULL,NULL,NULL,NULL);
+INSERT INTO `department` VALUES (136,'heavyVehicles','VEHICULOS PESADOS',128,129,NULL,0,0,0,1,0,1,'/1/',NULL,0,NULL,0,0,0,0,NULL,NULL,NULL,NULL);
+INSERT INTO `department` VALUES (137,'sorter','SORTER',130,131,NULL,0,0,0,1,0,1,'/1/',NULL,0,NULL,0,0,0,0,NULL,NULL,NULL,NULL);
+INSERT INTO `department` VALUES (139,'spainTeam4','EQUIPO ESPAÑA 4',69,70,3803,0,0,0,2,0,43,'/1/43/',NULL,1,NULL,0,0,0,0,NULL,NULL,NULL,NULL);
+INSERT INTO `department` VALUES (140,'internationalTeam','EQUIPO INTERNACIONAL',71,72,24065,0,0,0,2,0,43,'/1/43/','int_equipo',1,'international@verdnatura.es',0,0,0,0,NULL,NULL,NULL,NULL);
INSERT INTO `department` VALUES (141,NULL,'PREVIA',35,36,NULL,0,1,0,2,0,37,'/1/37/',NULL,0,NULL,0,0,0,1,NULL,NULL,NULL,'PREVIOUS');
INSERT INTO `department` VALUES (146,NULL,'VERDNACOLOMBIA',3,4,NULL,72,0,0,2,0,22,'/1/22/',NULL,0,NULL,0,0,0,0,NULL,NULL,NULL,NULL);
-INSERT INTO `department` VALUES (147,'spainTeamAsia','EQUIPO ESPAÑA ASIA',71,72,40214,0,0,0,2,0,43,'/1/43/','esA_equipo',1,'esA@verdnatura.es',0,0,0,0,NULL,NULL,'5500',NULL);
-INSERT INTO `department` VALUES (148,'franceTeamCatchment','EQUIPO CAPTACIÓN FRANCIA',73,74,25178,0,0,0,2,0,43,'/1/43/',NULL,1,NULL,0,0,0,0,NULL,NULL,'6000',NULL);
-INSERT INTO `department` VALUES (149,'spainTeamCatchment','EQUIPO ESPAÑA CAPTACIÓN',75,76,1203,0,0,0,2,0,43,'/1/43/','es_captacion_equipo',1,'es_captacion@verdnatura.es',0,0,0,0,NULL,NULL,'5700',NULL);
-INSERT INTO `department` VALUES (150,'spainTeamLevanteIslands','EQUIPO ESPAÑA LEVANTE',77,78,1118,0,0,0,2,0,43,'/1/43/','es_levante_equipo',1,'levanteislas.verdnatura@gmail.com',0,0,0,0,NULL,NULL,'5000',NULL);
-INSERT INTO `department` VALUES (151,'spainTeamNorthwest','EQUIPO ESPAÑA NOROESTE',79,80,7102,0,0,0,2,0,43,'/1/43/','es_noroeste_equipo',1,'noroeste.verdnatura@gmail.com',0,0,0,0,NULL,NULL,'5300',NULL);
-INSERT INTO `department` VALUES (152,'spainTeamNortheast','EQUIPO ESPAÑA NORESTE',81,82,1118,0,0,0,2,0,43,'/1/43/','es_noreste_equipo',1,'noreste.verdnatura@gmail.com',0,0,0,0,NULL,NULL,'5200',NULL);
-INSERT INTO `department` VALUES (153,'spainTeamSouth','EQUIPO ESPAÑA SUR',83,84,36578,0,0,0,2,0,43,'/1/43/','es_sur_equipo',1,'sur.verdnatura@gmail.com',0,0,0,0,NULL,NULL,'5400',NULL);
-INSERT INTO `department` VALUES (154,'spainTeamCenter','EQUIPO ESPAÑA CENTRO',85,86,4661,0,0,0,2,0,43,'/1/43/','es_centro_equipo',1,'centro.verdnatura@gmail.com',0,0,0,0,NULL,NULL,'5100',NULL);
-INSERT INTO `department` VALUES (155,'spainTeamVip','EQUIPO ESPAÑA VIP',87,88,5432,0,0,0,2,0,43,'/1/43/','es_vip_equipo',1,'vip.verdnatura@gmail.com',0,0,0,0,NULL,NULL,'5600',NULL);
+INSERT INTO `department` VALUES (147,'spainTeamAsia','EQUIPO ESPAÑA ASIA',73,74,40214,0,0,0,2,0,43,'/1/43/','esA_equipo',1,'esA@verdnatura.es',0,0,0,0,NULL,NULL,'5500',NULL);
+INSERT INTO `department` VALUES (148,'franceTeamCatchment','EQUIPO CAPTACIÓN FRANCIA',75,76,25178,0,0,0,2,0,43,'/1/43/',NULL,1,NULL,0,0,0,0,NULL,NULL,'6000',NULL);
+INSERT INTO `department` VALUES (149,'spainTeamCatchment','EQUIPO ESPAÑA CAPTACIÓN',77,78,1203,0,0,0,2,0,43,'/1/43/','es_captacion_equipo',1,'es_captacion@verdnatura.es',0,0,0,0,NULL,NULL,'5700',NULL);
+INSERT INTO `department` VALUES (150,'spainTeamLevanteIslands','EQUIPO ESPAÑA LEVANTE',79,80,1118,0,0,0,2,0,43,'/1/43/','es_levante_equipo',1,'es_levante@verdnatura.es',0,0,0,0,NULL,NULL,'5000',NULL);
+INSERT INTO `department` VALUES (151,'spainTeamNorthwest','EQUIPO ESPAÑA NOROESTE',81,82,7102,0,0,0,2,0,43,'/1/43/','es_noroeste_equipo',1,'es_noroeste@verdnatura.es',0,0,0,0,NULL,NULL,'5300',NULL);
+INSERT INTO `department` VALUES (152,'spainTeamNortheast','EQUIPO ESPAÑA NORESTE',83,84,1118,0,0,0,2,0,43,'/1/43/','es_noreste_equipo',1,'es_noreste@verdnatura.es',0,0,0,0,NULL,NULL,'5200',NULL);
+INSERT INTO `department` VALUES (153,'spainTeamSouth','EQUIPO ESPAÑA SUR',85,86,36578,0,0,0,2,0,43,'/1/43/','es_sur_equipo',1,'es_sur@verdnatura.es',0,0,0,0,NULL,NULL,'5400',NULL);
+INSERT INTO `department` VALUES (154,'spainTeamCenter','EQUIPO ESPAÑA CENTRO',87,88,4661,0,0,0,2,0,43,'/1/43/','es_centro_equipo',1,'es_centro@verdnatura.es',0,0,0,0,NULL,NULL,'5100',NULL);
+INSERT INTO `department` VALUES (155,'spainTeamVip','EQUIPO ESPAÑA VIP',89,90,5432,0,0,0,2,0,43,'/1/43/','es_vip_equipo',1,'es_vip@verdnatura.es',0,0,0,0,NULL,NULL,'5600',NULL);
+INSERT INTO `department` VALUES (156,NULL,'COCINA',37,38,NULL,0,0,0,2,0,37,'/1/37/',NULL,0,NULL,0,0,0,0,NULL,NULL,NULL,NULL);
INSERT INTO `docuware` VALUES (1,'deliveryNote','Albaranes cliente','find','find','N__ALBAR_N',NULL);
INSERT INTO `docuware` VALUES (2,'deliveryNote','Albaranes cliente','store','Archivar','N__ALBAR_N',NULL);
@@ -3046,6 +3072,7 @@ INSERT INTO `message` VALUES (20,'clientNotVerified','Incomplete tax data, pleas
INSERT INTO `message` VALUES (21,'quantityLessThanMin','The quantity cannot be less than the minimum');
INSERT INTO `message` VALUES (22,'ORDER_ROW_UNAVAILABLE','The ordered quantity exceeds the available');
INSERT INTO `message` VALUES (23,'AMOUNT_NOT_MATCH_GROUPING','The quantity ordered does not match the grouping');
+INSERT INTO `message` VALUES (24,'orderLinesWithZero','There are empty lines. Please delete them');
INSERT INTO `metatag` VALUES (2,'title','Verdnatura Levante SL, mayorista de flores, plantas y complementos para floristería y decoración');
INSERT INTO `metatag` VALUES (3,'description','Verdnatura Levante SL, mayorista de flores, plantas y complementos para floristería y decoración. Envío a toda España, pedidos por internet o por teléfono.');
diff --git a/db/dump/.dump/privileges.sql b/db/dump/.dump/privileges.sql
index 460256b564..1d4fce1892 100644
--- a/db/dump/.dump/privileges.sql
+++ b/db/dump/.dump/privileges.sql
@@ -602,7 +602,7 @@ INSERT IGNORE INTO `tables_priv` VALUES ('','vn','administrative','projectState'
INSERT IGNORE INTO `tables_priv` VALUES ('','vn','employee','entrySplit__','alexm@%','0000-00-00 00:00:00','Select,Insert,Update,Delete','');
INSERT IGNORE INTO `tables_priv` VALUES ('','vn','employee','entryType','alexm@%','0000-00-00 00:00:00','Select','');
INSERT IGNORE INTO `tables_priv` VALUES ('','vn','administrative','projectNotes','alexm@%','0000-00-00 00:00:00','Select','');
-INSERT IGNORE INTO `tables_priv` VALUES ('','vn','administrative','project','juan@10.5.1.1','0000-00-00 00:00:00','Select,Update','');
+INSERT IGNORE INTO `tables_priv` VALUES ('','vn','administrative','project','guillermo@db-proxy2.servers.dc.verdnatura.es','0000-00-00 00:00:00','Select,Insert,Update','');
INSERT IGNORE INTO `tables_priv` VALUES ('','vn','employee','productionConfig','alexm@%','0000-00-00 00:00:00','Select','');
INSERT IGNORE INTO `tables_priv` VALUES ('','vn','manager','productionConfig','alexm@%','0000-00-00 00:00:00','Update','');
INSERT IGNORE INTO `tables_priv` VALUES ('','vn','grafana','creditInsurance','juan@db-proxy2.static.verdnatura.es','0000-00-00 00:00:00','Select','');
@@ -1494,6 +1494,17 @@ INSERT IGNORE INTO `tables_priv` VALUES ('','vn','grafana','travelThermograph','
INSERT IGNORE INTO `tables_priv` VALUES ('','vn','grafana','thermograph','guillermo@db-proxy1.servers.dc.verdnatura.es','0000-00-00 00:00:00','Select','');
INSERT IGNORE INTO `tables_priv` VALUES ('','vn2008','buyerSalesAssistant','Tickets','guillermo@db-proxy1.servers.dc.verdnatura.es','0000-00-00 00:00:00','Update','');
INSERT IGNORE INTO `tables_priv` VALUES ('','vn','hr','sim','jenkins@db-proxy1.servers.dc.verdnatura.es','0000-00-00 00:00:00','Select,Insert,Update,Delete','');
+INSERT IGNORE INTO `tables_priv` VALUES ('','vn','employee','zoneGeo','guillermo@db-proxy2.servers.dc.verdnatura.es','0000-00-00 00:00:00','Select','');
+INSERT IGNORE INTO `tables_priv` VALUES ('','vn','buyer','itemCampaign','guillermo@db-proxy1.servers.dc.verdnatura.es','0000-00-00 00:00:00','Select','');
+INSERT IGNORE INTO `tables_priv` VALUES ('','vn','grafana','itemCampaign','guillermo@db-proxy1.servers.dc.verdnatura.es','0000-00-00 00:00:00','Select','');
+INSERT IGNORE INTO `tables_priv` VALUES ('','vn','buyer','campaign','guillermo@db-proxy1.servers.dc.verdnatura.es','0000-00-00 00:00:00','Select','');
+INSERT IGNORE INTO `tables_priv` VALUES ('','vn','grafana','awb','guillermo@db-proxy2.servers.dc.verdnatura.es','0000-00-00 00:00:00','Select','');
+INSERT IGNORE INTO `tables_priv` VALUES ('','vn','grafana','awbComponent','guillermo@db-proxy1.servers.dc.verdnatura.es','0000-00-00 00:00:00','Select','');
+INSERT IGNORE INTO `tables_priv` VALUES ('','vn','grafana','awbComponentType','guillermo@db-proxy1.servers.dc.verdnatura.es','0000-00-00 00:00:00','Select','');
+INSERT IGNORE INTO `tables_priv` VALUES ('','vn','logisticAssist','itemSoldOutTag','jenkins@db-proxy1.servers.dc.verdnatura.es','0000-00-00 00:00:00','Select,Insert,Update,Delete','');
+INSERT IGNORE INTO `tables_priv` VALUES ('','vn','logisticAssist','itemDurationTag','jenkins@db-proxy1.servers.dc.verdnatura.es','0000-00-00 00:00:00','Select,Insert,Update,Delete','');
+INSERT IGNORE INTO `tables_priv` VALUES ('','vn','logisticAssist','itemGrowingTag','jenkins@db-proxy1.servers.dc.verdnatura.es','0000-00-00 00:00:00','Select,Insert,Update,Delete','');
+INSERT IGNORE INTO `tables_priv` VALUES ('','vn','adminBoss','receipt','guillermo@db-proxy1.servers.dc.verdnatura.es','0000-00-00 00:00:00','Update,Delete','');
/*!40000 ALTER TABLE `tables_priv` ENABLE KEYS */;
/*!40000 ALTER TABLE `columns_priv` DISABLE KEYS */;
@@ -2138,6 +2149,7 @@ INSERT IGNORE INTO `procs_priv` VALUES ('','srt','delivery','buffer_settypebynam
INSERT IGNORE INTO `procs_priv` VALUES ('','vn','delivery','expedition_getstate','PROCEDURE','guillermo@db-proxy1.static.verdnatura.es','Execute','0000-00-00 00:00:00');
INSERT IGNORE INTO `procs_priv` VALUES ('','srt','delivery','expedition_scan','PROCEDURE','guillermo@db-proxy1.static.verdnatura.es','Execute','0000-00-00 00:00:00');
INSERT IGNORE INTO `procs_priv` VALUES ('','vn','delivery','itemshelving_get','PROCEDURE','guillermo@db-proxy1.static.verdnatura.es','Execute','0000-00-00 00:00:00');
+INSERT IGNORE INTO `procs_priv` VALUES ('','vn','financial','remittance_calc','PROCEDURE','jgallego@db-proxy2.servers.dc.verdnatura.es','Execute','0000-00-00 00:00:00');
INSERT IGNORE INTO `procs_priv` VALUES ('','vn','delivery','itemshelving_add','PROCEDURE','guillermo@db-proxy1.static.verdnatura.es','Execute','0000-00-00 00:00:00');
INSERT IGNORE INTO `procs_priv` VALUES ('','vn','delivery','itemshelving_getsaledate','PROCEDURE','guillermo@db-proxy1.static.verdnatura.es','Execute','0000-00-00 00:00:00');
INSERT IGNORE INTO `procs_priv` VALUES ('','vn','delivery','itemshelving_filterbuyer','PROCEDURE','guillermo@db-proxy1.static.verdnatura.es','Execute','0000-00-00 00:00:00');
@@ -2200,7 +2212,6 @@ INSERT IGNORE INTO `procs_priv` VALUES ('','vn','claimManager','entry_getTransfe
INSERT IGNORE INTO `procs_priv` VALUES ('','vn','buyer','entry_getTransfer','PROCEDURE','jenkins@db-proxy1.servers.dc.verdnatura.es','Execute','0000-00-00 00:00:00');
INSERT IGNORE INTO `procs_priv` VALUES ('','vn','administrative','intrastat_estimateNet','FUNCTION','jenkins@db-proxy1.servers.dc.verdnatura.es','Execute','0000-00-00 00:00:00');
INSERT IGNORE INTO `procs_priv` VALUES ('','vn','artificialBoss','confection_controlSource','PROCEDURE','jenkins@db-proxy1.servers.dc.verdnatura.es','Execute','0000-00-00 00:00:00');
-INSERT IGNORE INTO `procs_priv` VALUES ('','vn','financial','remittance_calc','PROCEDURE','alexm@db-proxy1.servers.dc.verdnatura.es','Execute','0000-00-00 00:00:00');
INSERT IGNORE INTO `procs_priv` VALUES ('','util','developer','connection_kill','PROCEDURE','jenkins@db-proxy1.servers.dc.verdnatura.es','Execute','0000-00-00 00:00:00');
INSERT IGNORE INTO `procs_priv` VALUES ('','vn','financial','client_getRisk','PROCEDURE','jenkins@db-proxy1.servers.dc.verdnatura.es','Execute','0000-00-00 00:00:00');
INSERT IGNORE INTO `procs_priv` VALUES ('','account','developer','user_hasRole','FUNCTION','root@localhost','Execute','0000-00-00 00:00:00');
@@ -2308,6 +2319,7 @@ INSERT IGNORE INTO `global_priv` VALUES ('','root','{\"access\": 549755781119, \
INSERT IGNORE INTO `global_priv` VALUES ('','salesAssistant','{\"access\":0,\"version_id\":101106,\"is_role\":true}');
INSERT IGNORE INTO `global_priv` VALUES ('','salesBoss','{\"access\":0,\"version_id\":101106,\"is_role\":true}');
INSERT IGNORE INTO `global_priv` VALUES ('','salesPerson','{\"access\": 0, \"is_role\": true,\"version_id\":101106}');
+INSERT IGNORE INTO `global_priv` VALUES ('','salesPersonClaim','{\"access\":0,\"version_id\":101106,\"is_role\":true}');
INSERT IGNORE INTO `global_priv` VALUES ('','salesTeamBoss','{\"access\":0,\"version_id\":100707,\"is_role\":true}');
INSERT IGNORE INTO `global_priv` VALUES ('','salix','{\"access\":33555456,\"version_id\":100707,\"is_role\":true}');
INSERT IGNORE INTO `global_priv` VALUES ('','sysadmin','{\"access\": 201326592, \"is_role\": true, \"version_id\": 100707}');
diff --git a/db/dump/.dump/structure.sql b/db/dump/.dump/structure.sql
index e52ed2a510..97f7bc512d 100644
--- a/db/dump/.dump/structure.sql
+++ b/db/dump/.dump/structure.sql
@@ -2543,17 +2543,17 @@ CREATE TABLE `defaulting` (
/*!40101 SET character_set_client = @saved_cs_client */;
--
--- Table structure for table `f_tvc`
+-- Table structure for table `f_tvc__`
--
-DROP TABLE IF EXISTS `f_tvc`;
+DROP TABLE IF EXISTS `f_tvc__`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `f_tvc` (
+CREATE TABLE `f_tvc__` (
`Id_Ticket` int(11) NOT NULL,
PRIMARY KEY (`Id_Ticket`),
CONSTRAINT `id_ticket_to_comisionantes` FOREIGN KEY (`Id_Ticket`) REFERENCES `vn`.`ticket` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci COMMENT='Almacenamos la lista de tickets para agilizar la consulta. Corresponde a los clientes REAL y en los almacenes COMISIONANTES';
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci COMMENT='@deprecated 2025-01-15';
/*!40101 SET character_set_client = @saved_cs_client */;
--
@@ -6249,19 +6249,27 @@ BEGIN
* @param vDateFrom Fecha desde
* @param vDateTo Fecha hasta
*/
- IF vDateFrom IS NULL THEN
- SET vDateFrom = util.VN_CURDATE() - INTERVAL WEEKDAY(util.VN_CURDATE()) DAY;
+ DECLARE vDaysInYear INT;
+ SET vDaysInYear = DATEDIFF(util.lastDayOfYear(CURDATE()), util.firstDayOfYear(CURDATE()));
+
+ SET vDateFrom = COALESCE(vDateFrom, util.VN_CURDATE());
+ SET vDateTo = COALESCE(vDateTo, util.VN_CURDATE());
+
+ IF DATEDIFF(vDateTo, vDateFrom) > vDaysInYear THEN
+ CALL util.throw('The period cannot be longer than one year');
END IF;
- IF vDateTo IS NULL THEN
- SET vDateTo = vDateFrom + INTERVAL 6 DAY;
- END IF;
+ -- Obtiene el primer día de la semana de esa fecha
+ SET vDateFrom = DATE_SUB(vDateFrom, INTERVAL ((WEEKDAY(vDateFrom) + 1) % 7) DAY);
+
+ -- Obtiene el último día de la semana de esa fecha
+ SET vDateTo = DATE_ADD(vDateTo, INTERVAL (6 - ((WEEKDAY(vDateTo) + 1) % 7)) DAY);
CALL cache.last_buy_refresh(FALSE);
REPLACE bs.waste
- SELECT YEAR(t.shipped),
- WEEK(t.shipped, 4),
+ SELECT YEARWEEK(t.shipped, 6) DIV 100,
+ WEEK(t.shipped, 6),
it.workerFk,
it.id,
s.itemFk,
@@ -6307,9 +6315,9 @@ BEGIN
JOIN cache.last_buy lb ON lb.item_id = i.id
AND lb.warehouse_id = w.id
JOIN vn.buy b ON b.id = lb.buy_id
- WHERE t.shipped BETWEEN vDateFrom AND vDateTo
+ WHERE t.shipped BETWEEN vDateFrom AND util.dayEnd(vDateTo)
AND w.isManaged
- GROUP BY YEAR(t.shipped), WEEK(t.shipped, 4), i.id;
+ GROUP BY YEARWEEK(t.shipped, 6) DIV 100, WEEK(t.shipped, 6), i.id;
END ;;
DELIMITER ;
/*!50003 SET sql_mode = @saved_sql_mode */ ;
@@ -13807,7 +13815,7 @@ BEGIN
) INTO vHas0Amount;
IF vHas0Amount THEN
- CALL util.throw('Hay líneas vacías. Por favor, elimínelas');
+ CALL util.throw('orderLinesWithZero');
END IF;
START TRANSACTION;
@@ -25870,7 +25878,7 @@ CREATE TABLE `address` (
`isActive` tinyint(4) NOT NULL DEFAULT 1,
`longitude` decimal(11,7) DEFAULT NULL COMMENT 'Indica la última longitud proporcionada por tabla delivery',
`latitude` decimal(11,7) DEFAULT NULL COMMENT 'Indica la última latitud proporcionada por tabla delivery',
- `isEqualizated` tinyint(1) NOT NULL DEFAULT 0,
+ `isEqualizated` tinyint(1) DEFAULT NULL,
`customsAgentFk` int(11) DEFAULT NULL,
`incotermsFk` varchar(3) DEFAULT NULL,
`isLogifloraAllowed` tinyint(4) NOT NULL DEFAULT 0,
@@ -27717,6 +27725,7 @@ CREATE TABLE `client` (
`hasDailyInvoice` tinyint(1) NOT NULL DEFAULT 0 COMMENT 'Indica si el cliente requiere facturación diaria por defecto se copiará lo que tenga country.hasDailyInvoice',
`geoFk` int(11) DEFAULT NULL,
`editorFk` int(10) unsigned DEFAULT NULL,
+ `packagesDiscountFactor` decimal(4,3) NOT NULL DEFAULT 1.000 COMMENT 'Porcentaje de ajuste entre el numero de bultos medio del cliente, y el número medio óptimo para las zonas en las que compra',
PRIMARY KEY (`id`),
UNIQUE KEY `IF` (`fi`),
KEY `Id_Trabajador` (`salesPersonFk`),
@@ -27796,6 +27805,8 @@ CREATE TABLE `clientConfig` (
`defaultHasCoreVnl` tinyint(1) DEFAULT NULL,
`defaultMandateTypeFk` smallint(5) DEFAULT NULL,
`monthsToDisableUser` int(10) unsigned DEFAULT NULL,
+ `packagesOptimum` int(10) unsigned NOT NULL DEFAULT 20 COMMENT 'Numero de bultos por cliente/dia para conseguir el precio optimo',
+ `monthsToCalcOptimumPrice` tinyint(3) unsigned NOT NULL DEFAULT 3 COMMENT 'Número de meses a usar para el cálculo de client.packagesDiscountFactor',
PRIMARY KEY (`id`),
KEY `clientNewConfigPayMethod_FK` (`defaultPayMethodFk`),
KEY `clientNewConfigMandateType_FK` (`defaultMandateTypeFk`),
@@ -28922,6 +28933,7 @@ CREATE TABLE `country` (
`isSocialNameUnique` tinyint(1) NOT NULL DEFAULT 1,
PRIMARY KEY (`id`),
UNIQUE KEY `country_unique` (`code`),
+ UNIQUE KEY `country_unique_name` (`name`),
KEY `currency_id_fk_idx` (`currencyFk`),
KEY `country_Ix4` (`name`),
KEY `continent_id_fk_idx` (`continentFk`),
@@ -29052,6 +29064,7 @@ CREATE TABLE `currency` (
`code` varchar(3) NOT NULL,
`name` varchar(45) DEFAULT NULL,
`ratio` double NOT NULL DEFAULT 1,
+ `hasToDownloadRate` tinyint(1) NOT NULL DEFAULT 0 COMMENT 'Si se guarda el tipo de cambio diariamente en referenceRate',
PRIMARY KEY (`id`),
UNIQUE KEY `Moneda_UNIQUE` (`code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
@@ -29963,6 +29976,8 @@ CREATE TABLE `entry` (
`editorFk` int(10) unsigned DEFAULT NULL,
`lockerUserFk` int(10) unsigned DEFAULT NULL,
`locked` datetime DEFAULT current_timestamp(),
+ `initialTemperature` decimal(10,2) DEFAULT NULL COMMENT 'Temperatura de como lo recibimos del proveedor ej. en colombia',
+ `finalTemperature` decimal(10,2) DEFAULT NULL COMMENT 'Temperatura final de como llega a nuestras instalaciones',
PRIMARY KEY (`id`),
KEY `Id_Proveedor` (`supplierFk`),
KEY `Fecha` (`dated`),
@@ -31765,6 +31780,8 @@ CREATE TABLE `invoiceOut` (
`cplusTaxBreakFk` int(10) unsigned NOT NULL DEFAULT 1,
`cplusSubjectOpFk` int(10) unsigned NOT NULL DEFAULT 1,
`siiTrascendencyInvoiceOutFk` int(10) unsigned NOT NULL DEFAULT 1,
+ `customsAgentFk` int(11) DEFAULT NULL,
+ `incotermsFk` varchar(3) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `invoiceOut_unique` (`ref`),
KEY `Id_Banco` (`bankFk`),
@@ -31777,9 +31794,13 @@ CREATE TABLE `invoiceOut` (
KEY `Facturas_ibfk_5_idx` (`siiTrascendencyInvoiceOutFk`),
KEY `Facturas_idx_Vencimiento` (`dued`),
KEY `invoiceOut_serial` (`serial`),
+ KEY `invoiceOut_customsAgentFk` (`customsAgentFk`),
+ KEY `invoiceOut_incotermsFk` (`incotermsFk`),
+ CONSTRAINT `invoiceOut_customsAgentFk` FOREIGN KEY (`customsAgentFk`) REFERENCES `customsAgent` (`id`) ON UPDATE CASCADE,
CONSTRAINT `invoiceOut_ibfk_2` FOREIGN KEY (`siiTypeInvoiceOutFk`) REFERENCES `siiTypeInvoiceOut` (`id`) ON UPDATE CASCADE,
CONSTRAINT `invoiceOut_ibfk_3` FOREIGN KEY (`cplusSubjectOpFk`) REFERENCES `cplusSubjectOp` (`id`) ON UPDATE CASCADE,
CONSTRAINT `invoiceOut_ibfk_4` FOREIGN KEY (`cplusTaxBreakFk`) REFERENCES `cplusTaxBreak` (`id`) ON UPDATE CASCADE,
+ CONSTRAINT `invoiceOut_incotermsFk` FOREIGN KEY (`incotermsFk`) REFERENCES `incoterms` (`code`) ON UPDATE CASCADE,
CONSTRAINT `invoiceOut_serial` FOREIGN KEY (`serial`) REFERENCES `invoiceOutSerial` (`code`),
CONSTRAINT `invoice_bank_id` FOREIGN KEY (`bankFk`) REFERENCES `accounting` (`id`) ON UPDATE CASCADE,
CONSTRAINT `invoice_customer_id` FOREIGN KEY (`clientFk`) REFERENCES `client` (`id`) ON UPDATE CASCADE
@@ -31971,6 +31992,7 @@ CREATE TABLE `item` (
`value12` varchar(50) DEFAULT NULL,
`tag13` varchar(20) DEFAULT NULL,
`value13` varchar(50) DEFAULT NULL,
+ `isCustomInspectionRequired` tinyint(1) NOT NULL DEFAULT 0 COMMENT 'Indicates if the item requires physical inspection at customs',
PRIMARY KEY (`id`),
UNIQUE KEY `item_supplyResponseFk_idx` (`supplyResponseFk`),
KEY `Color` (`inkFk`),
@@ -32249,6 +32271,21 @@ CREATE TABLE `itemCost` (
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci COMMENT='Almacena los valores de rotacion en los ultimos 365 dias';
/*!40101 SET character_set_client = @saved_cs_client */;
+--
+-- Table structure for table `itemDurationTag`
+--
+
+DROP TABLE IF EXISTS `itemDurationTag`;
+/*!40101 SET @saved_cs_client = @@character_set_client */;
+/*!40101 SET character_set_client = utf8 */;
+CREATE TABLE `itemDurationTag` (
+ `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
+ `name` varchar(50) NOT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `name_UNIQUE` (`name`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
+/*!40101 SET character_set_client = @saved_cs_client */;
+
--
-- Temporary table structure for view `itemEntryIn`
--
@@ -32313,6 +32350,21 @@ CREATE TABLE `itemFarmingTag` (
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
+--
+-- Table structure for table `itemGrowingTag`
+--
+
+DROP TABLE IF EXISTS `itemGrowingTag`;
+/*!40101 SET @saved_cs_client = @@character_set_client */;
+/*!40101 SET character_set_client = utf8 */;
+CREATE TABLE `itemGrowingTag` (
+ `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
+ `name` varchar(50) NOT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `name_UNIQUE` (`name`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
+/*!40101 SET character_set_client = @saved_cs_client */;
+
--
-- Table structure for table `itemImageQueue`
--
@@ -32861,6 +32913,21 @@ SET character_set_client = utf8;
1 AS `removed` */;
SET character_set_client = @saved_cs_client;
+--
+-- Table structure for table `itemSoldOutTag`
+--
+
+DROP TABLE IF EXISTS `itemSoldOutTag`;
+/*!40101 SET @saved_cs_client = @@character_set_client */;
+/*!40101 SET character_set_client = utf8 */;
+CREATE TABLE `itemSoldOutTag` (
+ `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
+ `name` varchar(50) NOT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `name_UNIQUE` (`name`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
+/*!40101 SET character_set_client = @saved_cs_client */;
+
--
-- Table structure for table `itemStateTag`
--
@@ -35450,6 +35517,21 @@ CREATE TABLE `productionConfigLog` (
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
+--
+-- Table structure for table `productionCountry`
+--
+
+DROP TABLE IF EXISTS `productionCountry`;
+/*!40101 SET @saved_cs_client = @@character_set_client */;
+/*!40101 SET character_set_client = utf8 */;
+CREATE TABLE `productionCountry` (
+ `countryFk` mediumint(8) unsigned NOT NULL,
+ `volumeGrowthEstimatePercent` decimal(6,2) DEFAULT NULL COMMENT 'Porcentaje estimado de crecimiento del volumen',
+ PRIMARY KEY (`countryFk`),
+ CONSTRAINT `productionCountryVolume_countryFK` FOREIGN KEY (`countryFk`) REFERENCES `country` (`id`) ON UPDATE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci COMMENT='Datos de producción por país';
+/*!40101 SET character_set_client = @saved_cs_client */;
+
--
-- Table structure for table `productionError`
--
@@ -37982,7 +38064,7 @@ CREATE TABLE `supplier` (
`payDay` tinyint(4) unsigned DEFAULT NULL,
`payDemFk` tinyint(3) unsigned NOT NULL DEFAULT 7,
`created` timestamp NOT NULL DEFAULT current_timestamp(),
- `isReal` tinyint(1) unsigned NOT NULL DEFAULT 0,
+ `isReal` tinyint(1) unsigned NOT NULL DEFAULT 1,
`note` text CHARACTER SET utf8mb3 COLLATE utf8mb3_unicode_ci DEFAULT NULL,
`postcodeFk` int(11) unsigned DEFAULT NULL,
`postCode` char(8) CHARACTER SET utf8mb3 COLLATE utf8mb3_unicode_ci DEFAULT NULL,
@@ -38575,6 +38657,7 @@ CREATE TABLE `ticket` (
KEY `tickets_zone_fk_idx` (`zoneFk`),
KEY `ticket_fk_editor` (`editorFk`),
KEY `ticket_cmrFk` (`cmrFk`),
+ KEY `ticket_landed_IDX` (`landed`) USING BTREE,
CONSTRAINT `ticketCompany_Fk` FOREIGN KEY (`companyFk`) REFERENCES `company` (`id`) ON UPDATE CASCADE,
CONSTRAINT `ticket_cmrFk` FOREIGN KEY (`cmrFk`) REFERENCES `cmr` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `ticket_customer_id` FOREIGN KEY (`clientFk`) REFERENCES `client` (`id`) ON UPDATE CASCADE,
@@ -41251,6 +41334,7 @@ CREATE TABLE `zone` (
`agencyModeFk` int(11) NOT NULL,
`travelingDays` int(11) NOT NULL DEFAULT 1,
`price` decimal(10,2) DEFAULT NULL,
+ `priceOptimum` decimal(10,2) NOT NULL COMMENT 'Precio mínimo que puede pagar un bulto',
`bonus` double NOT NULL DEFAULT 0,
`isVolumetric` tinyint(1) NOT NULL DEFAULT 0,
`inflation` decimal(5,2) NOT NULL DEFAULT 1.00,
@@ -41267,7 +41351,8 @@ CREATE TABLE `zone` (
KEY `zone_address_FK` (`addressFk`),
CONSTRAINT `fk_zone_2` FOREIGN KEY (`agencyModeFk`) REFERENCES `agencyMode` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `zone_address_FK` FOREIGN KEY (`addressFk`) REFERENCES `address` (`id`) ON UPDATE CASCADE,
- CONSTRAINT `zone_fk_editor` FOREIGN KEY (`editorFk`) REFERENCES `account`.`user` (`id`)
+ CONSTRAINT `zone_fk_editor` FOREIGN KEY (`editorFk`) REFERENCES `account`.`user` (`id`),
+ CONSTRAINT `ck_zone_priceOptimum` CHECK (`priceOptimum` <= `price`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
@@ -41360,6 +41445,7 @@ CREATE TABLE `zoneEvent` (
`hour` datetime DEFAULT NULL,
`travelingDays` int(11) DEFAULT NULL,
`price` decimal(10,2) DEFAULT NULL,
+ `priceOptimum` decimal(10,2) DEFAULT NULL COMMENT 'Precio mínimo que puede pagar un bulto',
`bonus` decimal(10,2) DEFAULT NULL,
`m3Max` decimal(10,2) unsigned DEFAULT NULL,
`editorFk` int(10) unsigned DEFAULT NULL,
@@ -41367,7 +41453,8 @@ CREATE TABLE `zoneEvent` (
UNIQUE KEY `zoneFk` (`zoneFk`,`type`,`dated`),
KEY `zoneEvent_fk_editor` (`editorFk`),
CONSTRAINT `zoneEvent_fk_editor` FOREIGN KEY (`editorFk`) REFERENCES `account`.`user` (`id`),
- CONSTRAINT `zoneEvent_ibfk_1` FOREIGN KEY (`zoneFk`) REFERENCES `zone` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
+ CONSTRAINT `zoneEvent_ibfk_1` FOREIGN KEY (`zoneFk`) REFERENCES `zone` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
+ CONSTRAINT `ck_zoneEvent_priceOptimum` CHECK (`priceOptimum` <= `price`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
@@ -41601,6 +41688,24 @@ END */ ;;
/*!50003 SET character_set_client = @saved_cs_client */ ;;
/*!50003 SET character_set_results = @saved_cs_results */ ;;
/*!50003 SET collation_connection = @saved_col_connection */ ;;
+/*!50106 DROP EVENT IF EXISTS `client_setPackagesDiscountFactor` */;;
+DELIMITER ;;
+/*!50003 SET @saved_cs_client = @@character_set_client */ ;;
+/*!50003 SET @saved_cs_results = @@character_set_results */ ;;
+/*!50003 SET @saved_col_connection = @@collation_connection */ ;;
+/*!50003 SET character_set_client = utf8mb4 */ ;;
+/*!50003 SET character_set_results = utf8mb4 */ ;;
+/*!50003 SET collation_connection = utf8mb4_unicode_ci */ ;;
+/*!50003 SET @saved_sql_mode = @@sql_mode */ ;;
+/*!50003 SET sql_mode = 'IGNORE_SPACE,NO_ENGINE_SUBSTITUTION' */ ;;
+/*!50003 SET @saved_time_zone = @@time_zone */ ;;
+/*!50003 SET time_zone = 'SYSTEM' */ ;;
+/*!50106 CREATE*/ /*!50117 DEFINER=`vn`@`localhost`*/ /*!50106 EVENT `client_setPackagesDiscountFactor` ON SCHEDULE EVERY 1 DAY STARTS '2024-10-18 03:00:00' ON COMPLETION PRESERVE ENABLE DO CALL client_setPackagesDiscountFactor() */ ;;
+/*!50003 SET time_zone = @saved_time_zone */ ;;
+/*!50003 SET sql_mode = @saved_sql_mode */ ;;
+/*!50003 SET character_set_client = @saved_cs_client */ ;;
+/*!50003 SET character_set_results = @saved_cs_results */ ;;
+/*!50003 SET collation_connection = @saved_col_connection */ ;;
/*!50106 DROP EVENT IF EXISTS `client_unassignSalesPerson` */;;
DELIMITER ;;
/*!50003 SET @saved_cs_client = @@character_set_client */ ;;
@@ -49224,7 +49329,19 @@ BEGIN
SELECT tcc.warehouseFK,
tcc.itemFk,
c2.id,
- z.inflation * ROUND(ic.cm3delivery * (IFNULL(zo.price,5000) - IFNULL(zo.bonus,0)) / (1000 * vc.standardFlowerBox) , 4) cost
+ z.inflation
+ * ROUND(
+ ic.cm3delivery
+ * (
+ (
+ zo.priceOptimum + (( zo.price - zo.priceOptimum) * 2 * ( 1 - c.packagesDiscountFactor))
+ )
+ - IFNULL(zo.bonus, 0)
+ )
+ / (1000 * vc.standardFlowerBox),
+ 4
+ ) cost
+
FROM tmp.ticketComponentCalculate tcc
JOIN item i ON i.id = tcc.itemFk
JOIN tmp.zoneOption zo ON zo.zoneFk = vZoneFk
@@ -49232,6 +49349,7 @@ BEGIN
JOIN agencyMode am ON am.id = z.agencyModeFk
JOIN vn.volumeConfig vc
JOIN vn.component c2 ON c2.code = 'delivery'
+ JOIN `client` c on c.id = vClientFk
LEFT JOIN itemCost ic ON ic.warehouseFk = tcc.warehouseFk
AND ic.itemFk = tcc.itemFk
HAVING cost <> 0;
@@ -50934,6 +51052,41 @@ BEGIN
ORDER BY clientFk;
+END ;;
+DELIMITER ;
+/*!50003 SET sql_mode = @saved_sql_mode */ ;
+/*!50003 SET character_set_client = @saved_cs_client */ ;
+/*!50003 SET character_set_results = @saved_cs_results */ ;
+/*!50003 SET collation_connection = @saved_col_connection */ ;
+/*!50003 SET @saved_sql_mode = @@sql_mode */ ;
+/*!50003 SET sql_mode = 'IGNORE_SPACE,NO_ENGINE_SUBSTITUTION' */ ;
+/*!50003 DROP PROCEDURE IF EXISTS `client_setPackagesDiscountFactor` */;
+/*!50003 SET @saved_cs_client = @@character_set_client */ ;
+/*!50003 SET @saved_cs_results = @@character_set_results */ ;
+/*!50003 SET @saved_col_connection = @@collation_connection */ ;
+/*!50003 SET character_set_client = utf8mb4 */ ;
+/*!50003 SET character_set_results = utf8mb4 */ ;
+/*!50003 SET collation_connection = utf8mb4_unicode_ci */ ;
+DELIMITER ;;
+CREATE DEFINER=`vn`@`localhost` PROCEDURE `client_setPackagesDiscountFactor`()
+BEGIN
+ /**
+ * Set the discount factor for the packages of the clients.
+ */
+ UPDATE client c
+ JOIN (
+ SELECT t.clientFk,
+ LEAST((
+ SUM(t.packages) / COUNT(DISTINCT DATE(t.shipped))
+ ) / cc.packagesOptimum, 1) discountFactor
+ FROM ticket t
+ JOIN clientConfig cc ON TRUE
+ WHERE t.shipped > util.VN_CURDATE() - INTERVAL cc.monthsToCalcOptimumPrice MONTH
+ AND t.packages
+ GROUP BY t.clientFk
+ ) ca ON c.id = ca.clientFk
+ SET c.packagesDiscountFactor = ca.discountFactor;
+
END ;;
DELIMITER ;
/*!50003 SET sql_mode = @saved_sql_mode */ ;
@@ -58727,6 +58880,7 @@ BEGIN
DECLARE vMaxShipped DATE;
DECLARE vDone BOOL;
DECLARE vTicketFk INT;
+ DECLARE vAddressFk INT;
DECLARE vCursor CURSOR FOR
SELECT id
FROM tmp.ticketToInvoice;
@@ -58741,11 +58895,13 @@ BEGIN
DATE(vInvoiceDate) >= invoiceOut_getMaxIssued(
vSerial,
t.companyFk,
- YEAR(vInvoiceDate))
+ YEAR(vInvoiceDate)),
+ t.addressFk
INTO vClientFk,
vCompanyFk,
vMaxShipped,
- vIsCorrectInvoiceDate
+ vIsCorrectInvoiceDate,
+ vAddressFk
FROM tmp.ticketToInvoice tt
JOIN ticket t ON t.id = tt.id;
@@ -58798,7 +58954,9 @@ BEGIN
clientFk,
dued,
companyFk,
- siiTypeInvoiceOutFk
+ siiTypeInvoiceOutFk,
+ customsAgentFk,
+ incotermsFk
)
SELECT
1,
@@ -58811,9 +58969,12 @@ BEGIN
vCplusCorrectingInvoiceTypeFk,
IF(vSerial = vSimplifiedSerial,
vCplusSimplifiedInvoiceTypeFk,
- vCplusStandardInvoiceTypeFk))
- FROM client
- WHERE id = vClientFk;
+ vCplusStandardInvoiceTypeFk)),
+ a.customsAgentFk,
+ a.incotermsFk
+ FROM client c
+ JOIN address a ON a.id = vAddressFk
+ WHERE c.id = vClientFk;
SET vNewInvoiceId = LAST_INSERT_ID();
@@ -67481,14 +67642,14 @@ DELIMITER ;
/*!50003 SET character_set_results = @saved_cs_results */ ;
/*!50003 SET collation_connection = @saved_col_connection */ ;
/*!50003 SET @saved_sql_mode = @@sql_mode */ ;
-/*!50003 SET sql_mode = 'IGNORE_SPACE,NO_ENGINE_SUBSTITUTION' */ ;
+/*!50003 SET sql_mode = 'NO_ENGINE_SUBSTITUTION' */ ;
/*!50003 DROP PROCEDURE IF EXISTS `remittance_calc` */;
/*!50003 SET @saved_cs_client = @@character_set_client */ ;
/*!50003 SET @saved_cs_results = @@character_set_results */ ;
/*!50003 SET @saved_col_connection = @@collation_connection */ ;
/*!50003 SET character_set_client = utf8mb4 */ ;
/*!50003 SET character_set_results = utf8mb4 */ ;
-/*!50003 SET collation_connection = utf8mb4_unicode_ci */ ;
+/*!50003 SET collation_connection = utf8mb4_general_ci */ ;
DELIMITER ;;
CREATE DEFINER=`vn`@`localhost` PROCEDURE `remittance_calc`(
vDated DATE
@@ -67552,7 +67713,7 @@ BEGIN
) risk ON risk.clientFk = c.id
GROUP BY risk.companyFk, c.id
- HAVING receipt > 10
+ HAVING receipt > 1
) sub ON sub.id = c.id
JOIN supplier s ON s.id = sub.companyFk
JOIN company co ON co.id = sub.companyFk
@@ -68661,10 +68822,11 @@ BEGIN
TRUE,
sc.userFk,
s.id
- FROM vn.sectorCollection sc
- JOIN vn.sectorCollectionSaleGroup scsg ON scsg.sectorCollectionFk = sc.id
- JOIN vn.saleGroupDetail sgd ON sgd.saleGroupFk = scsg.saleGroupFk
- JOIN vn.state s ON s.code = 'OK PREVIOUS'
+ FROM sectorCollection sc
+ JOIN sectorCollectionSaleGroup scsg ON scsg.sectorCollectionFk = sc.id
+ JOIN saleGroupDetail sgd ON sgd.saleGroupFk = scsg.saleGroupFk
+ JOIN state s ON s.code = 'OK PREVIOUS'
+ JOIN itemShelvingSale iss ON iss.saleFk = sgd.saleFk
WHERE sc.id = vSectorCollectionFk;
END ;;
DELIMITER ;
@@ -74493,9 +74655,6 @@ BEGIN
IFNULL(sat.supplierFk, su.id) supplierFk,
t.landed
FROM ticket t
- JOIN ticketState ts ON ts.ticketFk = t.id
- JOIN `state` s ON s.id = ts.stateFk
- JOIN alertLevel al ON al.id = s.alertLevel
JOIN client c ON c.id = t.clientFk
JOIN `address` a ON a.id = t.addressFk
JOIN province p ON p.id = a.provinceFk
@@ -74512,8 +74671,7 @@ BEGIN
LEFT JOIN agency ag ON ag.id = am.agencyFk
LEFT JOIN supplierAgencyTerm sat ON sat.agencyFk = ag.id
AND wo.isFreelance
- WHERE al.code IN ('PACKED', 'DELIVERED')
- AND co.code <> 'ES'
+ WHERE co.code <> 'ES'
AND am.name <> 'ABONO'
AND w.code = 'ALG'
AND t.id = vSelf
@@ -81580,26 +81738,27 @@ DELIMITER ;
DELIMITER ;;
CREATE DEFINER=`vn`@`localhost` PROCEDURE `zone_getAddresses`(
vSelf INT,
- vShipped DATE,
+ vLanded DATE,
vDepartmentFk INT
)
BEGIN
/**
* Devuelve un listado de todos los clientes activos
* con consignatarios a los que se les puede
- * vender producto para esa zona.
+ * entregar producto para esa zona.
*
* @param vSelf Id de zona
- * @param vShipped Fecha de envio
- * @param vDepartmentFk Id de departamento
+ * @param vLanded Fecha de entrega
+ * @param vDepartmentFk Id de departamento | NULL para mostrar todos
* @return Un select
*/
CALL zone_getPostalCode(vSelf);
WITH clientWithTicket AS (
- SELECT clientFk
+ SELECT DISTINCT clientFk
FROM vn.ticket
- WHERE shipped BETWEEN vShipped AND util.dayEnd(vShipped)
+ WHERE landed BETWEEN vLanded AND util.dayEnd(vLanded)
+ AND NOT isDeleted
)
SELECT c.id,
c.name,
@@ -81609,7 +81768,7 @@ BEGIN
u.name username,
aai.invoiced,
cnb.lastShipped,
- cwt.clientFk
+ IF(cwt.clientFk, TRUE, FALSE) hasTicket
FROM vn.client c
JOIN vn.worker w ON w.id = c.salesPersonFk
JOIN vn.workerDepartment wd ON wd.workerFk = w.id
@@ -81629,7 +81788,7 @@ BEGIN
AND c.isActive
AND ct.code = 'normal'
AND bt.code <> 'worker'
- AND (d.id = vDepartmentFk OR NOT vDepartmentFk)
+ AND (d.id = vDepartmentFk OR vDepartmentFk IS NULL)
GROUP BY c.id;
DROP TEMPORARY TABLE tmp.zoneNodes;
@@ -82321,7 +82480,7 @@ BEGIN
* @return tmp.zoneOption(zoneFk, hour, travelingDays, price, bonus, specificity) The computed options
*/
DECLARE vHour TIME DEFAULT TIME(util.VN_NOW());
-
+
DROP TEMPORARY TABLE IF EXISTS tLandings;
CREATE TEMPORARY TABLE tLandings
(INDEX (eventFk))
@@ -82342,6 +82501,7 @@ BEGIN
TIME(IFNULL(e.`hour`, z.`hour`)) `hour`,
l.travelingDays,
IFNULL(e.price, z.price) price,
+ IFNULL(e.priceOptimum, z.priceOptimum) priceOptimum,
IFNULL(e.bonus, z.bonus) bonus,
l.landed,
vShipped shipped
@@ -90882,4 +91042,4 @@ USE `vn2008`;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
--- Dump completed on 2025-01-07 6:51:38
+-- Dump completed on 2025-01-28 7:08:42
diff --git a/db/dump/.dump/triggers.sql b/db/dump/.dump/triggers.sql
index 039dbb2a86..4f7bab43b8 100644
--- a/db/dump/.dump/triggers.sql
+++ b/db/dump/.dump/triggers.sql
@@ -6804,6 +6804,30 @@ DELIMITER ;;
FOR EACH ROW
BEGIN
SET NEW.editorFk = account.myUser_getId();
+
+ IF NOT(NEW.`countryFk` <=> OLD.`countryFk`) OR NOT(NEW.`itemFk` <=> OLD.`itemFk`) THEN
+ CALL util.throw('Only the VAT can be modified');
+ END IF;
+END */;;
+DELIMITER ;
+/*!50003 SET sql_mode = @saved_sql_mode */ ;
+/*!50003 SET character_set_client = @saved_cs_client */ ;
+/*!50003 SET character_set_results = @saved_cs_results */ ;
+/*!50003 SET collation_connection = @saved_col_connection */ ;
+/*!50003 SET @saved_cs_client = @@character_set_client */ ;
+/*!50003 SET @saved_cs_results = @@character_set_results */ ;
+/*!50003 SET @saved_col_connection = @@collation_connection */ ;
+/*!50003 SET character_set_client = utf8mb4 */ ;
+/*!50003 SET character_set_results = utf8mb4 */ ;
+/*!50003 SET collation_connection = utf8mb4_unicode_ci */ ;
+/*!50003 SET @saved_sql_mode = @@sql_mode */ ;
+/*!50003 SET sql_mode = 'IGNORE_SPACE,NO_ENGINE_SUBSTITUTION' */ ;
+DELIMITER ;;
+/*!50003 CREATE*/ /*!50017 DEFINER=`vn`@`localhost`*/ /*!50003 TRIGGER `vn`.`itemTaxCountry_beforeDelete`
+ BEFORE DELETE ON `itemTaxCountry`
+ FOR EACH ROW
+BEGIN
+ CALL util.throw('Records in this table cannot be deleted');
END */;;
DELIMITER ;
/*!50003 SET sql_mode = @saved_sql_mode */ ;
@@ -11019,6 +11043,92 @@ DELIMITER ;
/*!50003 SET @saved_sql_mode = @@sql_mode */ ;
/*!50003 SET sql_mode = 'IGNORE_SPACE,NO_ENGINE_SUBSTITUTION' */ ;
DELIMITER ;;
+/*!50003 CREATE*/ /*!50017 DEFINER=`vn`@`localhost`*/ /*!50003 TRIGGER `vn`.`workerMana_beforeInsert`
+ BEFORE INSERT ON `workerMana`
+ FOR EACH ROW
+BEGIN
+ IF (SELECT EXISTS(SELECT TRUE FROM workerManaExcluded WHERE workerFk = NEW.workerFk)) THEN
+ CALL util.throw('Worker is excluded from mana');
+ END IF;
+END */;;
+DELIMITER ;
+/*!50003 SET sql_mode = @saved_sql_mode */ ;
+/*!50003 SET character_set_client = @saved_cs_client */ ;
+/*!50003 SET character_set_results = @saved_cs_results */ ;
+/*!50003 SET collation_connection = @saved_col_connection */ ;
+/*!50003 SET @saved_cs_client = @@character_set_client */ ;
+/*!50003 SET @saved_cs_results = @@character_set_results */ ;
+/*!50003 SET @saved_col_connection = @@collation_connection */ ;
+/*!50003 SET character_set_client = utf8mb4 */ ;
+/*!50003 SET character_set_results = utf8mb4 */ ;
+/*!50003 SET collation_connection = utf8mb4_unicode_ci */ ;
+/*!50003 SET @saved_sql_mode = @@sql_mode */ ;
+/*!50003 SET sql_mode = 'IGNORE_SPACE,NO_ENGINE_SUBSTITUTION' */ ;
+DELIMITER ;;
+/*!50003 CREATE*/ /*!50017 DEFINER=`vn`@`localhost`*/ /*!50003 TRIGGER `vn`.`workerMana_beforeUpdate`
+ BEFORE UPDATE ON `workerMana`
+ FOR EACH ROW
+BEGIN
+ IF (SELECT EXISTS(SELECT TRUE FROM workerManaExcluded WHERE workerFk = NEW.workerFk)) THEN
+ CALL util.throw('Worker is excluded from mana');
+ END IF;
+END */;;
+DELIMITER ;
+/*!50003 SET sql_mode = @saved_sql_mode */ ;
+/*!50003 SET character_set_client = @saved_cs_client */ ;
+/*!50003 SET character_set_results = @saved_cs_results */ ;
+/*!50003 SET collation_connection = @saved_col_connection */ ;
+/*!50003 SET @saved_cs_client = @@character_set_client */ ;
+/*!50003 SET @saved_cs_results = @@character_set_results */ ;
+/*!50003 SET @saved_col_connection = @@collation_connection */ ;
+/*!50003 SET character_set_client = utf8mb4 */ ;
+/*!50003 SET character_set_results = utf8mb4 */ ;
+/*!50003 SET collation_connection = utf8mb4_unicode_ci */ ;
+/*!50003 SET @saved_sql_mode = @@sql_mode */ ;
+/*!50003 SET sql_mode = 'IGNORE_SPACE,NO_ENGINE_SUBSTITUTION' */ ;
+DELIMITER ;;
+/*!50003 CREATE*/ /*!50017 DEFINER=`vn`@`localhost`*/ /*!50003 TRIGGER `vn`.`workerManaExcluded_beforeInsert`
+ BEFORE INSERT ON `workerManaExcluded`
+ FOR EACH ROW
+BEGIN
+ DELETE FROM workerMana
+ WHERE workerFk = NEW.workerFk;
+END */;;
+DELIMITER ;
+/*!50003 SET sql_mode = @saved_sql_mode */ ;
+/*!50003 SET character_set_client = @saved_cs_client */ ;
+/*!50003 SET character_set_results = @saved_cs_results */ ;
+/*!50003 SET collation_connection = @saved_col_connection */ ;
+/*!50003 SET @saved_cs_client = @@character_set_client */ ;
+/*!50003 SET @saved_cs_results = @@character_set_results */ ;
+/*!50003 SET @saved_col_connection = @@collation_connection */ ;
+/*!50003 SET character_set_client = utf8mb4 */ ;
+/*!50003 SET character_set_results = utf8mb4 */ ;
+/*!50003 SET collation_connection = utf8mb4_unicode_ci */ ;
+/*!50003 SET @saved_sql_mode = @@sql_mode */ ;
+/*!50003 SET sql_mode = 'IGNORE_SPACE,NO_ENGINE_SUBSTITUTION' */ ;
+DELIMITER ;;
+/*!50003 CREATE*/ /*!50017 DEFINER=`vn`@`localhost`*/ /*!50003 TRIGGER `vn`.`workerManaExcluded_beforeUpdate`
+ BEFORE UPDATE ON `workerManaExcluded`
+ FOR EACH ROW
+BEGIN
+ DELETE FROM workerMana
+ WHERE workerFk = NEW.workerFk;
+END */;;
+DELIMITER ;
+/*!50003 SET sql_mode = @saved_sql_mode */ ;
+/*!50003 SET character_set_client = @saved_cs_client */ ;
+/*!50003 SET character_set_results = @saved_cs_results */ ;
+/*!50003 SET collation_connection = @saved_col_connection */ ;
+/*!50003 SET @saved_cs_client = @@character_set_client */ ;
+/*!50003 SET @saved_cs_results = @@character_set_results */ ;
+/*!50003 SET @saved_col_connection = @@collation_connection */ ;
+/*!50003 SET character_set_client = utf8mb4 */ ;
+/*!50003 SET character_set_results = utf8mb4 */ ;
+/*!50003 SET collation_connection = utf8mb4_unicode_ci */ ;
+/*!50003 SET @saved_sql_mode = @@sql_mode */ ;
+/*!50003 SET sql_mode = 'IGNORE_SPACE,NO_ENGINE_SUBSTITUTION' */ ;
+DELIMITER ;;
/*!50003 CREATE*/ /*!50017 DEFINER=`vn`@`localhost`*/ /*!50003 TRIGGER `vn`.`workerTimeControl_beforeInsert`
BEFORE INSERT ON `workerTimeControl`
FOR EACH ROW
@@ -11085,11 +11195,13 @@ DELIMITER ;;
AFTER DELETE ON `workerTimeControl`
FOR EACH ROW
BEGIN
- INSERT INTO workerLog
- SET `action` = 'delete',
- `changedModel` = 'WorkerTimeControl',
- `changedModelId` = OLD.id,
- `userFk` = account.myUser_getId();
+ IF account.myUser_getId() IS NOT NULL THEN
+ INSERT INTO workerLog
+ SET `action` = 'delete',
+ `changedModel` = 'WorkerTimeControl',
+ `changedModelId` = OLD.id,
+ `userFk` = account.myUser_getId();
+ END IF;
END */;;
DELIMITER ;
/*!50003 SET sql_mode = @saved_sql_mode */ ;
@@ -11499,4 +11611,4 @@ USE `vn2008`;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
--- Dump completed on 2025-01-07 6:51:57
+-- Dump completed on 2025-01-28 7:09:01
diff --git a/db/dump/fixtures.before.sql b/db/dump/fixtures.before.sql
index ff896b84d2..30c49aafc9 100644
--- a/db/dump/fixtures.before.sql
+++ b/db/dump/fixtures.before.sql
@@ -158,13 +158,13 @@ INSERT INTO `account`.`mailForward`(`account`, `forwardTo`)
-INSERT INTO `vn`.`currency`(`id`, `code`, `name`, `ratio`)
+INSERT INTO `vn`.`currency`(`id`, `code`, `name`, `ratio`, `hasToDownloadRate`)
VALUES
- (1, 'EUR', 'Euro', 1),
- (2, 'USD', 'Dollar USA', 1.4),
- (3, 'GBP', 'Libra', 1),
- (4, 'JPY', 'Yen Japones', 1),
- (5, 'CNY', 'Yuan Chino', 1.2);
+ (1, 'EUR', 'Euro', 1, FALSE),
+ (2, 'USD', 'Dollar USA', 1.4, TRUE),
+ (3, 'GBP', 'Libra', 1, TRUE),
+ (4, 'JPY', 'Yen Japones', 1, FALSE),
+ (5, 'CNY', 'Yuan Chino', 1.2, TRUE);
INSERT INTO `vn`.`country`(`id`, `name`, `isUeeMember`, `code`, `currencyFk`, `ibanLength`, `continentFk`, `hasDailyInvoice`, `CEE`)
VALUES
@@ -321,6 +321,11 @@ UPDATE `vn`.`agencyMode` SET `web` = 1, `reportMail` = 'no-reply@gothamcity.com'
UPDATE `vn`.`agencyMode` SET `code` = 'refund' WHERE `id` = 23;
+INSERT INTO `vn`.`agencyIncoming`(`agencyModeFk`)
+ VALUES
+ (1),
+ (2);
+
INSERT INTO `vn`.`payMethod`(`id`,`code`, `name`, `graceDays`, `outstandingDebt`, `isIbanRequiredForClients`, `isIbanRequiredForSuppliers`, `hasVerified`)
VALUES
(1, NULL, 'PayMethod one', 0, 001, 0, 0, 0),
@@ -694,22 +699,22 @@ INSERT INTO `vn`.`invoiceOutExpense`(`id`, `invoiceOutFk`, `amount`, `expenseFk`
(6, 4, 8.07, 2000000000, util.VN_CURDATE()),
(7, 5, 8.07, 2000000000, util.VN_CURDATE());
-INSERT INTO `vn`.`zone` (`id`, `name`, `hour`, `agencyModeFk`, `travelingDays`, `price`, `bonus`, `itemMaxSize`)
- VALUES
- (1, 'Zone pickup A', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 1, 0, 1, 0, 100),
- (2, 'Zone pickup B', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 1, 0, 1, 0, 100),
- (3, 'Zone 247 A', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 7, 1, 2, 0, 100),
- (4, 'Zone 247 B', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 7, 1, 2, 0, 100),
- (5, 'Zone expensive A', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 8, 1, 1000, 0, 100),
- (6, 'Zone expensive B', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 8, 1, 1000, 0, 100),
- (7, 'Zone refund', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 23, 0, 1, 0, 100),
- (8, 'Zone others', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 10, 0, 1, 0, 100),
- (9, 'Zone superMan', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 2, 0, 1, 0, 100),
- (10, 'Zone teleportation', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 3, 0, 1, 0, 100),
- (11, 'Zone pickup C', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 1, 0, 1, 0, 100),
- (12, 'Zone entanglement', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 4, 0, 1, 0, 100),
- (13, 'Zone quantum break', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 5, 0, 1, 0, 100);
-
+INSERT INTO `vn`.`zone`
+ (`id`, `name`, `hour`, `agencyModeFk`, `travelingDays`, `price`, `bonus`, `itemMaxSize`, `priceOptimum`)
+VALUES
+ (1, 'Zone pickup A', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 1, 0, 1, 0, 100, 1),
+ (2, 'Zone pickup B', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 1, 0, 1, 0, 100, 1),
+ (3, 'Zone 247 A', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 7, 1, 2, 0, 100, 1),
+ (4, 'Zone 247 B', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 7, 1, 2, 0, 100, 1),
+ (5, 'Zone expensive A', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 8, 1, 1000, 0, 100, 500),
+ (6, 'Zone expensive B', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 8, 1, 1000, 0, 100, 500),
+ (7, 'Zone refund', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 23, 0, 1, 0, 100, 0.5),
+ (8, 'Zone others', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 10, 0, 1, 0, 100, 0.5),
+ (9, 'Zone superMan', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 2, 0, 1, 0, 100, 0.5),
+ (10, 'Zone teleportation', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 3, 0, 1, 0, 100, 0.5),
+ (11, 'Zone pickup C', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 1, 0, 1, 0, 100, 0.5),
+ (12, 'Zone entanglement', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 4, 0, 1, 0, 100, 0.5),
+ (13, 'Zone quantum break', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 5, 0, 1, 0, 100, 0.5);
INSERT INTO `vn`.`zoneWarehouse` (`id`, `zoneFk`, `warehouseFk`)
VALUES
diff --git a/db/routines/bs/procedures/ventas_contables_add.sql b/db/routines/bs/procedures/ventas_contables_add.sql
index 72b0c0feed..c82cb96d9c 100644
--- a/db/routines/bs/procedures/ventas_contables_add.sql
+++ b/db/routines/bs/procedures/ventas_contables_add.sql
@@ -15,7 +15,7 @@ BEGIN
DELETE FROM bs.ventas_contables
WHERE year = vYear
- AND month = vMonth;
+ AND month = vMonth;
DROP TEMPORARY TABLE IF EXISTS tmp.ticket_list;
CREATE TEMPORARY TABLE tmp.ticket_list
diff --git a/db/routines/vn/events/client_setPackagesDiscountFactor.sql b/db/routines/vn/events/client_setPackagesDiscountFactor.sql
new file mode 100644
index 0000000000..a0dc33cac3
--- /dev/null
+++ b/db/routines/vn/events/client_setPackagesDiscountFactor.sql
@@ -0,0 +1,8 @@
+DELIMITER $$
+CREATE OR REPLACE DEFINER=`vn`@`localhost` EVENT `vn`.`client_setPackagesDiscountFactor`
+ ON SCHEDULE EVERY 1 DAY
+ STARTS '2024-10-18 03:00:00.000'
+ ON COMPLETION PRESERVE
+ ENABLE
+DO CALL client_setPackagesDiscountFactor()$$
+DELIMITER ;
diff --git a/db/routines/vn/procedures/catalog_componentCalculate.sql b/db/routines/vn/procedures/catalog_componentCalculate.sql
index e29e13a8c4..aaf2db408d 100644
--- a/db/routines/vn/procedures/catalog_componentCalculate.sql
+++ b/db/routines/vn/procedures/catalog_componentCalculate.sql
@@ -231,7 +231,19 @@ BEGIN
SELECT tcc.warehouseFK,
tcc.itemFk,
c2.id,
- z.inflation * ROUND(ic.cm3delivery * (IFNULL(zo.price,5000) - IFNULL(zo.bonus,0)) / (1000 * vc.standardFlowerBox) , 4) cost
+ z.inflation
+ * ROUND(
+ ic.cm3delivery
+ * (
+ (
+ zo.priceOptimum + (( zo.price - zo.priceOptimum) * 2 * ( 1 - c.packagesDiscountFactor))
+ )
+ - IFNULL(zo.bonus, 0)
+ )
+ / (1000 * vc.standardFlowerBox),
+ 4
+ ) cost
+
FROM tmp.ticketComponentCalculate tcc
JOIN item i ON i.id = tcc.itemFk
JOIN tmp.zoneOption zo ON zo.zoneFk = vZoneFk
@@ -239,6 +251,7 @@ BEGIN
JOIN agencyMode am ON am.id = z.agencyModeFk
JOIN vn.volumeConfig vc
JOIN vn.component c2 ON c2.code = 'delivery'
+ JOIN `client` c on c.id = vClientFk
LEFT JOIN itemCost ic ON ic.warehouseFk = tcc.warehouseFk
AND ic.itemFk = tcc.itemFk
HAVING cost <> 0;
diff --git a/db/routines/vn/procedures/client_setPackagesDiscountFactor.sql b/db/routines/vn/procedures/client_setPackagesDiscountFactor.sql
new file mode 100644
index 0000000000..f6068ca375
--- /dev/null
+++ b/db/routines/vn/procedures/client_setPackagesDiscountFactor.sql
@@ -0,0 +1,25 @@
+DELIMITER $$
+
+CREATE OR REPLACE DEFINER=`vn`@`localhost`
+PROCEDURE `vn`.`client_setPackagesDiscountFactor`()
+BEGIN
+ /**
+ * Set the discount factor for the packages of the clients.
+ */
+ UPDATE client c
+ JOIN (
+ SELECT t.clientFk,
+ LEAST((
+ SUM(t.packages) / COUNT(DISTINCT DATE(t.shipped))
+ ) / cc.packagesOptimum, 1) discountFactor
+ FROM ticket t
+ JOIN clientConfig cc ON TRUE
+ WHERE t.shipped > util.VN_CURDATE() - INTERVAL cc.monthsToCalcOptimumPrice MONTH
+ AND t.packages
+ GROUP BY t.clientFk
+ ) ca ON c.id = ca.clientFk
+ SET c.packagesDiscountFactor = ca.discountFactor;
+
+END$$
+
+DELIMITER ;
diff --git a/db/routines/vn/procedures/entry_clone.sql b/db/routines/vn/procedures/entry_clone.sql
index a0ed39c295..511ff4837f 100644
--- a/db/routines/vn/procedures/entry_clone.sql
+++ b/db/routines/vn/procedures/entry_clone.sql
@@ -1,20 +1,31 @@
DELIMITER $$
-CREATE OR REPLACE DEFINER=`vn`@`localhost` PROCEDURE `vn`.`entry_clone`(vSelf INT)
+CREATE OR REPLACE DEFINER=`vn`@`localhost` PROCEDURE `vn`.`entry_clone`(
+ vSelf INT,
+ OUT vOutputEntryFk INT
+)
BEGIN
/**
* clones an entry.
*
* @param vSelf The entry id
+ * @param vOutputEntryFk The new entry id
*/
DECLARE vNewEntryFk INT;
- START TRANSACTION;
+ DECLARE vIsRequiredTx BOOL DEFAULT NOT @@in_transaction;
+ DECLARE EXIT HANDLER FOR SQLEXCEPTION
+ BEGIN
+ CALL util.tx_rollback(vIsRequiredTx);
+ RESIGNAL;
+ END;
+
+ CALL util.tx_start(vIsRequiredTx);
CALL entry_cloneHeader(vSelf, vNewEntryFk, NULL);
CALL entry_copyBuys(vSelf, vNewEntryFk);
- COMMIT;
+ CALL util.tx_commit(vIsRequiredTx);
+ SET vOutputEntryFk = vNewEntryFk;
- SELECT vNewEntryFk;
END$$
DELIMITER ;
diff --git a/db/routines/vn/procedures/entry_splitByShelving.sql b/db/routines/vn/procedures/entry_splitByShelving.sql
index f5de360980..019abe6cb1 100644
--- a/db/routines/vn/procedures/entry_splitByShelving.sql
+++ b/db/routines/vn/procedures/entry_splitByShelving.sql
@@ -39,14 +39,14 @@ BEGIN
read_loop: LOOP
SET vDone = FALSE;
-
+
FETCH cur INTO vBuyFk, vIshStickers, vBuyStickers;
IF vDone THEN
LEAVE read_loop;
END IF;
- IF vIshStickers = vBuyStickers THEN
+ IF vIshStickers = vBuyStickers THEN
UPDATE buy
SET entryFk = vToEntryFk
WHERE id = vBuyFk;
diff --git a/db/routines/vn/procedures/entry_transfer.sql b/db/routines/vn/procedures/entry_transfer.sql
new file mode 100644
index 0000000000..5b83ae5321
--- /dev/null
+++ b/db/routines/vn/procedures/entry_transfer.sql
@@ -0,0 +1,158 @@
+DELIMITER $$
+CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`entry_transfer`(
+ vOriginalEntry INT,
+ OUT vNewEntryFk INT
+ )
+BEGIN
+/**
+ * Adelanta a mañana la mercancia de una entrada a partir de lo que hay ubicado en el almacén
+ *
+ * @param vOriginalEntry entrada que se quiera adelantar
+ * @param vNewEntry nueva entrada creada
+ */
+ DECLARE vTravelFk INT;
+ DECLARE vWarehouseFk INT;
+ DECLARE vWarehouseInFk INT;
+ DECLARE vWarehouseOutFk INT;
+ DECLARE vRef INT;
+ DECLARE vIsReceived INT;
+ DECLARE vAgencyModeFk INT;
+ DECLARE vTomorrow DATETIME DEFAULT util.tomorrow();
+ DECLARE vCurDate DATE DEFAULT util.VN_CURDATE();
+
+ DECLARE vIsRequiredTx BOOL DEFAULT NOT @@in_transaction;
+ DECLARE EXIT HANDLER FOR SQLEXCEPTION
+ BEGIN
+ CALL util.tx_rollback(vIsRequiredTx);
+ RESIGNAL;
+ END;
+
+ -- Clonar la entrada
+ CALL entry_clone(vOriginalEntry, vNewEntryFk);
+
+ CALL util.tx_start(vIsRequiredTx);
+
+ /* Hay que crear un nuevo travel, con salida hoy y llegada mañana y
+ asignar la entrada nueva al nuevo travel.*/
+ SELECT t.warehouseInFk, t.warehouseOutFk, t.`ref`, t.isReceived, t.agencyModeFk
+ INTO vWarehouseInFk, vWarehouseOutFk, vRef, vIsReceived, vAgencyModeFk
+ FROM travel t
+ JOIN entry e ON e.travelFk = t.id
+ WHERE e.id = vOriginalEntry;
+
+ SELECT id INTO vTravelFk
+ FROM travel t
+ WHERE shipped = vCurDate
+ AND landed = vTomorrow
+ AND warehouseInFk = vWarehouseInFk
+ AND warehouseOutFk = vWarehouseOutFk
+ AND `ref` = vRef
+ AND isReceived =vIsReceived
+ AND agencyModeFk = vAgencyModeFk;
+
+ IF vTravelFk IS NULL THEN
+ INSERT INTO travel(
+ shipped,
+ landed,
+ warehouseInFk,
+ warehouseOutFk,
+ `ref`,
+ isReceived,
+ agencyModeFk)
+ SELECT vCurDate,
+ vTomorrow,
+ t.warehouseInFk,
+ t.warehouseOutFk,
+ t.`ref`,
+ t.isReceived,
+ t.agencyModeFk
+ FROM travel t
+ JOIN entry e ON e.travelFk = t.id
+ WHERE e.id = vOriginalEntry;
+
+ SET vTravelFk = LAST_INSERT_ID();
+ END IF;
+
+ UPDATE entry
+ SET travelFk = vTravelFk,
+ evaNotes = vOriginalEntry
+ WHERE id = vNewEntryFk;
+
+ -- Poner a 0 las cantidades
+ UPDATE buy b
+ SET b.quantity = 0, b.stickers = 0
+ WHERE b.entryFk = vNewEntryFk;
+
+ -- Eliminar duplicados
+ DELETE b
+ FROM buy b
+ LEFT JOIN (SELECT b.id, b.itemFk
+ FROM buy b
+ WHERE b.entryFk = vNewEntryFk
+ GROUP BY b.itemFk) tBuy ON tBuy.id = b.id
+ WHERE b.entryFk = vNewEntryFk
+ AND tBuy.id IS NULL;
+
+ SELECT t.warehouseInFk INTO vWarehouseFk
+ FROM travel t
+ JOIN entry e ON e.travelFk = t.id
+ WHERE e.id = vOriginalEntry;
+
+ /* Actualizar nueva entrada con lo que no está ubicado HOY,
+ descontando lo vendido HOY de esas ubicaciones*/
+ CREATE OR REPLACE TEMPORARY TABLE buys
+ WITH tBuy AS (
+ SELECT b.itemFk, SUM(b.quantity) totalQuantity
+ FROM vn.buy b
+ WHERE b.entryFk = vOriginalEntry
+ GROUP BY b.itemFk
+ ),
+ itemShelvings AS (
+ SELECT ish.itemFk, SUM(ish.visible) visible
+ FROM vn.itemShelving ish
+ JOIN vn.shelving sh ON sh.id = ish.shelvingFk
+ JOIN vn.parking p ON p.id = sh.parkingFk
+ JOIN vn.sector s ON s.id = p.sectorFk
+ JOIN vn.buy b ON b.id = ish.buyFk
+ JOIN vn.entry e ON e.id = b.entryFk
+ JOIN tBuy t ON t.itemFk = ish.itemFk
+ WHERE s.warehouseFk = vWarehouseFk
+ AND sh.parked >= vCurDate
+ GROUP BY ish.itemFk
+ ),
+ sales AS (
+ SELECT s.itemFk, SUM(s.quantity) sold
+ FROM vn.ticket t
+ JOIN vn.sale s ON s.ticketFk = t.id
+ JOIN vn.itemShelvingSale iss ON iss.saleFk = s.id
+ JOIN vn.itemShelving is2 ON is2.id = iss.itemShelvingFk
+ JOIN vn.shelving s2 ON s2.id = is2.shelvingFk
+ JOIN tBuy t ON t.itemFk = s.itemFk
+ WHERE t.shipped BETWEEN vCurDate AND util.dayend(vCurDate)
+ AND s2.parked >= vCurDate
+ GROUP BY s.itemFk
+ )
+ SELECT tmp.itemFk,
+ IFNULL(iss.visible, 0) visible,
+ tmp.totalQuantity,
+ IFNULL(s.sold, 0) sold
+ FROM tBuy tmp
+ LEFT JOIN itemShelvings iss ON tmp.itemFk = iss.itemFk
+ LEFT JOIN sales s ON s.itemFk = tmp.itemFk
+ WHERE visible < tmp.totalQuantity
+ OR iss.itemFk IS NULL;
+
+ UPDATE buy b
+ JOIN buys tmp ON tmp.itemFk = b.itemFk
+ SET b.quantity = tmp.totalQuantity - tmp.visible - tmp.sold
+ WHERE b.entryFk = vNewEntryFk;
+
+ -- Limpia la nueva entrada
+ DELETE FROM buy WHERE entryFk = vNewEntryFk AND quantity = 0;
+
+ CALL util.tx_commit(vIsRequiredTx);
+
+ CALL cache.visible_refresh(@c,TRUE,vWarehouseFk);
+ CALL cache.available_refresh(@c, TRUE, vWarehouseFk, vCurDate);
+END$$
+DELIMITER ;
diff --git a/db/routines/vn/procedures/saleTracking_addPrevOK.sql b/db/routines/vn/procedures/saleTracking_addPrevOK.sql
index 34d1cfac8c..9f823e9a09 100644
--- a/db/routines/vn/procedures/saleTracking_addPrevOK.sql
+++ b/db/routines/vn/procedures/saleTracking_addPrevOK.sql
@@ -16,10 +16,11 @@ BEGIN
TRUE,
sc.userFk,
s.id
- FROM vn.sectorCollection sc
- JOIN vn.sectorCollectionSaleGroup scsg ON scsg.sectorCollectionFk = sc.id
- JOIN vn.saleGroupDetail sgd ON sgd.saleGroupFk = scsg.saleGroupFk
- JOIN vn.state s ON s.code = 'OK PREVIOUS'
+ FROM sectorCollection sc
+ JOIN sectorCollectionSaleGroup scsg ON scsg.sectorCollectionFk = sc.id
+ JOIN saleGroupDetail sgd ON sgd.saleGroupFk = scsg.saleGroupFk
+ JOIN state s ON s.code = 'OK PREVIOUS'
+ JOIN itemShelvingSale iss ON iss.saleFk = sgd.saleFk
WHERE sc.id = vSectorCollectionFk;
END$$
DELIMITER ;
diff --git a/db/routines/vn/procedures/ticket_canbePostponed.sql b/db/routines/vn/procedures/ticket_canbePostponed.sql
index 82c5da3748..b4b0871cec 100644
--- a/db/routines/vn/procedures/ticket_canbePostponed.sql
+++ b/db/routines/vn/procedures/ticket_canbePostponed.sql
@@ -19,6 +19,7 @@ BEGIN
sub2.iptd futureIpt,
sub2.state futureState,
t.clientFk,
+ cl.salespersonFk,
t.warehouseFk,
ts.alertLevel,
sub2.alertLevel futureAlertLevel,
@@ -38,6 +39,7 @@ BEGIN
JOIN vn.province p ON p.id = a.provinceFk
JOIN vn.country c ON c.id = p.countryFk
JOIN vn.ticketState ts ON ts.ticketFk = t.id
+ JOIN vn.client cl ON cl.id = t.clientFk
JOIN vn.state st ON st.id = ts.stateFk
JOIN vn.alertLevel al ON al.id = ts.alertLevel
LEFT JOIN vn.ticketParking tp ON tp.ticketFk = t.id
diff --git a/db/routines/vn/procedures/ticket_doCmr.sql b/db/routines/vn/procedures/ticket_doCmr.sql
index ba64944f87..59bb3e0704 100644
--- a/db/routines/vn/procedures/ticket_doCmr.sql
+++ b/db/routines/vn/procedures/ticket_doCmr.sql
@@ -21,9 +21,6 @@ BEGIN
IFNULL(sat.supplierFk, su.id) supplierFk,
t.landed
FROM ticket t
- JOIN ticketState ts ON ts.ticketFk = t.id
- JOIN `state` s ON s.id = ts.stateFk
- JOIN alertLevel al ON al.id = s.alertLevel
JOIN client c ON c.id = t.clientFk
JOIN `address` a ON a.id = t.addressFk
JOIN province p ON p.id = a.provinceFk
@@ -40,8 +37,7 @@ BEGIN
LEFT JOIN agency ag ON ag.id = am.agencyFk
LEFT JOIN supplierAgencyTerm sat ON sat.agencyFk = ag.id
AND wo.isFreelance
- WHERE al.code IN ('PACKED', 'DELIVERED')
- AND co.code <> 'ES'
+ WHERE co.code <> 'ES'
AND am.name <> 'ABONO'
AND w.code = 'ALG'
AND t.id = vSelf
diff --git a/db/routines/vn/procedures/zone_getAddresses.sql b/db/routines/vn/procedures/zone_getAddresses.sql
index 2e5982c822..9946b0b732 100644
--- a/db/routines/vn/procedures/zone_getAddresses.sql
+++ b/db/routines/vn/procedures/zone_getAddresses.sql
@@ -1,26 +1,27 @@
DELIMITER $$
CREATE OR REPLACE DEFINER=`vn`@`localhost` PROCEDURE `vn`.`zone_getAddresses`(
vSelf INT,
- vShipped DATE,
+ vLanded DATE,
vDepartmentFk INT
)
BEGIN
/**
* Devuelve un listado de todos los clientes activos
* con consignatarios a los que se les puede
- * vender producto para esa zona.
+ * entregar producto para esa zona.
*
* @param vSelf Id de zona
- * @param vShipped Fecha de envio
- * @param vDepartmentFk Id de departamento
+ * @param vLanded Fecha de entrega
+ * @param vDepartmentFk Id de departamento | NULL para mostrar todos
* @return Un select
*/
CALL zone_getPostalCode(vSelf);
WITH clientWithTicket AS (
- SELECT clientFk
+ SELECT DISTINCT clientFk
FROM vn.ticket
- WHERE shipped BETWEEN vShipped AND util.dayEnd(vShipped)
+ WHERE landed BETWEEN vLanded AND util.dayEnd(vLanded)
+ AND NOT isDeleted
)
SELECT c.id,
c.name,
@@ -30,7 +31,7 @@ BEGIN
u.name username,
aai.invoiced,
cnb.lastShipped,
- cwt.clientFk
+ IF(cwt.clientFk, TRUE, FALSE) hasTicket
FROM vn.client c
JOIN vn.worker w ON w.id = c.salesPersonFk
JOIN vn.workerDepartment wd ON wd.workerFk = w.id
@@ -50,7 +51,7 @@ BEGIN
AND c.isActive
AND ct.code = 'normal'
AND bt.code <> 'worker'
- AND (d.id = vDepartmentFk OR NOT vDepartmentFk)
+ AND (d.id = vDepartmentFk OR vDepartmentFk IS NULL)
GROUP BY c.id;
DROP TEMPORARY TABLE tmp.zoneNodes;
diff --git a/db/routines/vn/procedures/zone_getOptionsForShipment.sql b/db/routines/vn/procedures/zone_getOptionsForShipment.sql
index fa48b0b0f7..17d1b3d11b 100644
--- a/db/routines/vn/procedures/zone_getOptionsForShipment.sql
+++ b/db/routines/vn/procedures/zone_getOptionsForShipment.sql
@@ -9,7 +9,7 @@ BEGIN
* @return tmp.zoneOption(zoneFk, hour, travelingDays, price, bonus, specificity) The computed options
*/
DECLARE vHour TIME DEFAULT TIME(util.VN_NOW());
-
+
DROP TEMPORARY TABLE IF EXISTS tLandings;
CREATE TEMPORARY TABLE tLandings
(INDEX (eventFk))
@@ -30,6 +30,7 @@ BEGIN
TIME(IFNULL(e.`hour`, z.`hour`)) `hour`,
l.travelingDays,
IFNULL(e.price, z.price) price,
+ IFNULL(e.priceOptimum, z.priceOptimum) priceOptimum,
IFNULL(e.bonus, z.bonus) bonus,
l.landed,
vShipped shipped
diff --git a/db/routines/vn/triggers/itemTaxCountry_beforeDelete.sql b/db/routines/vn/triggers/itemTaxCountry_beforeDelete.sql
new file mode 100644
index 0000000000..461b861f28
--- /dev/null
+++ b/db/routines/vn/triggers/itemTaxCountry_beforeDelete.sql
@@ -0,0 +1,8 @@
+DELIMITER $$
+CREATE OR REPLACE DEFINER=`vn`@`localhost` TRIGGER `vn`.`itemTaxCountry_beforeDelete`
+ BEFORE DELETE ON `itemTaxCountry`
+ FOR EACH ROW
+BEGIN
+ CALL util.throw('Records in this table cannot be deleted');
+END$$
+DELIMITER ;
diff --git a/db/routines/vn/triggers/itemTaxCountry_beforeUpdate.sql b/db/routines/vn/triggers/itemTaxCountry_beforeUpdate.sql
index ad7d6327bf..5220028e8b 100644
--- a/db/routines/vn/triggers/itemTaxCountry_beforeUpdate.sql
+++ b/db/routines/vn/triggers/itemTaxCountry_beforeUpdate.sql
@@ -4,5 +4,9 @@ CREATE OR REPLACE DEFINER=`vn`@`localhost` TRIGGER `vn`.`itemTaxCountry_beforeUp
FOR EACH ROW
BEGIN
SET NEW.editorFk = account.myUser_getId();
+
+ IF NOT(NEW.`countryFk` <=> OLD.`countryFk`) OR NOT(NEW.`itemFk` <=> OLD.`itemFk`) THEN
+ CALL util.throw('Only the VAT can be modified');
+ END IF;
END$$
DELIMITER ;
diff --git a/db/routines/vn/triggers/workerTimeControl_afterDelete.sql b/db/routines/vn/triggers/workerTimeControl_afterDelete.sql
index 27432fccb3..96db381b56 100644
--- a/db/routines/vn/triggers/workerTimeControl_afterDelete.sql
+++ b/db/routines/vn/triggers/workerTimeControl_afterDelete.sql
@@ -3,10 +3,12 @@ CREATE OR REPLACE DEFINER=`vn`@`localhost` TRIGGER `vn`.`workerTimeControl_after
AFTER DELETE ON `workerTimeControl`
FOR EACH ROW
BEGIN
- INSERT INTO workerLog
- SET `action` = 'delete',
- `changedModel` = 'WorkerTimeControl',
- `changedModelId` = OLD.id,
- `userFk` = account.myUser_getId();
+ IF account.myUser_getId() IS NOT NULL THEN
+ INSERT INTO workerLog
+ SET `action` = 'delete',
+ `changedModel` = 'WorkerTimeControl',
+ `changedModelId` = OLD.id,
+ `userFk` = account.myUser_getId();
+ END IF;
END$$
DELIMITER ;
diff --git a/db/routines/vn/views/agencyModeIncoming.sql b/db/routines/vn/views/agencyModeIncoming.sql
new file mode 100644
index 0000000000..f7f6e595df
--- /dev/null
+++ b/db/routines/vn/views/agencyModeIncoming.sql
@@ -0,0 +1,9 @@
+CREATE OR REPLACE DEFINER=`vn`@`localhost`
+SQL SECURITY DEFINER
+VIEW `vn`.`agencyModeIncoming` AS
+ SELECT
+ am.id,
+ am.name
+ FROM `vn`.`agencyMode` AS am
+ JOIN `vn`.`agencyIncoming` AS ai
+ ON am.id = ai.agencyModeFk;
diff --git a/db/routines/vn2008/views/Split_lines.sql b/db/routines/vn2008/views/Split_lines.sql
deleted file mode 100644
index 0b7897be73..0000000000
--- a/db/routines/vn2008/views/Split_lines.sql
+++ /dev/null
@@ -1,8 +0,0 @@
-CREATE OR REPLACE DEFINER=`root`@`localhost`
- SQL SECURITY DEFINER
- VIEW `vn2008`.`Split_lines`
-AS SELECT `sl`.`id` AS `Id_Split_lines`,
- `sl`.`splitFk` AS `Id_Split`,
- `sl`.`itemFk` AS `Id_Article`,
- `sl`.`buyFk` AS `Id_Compra`
-FROM `vn`.`splitLine` `sl`
\ No newline at end of file
diff --git a/db/versions/11269-wheatBirch/00-firstScript.sql b/db/versions/11269-wheatBirch/00-firstScript.sql
index 9432d131b5..9552fe6cd7 100644
--- a/db/versions/11269-wheatBirch/00-firstScript.sql
+++ b/db/versions/11269-wheatBirch/00-firstScript.sql
@@ -7,9 +7,9 @@ ALTER TABLE vn.invoiceOut ADD CONSTRAINT invoiceOut_customsAgentFk FOREIGN KEY (
ALTER TABLE vn.invoiceOut ADD CONSTRAINT invoiceOut_incotermsFk FOREIGN KEY (incotermsFk)
REFERENCES vn.incoterms (`code`) ON DELETE RESTRICT ON UPDATE CASCADE;
-UPDATE vn.invoiceOut io
- JOIN vn.client c ON c.id = io.clientFk
- JOIN vn.ticket t ON t.clientFk = c.id
- JOIN vn.address a ON a.id = t.addressFk
- SET io.customsAgentFk = a.customsAgentFk,
- io.incotermsFk = a.incotermsFk;
\ No newline at end of file
+-- UPDATE vn.invoiceOut io
+-- JOIN vn.client c ON c.id = io.clientFk
+-- JOIN vn.ticket t ON t.clientFk = c.id
+-- JOIN vn.address a ON a.id = t.addressFk
+-- SET io.customsAgentFk = a.customsAgentFk,
+-- io.incotermsFk = a.incotermsFk;
diff --git a/db/versions/11383-maroonChico/00-town.sql b/db/versions/11383-maroonChico/00-town.sql
new file mode 100644
index 0000000000..8fdd8c7b09
--- /dev/null
+++ b/db/versions/11383-maroonChico/00-town.sql
@@ -0,0 +1,10 @@
+UPDATE vn.town t
+ LEFT JOIN vn.zoneGeo zg ON zg.id = t.geoFk
+ SET t.geoFk = NULL
+ WHERE zg.id IS NULL;
+
+ALTER TABLE vn.town
+ ADD CONSTRAINT town_zoneGeo_FK FOREIGN KEY (geoFk)
+ REFERENCES vn.zoneGeo(id)
+ ON DELETE RESTRICT
+ ON UPDATE CASCADE;
diff --git a/db/versions/11383-maroonChico/01-postCode.sql b/db/versions/11383-maroonChico/01-postCode.sql
new file mode 100644
index 0000000000..668cf69cbf
--- /dev/null
+++ b/db/versions/11383-maroonChico/01-postCode.sql
@@ -0,0 +1,10 @@
+UPDATE vn.postCode pc
+ LEFT JOIN vn.zoneGeo zg ON zg.id = pc.geoFk
+ SET pc.geoFk = NULL
+ WHERE zg.id IS NULL;
+
+ALTER TABLE vn.postCode
+ ADD CONSTRAINT postCode_zoneGeo_FK FOREIGN KEY (geoFk)
+ REFERENCES vn.zoneGeo(id)
+ ON DELETE RESTRICT
+ ON UPDATE CASCADE;
diff --git a/db/versions/11383-maroonChico/02-province.sql b/db/versions/11383-maroonChico/02-province.sql
new file mode 100644
index 0000000000..c16d33cd8d
--- /dev/null
+++ b/db/versions/11383-maroonChico/02-province.sql
@@ -0,0 +1,10 @@
+UPDATE vn.province p
+ LEFT JOIN vn.zoneGeo zg ON zg.id = p.geoFk
+ SET p.geoFk = NULL
+ WHERE zg.id IS NULL;
+
+ALTER TABLE vn.province
+ ADD CONSTRAINT province_zoneGeo_FK FOREIGN KEY (geoFk)
+ REFERENCES vn.zoneGeo(id)
+ ON DELETE RESTRICT
+ ON UPDATE CASCADE;
diff --git a/db/versions/11398-orangeRose/00-zoneEventPriceOptimum.sql b/db/versions/11398-orangeRose/00-zoneEventPriceOptimum.sql
new file mode 100644
index 0000000000..0440714e4a
--- /dev/null
+++ b/db/versions/11398-orangeRose/00-zoneEventPriceOptimum.sql
@@ -0,0 +1,5 @@
+ALTER TABLE `vn`.`zoneEvent`
+ ADD COLUMN `priceOptimum` DECIMAL(10,2) NULL COMMENT 'Precio mínimo que puede pagar un bulto'
+ AFTER `price`,
+ ADD CONSTRAINT `ck_zoneEvent_priceOptimum`
+ CHECK (priceOptimum <= price)
diff --git a/db/versions/11398-orangeRose/00-zonePriceOptimum.sql b/db/versions/11398-orangeRose/00-zonePriceOptimum.sql
new file mode 100644
index 0000000000..82b2001cdf
--- /dev/null
+++ b/db/versions/11398-orangeRose/00-zonePriceOptimum.sql
@@ -0,0 +1,5 @@
+ALTER TABLE `vn`.`zone`
+ ADD COLUMN `priceOptimum` DECIMAL(10,2) NOT NULL COMMENT 'Precio mínimo que puede pagar un bulto'
+ AFTER `price`,
+ ADD CONSTRAINT `ck_zone_priceOptimum`
+ CHECK (priceOptimum <= price)
diff --git a/db/versions/11398-orangeRose/01-zoneUpdate.sql b/db/versions/11398-orangeRose/01-zoneUpdate.sql
new file mode 100644
index 0000000000..042f2a92b5
--- /dev/null
+++ b/db/versions/11398-orangeRose/01-zoneUpdate.sql
@@ -0,0 +1,2 @@
+UPDATE `vn`.`zone`
+ SET `priceOptimum` = `price`;
diff --git a/db/versions/11398-orangeRose/02-clientAlter.sql b/db/versions/11398-orangeRose/02-clientAlter.sql
new file mode 100644
index 0000000000..b5275a3014
--- /dev/null
+++ b/db/versions/11398-orangeRose/02-clientAlter.sql
@@ -0,0 +1,3 @@
+ALTER TABLE `vn`.`client`
+ ADD COLUMN `packagesDiscountFactor` DECIMAL(4,3) NOT NULL DEFAULT 1.000
+ COMMENT 'Porcentaje de ajuste entre el numero de bultos medio del cliente, y el número medio óptimo para las zonas en las que compra';
diff --git a/db/versions/11398-orangeRose/03-clientConfig.sql b/db/versions/11398-orangeRose/03-clientConfig.sql
new file mode 100644
index 0000000000..2869f26a20
--- /dev/null
+++ b/db/versions/11398-orangeRose/03-clientConfig.sql
@@ -0,0 +1,3 @@
+ALTER TABLE `vn`.`clientConfig`
+ ADD COLUMN `packagesOptimum` INT UNSIGNED NOT NULL DEFAULT 20 COMMENT 'Numero de bultos por cliente/dia para conseguir el precio optimo',
+ ADD COLUMN `monthsToCalcOptimumPrice` TINYINT UNSIGNED NOT NULL DEFAULT 3 COMMENT 'Número de meses a usar para el cálculo de client.packagesDiscountFactor';
diff --git a/db/versions/11405-blackMoss/00-entryAlter.sql b/db/versions/11405-blackMoss/00-entryAlter.sql
new file mode 100644
index 0000000000..3320b9dd3f
--- /dev/null
+++ b/db/versions/11405-blackMoss/00-entryAlter.sql
@@ -0,0 +1,3 @@
+ALTER TABLE `vn`.`entry`
+ ADD COLUMN `initialTemperature` decimal(10,2) DEFAULT NULL COMMENT 'Temperatura de como lo recibimos del proveedor ej. en colombia',
+ ADD COLUMN `finalTemperature` decimal(10,2) DEFAULT NULL COMMENT 'Temperatura final de como llega a nuestras instalaciones';
diff --git a/db/versions/11406-bronzeMoss/00-currrencyAlter.sql b/db/versions/11406-bronzeMoss/00-currrencyAlter.sql
new file mode 100644
index 0000000000..86465545e1
--- /dev/null
+++ b/db/versions/11406-bronzeMoss/00-currrencyAlter.sql
@@ -0,0 +1,2 @@
+ALTER TABLE `vn`.`currency`
+ADD COLUMN `hasToDownloadRate` TINYINT(1) NOT NULL DEFAULT 0 comment 'Si se guarda el tipo de cambio diariamente en referenceRate';
diff --git a/db/versions/11406-bronzeMoss/01-currrencyUpdate.sql b/db/versions/11406-bronzeMoss/01-currrencyUpdate.sql
new file mode 100644
index 0000000000..5e0882de27
--- /dev/null
+++ b/db/versions/11406-bronzeMoss/01-currrencyUpdate.sql
@@ -0,0 +1,3 @@
+UPDATE `vn`.`currency`
+ SET `hasToDownloadRate` = TRUE
+ WHERE `code` IN ('USD', 'CNY', 'GBP');
diff --git a/db/versions/11407-turquoiseTulip/00-firstScript.sql b/db/versions/11407-turquoiseTulip/00-firstScript.sql
new file mode 100644
index 0000000000..72d29061d4
--- /dev/null
+++ b/db/versions/11407-turquoiseTulip/00-firstScript.sql
@@ -0,0 +1,2 @@
+INSERT INTO salix.ACL (model,property,accessType,permission,principalType,principalId)
+ VALUES ('VnUser','adminUser','WRITE','ALLOW','ROLE','sysadmin');
\ No newline at end of file
diff --git a/db/versions/11410-blackTulip/00-firstScript.sql b/db/versions/11410-blackTulip/00-firstScript.sql
new file mode 100644
index 0000000000..e300c4b7c9
--- /dev/null
+++ b/db/versions/11410-blackTulip/00-firstScript.sql
@@ -0,0 +1,2 @@
+RENAME TABLE bi.f_tvc TO bi.f_tvc__;
+ALTER TABLE bi.f_tvc__ COMMENT='@deprecated 2025-01-15';
\ No newline at end of file
diff --git a/db/versions/11411-turquoiseEucalyptus/00-agencyIncomingForeign.sql b/db/versions/11411-turquoiseEucalyptus/00-agencyIncomingForeign.sql
new file mode 100644
index 0000000000..d2c46e9cad
--- /dev/null
+++ b/db/versions/11411-turquoiseEucalyptus/00-agencyIncomingForeign.sql
@@ -0,0 +1,13 @@
+use `vn`;
+DELETE ai from
+ `vn`.`agencyIncoming` ai
+ LEFT JOIN `vn`.`agencyMode` am ON
+ am.id = ai.agencyModeFk
+ WHERE am.id IS null;
+
+ALTER TABLE `vn`.`agencyIncoming`
+ ADD CONSTRAINT `fk_agencyIncoming_agencyMode`
+ FOREIGN KEY (`agencyModeFk`)
+ REFERENCES `agencyMode`(`id`)
+ ON DELETE CASCADE
+ ON UPDATE CASCADE;
diff --git a/db/versions/11411-turquoiseEucalyptus/01-travelThermographAlter.sql b/db/versions/11411-turquoiseEucalyptus/01-travelThermographAlter.sql
new file mode 100644
index 0000000000..3838f59d79
--- /dev/null
+++ b/db/versions/11411-turquoiseEucalyptus/01-travelThermographAlter.sql
@@ -0,0 +1,7 @@
+ALTER TABLE `vn`.`travelThermograph`
+ ADD COLUMN `agencyModeFk` INT(11) NULL AFTER `editorFk`,
+ ADD CONSTRAINT `travelThermograph_agencyIncoming_fk`
+ FOREIGN KEY (`agencyModeFk`)
+ REFERENCES `agencyIncoming`(`agencyModeFk`)
+ ON DELETE RESTRICT
+ ON UPDATE CASCADE;
diff --git a/db/versions/11415-chocolateTulip/00-firstScript.sql b/db/versions/11415-chocolateTulip/00-firstScript.sql
new file mode 100644
index 0000000000..2ed7ec9b51
--- /dev/null
+++ b/db/versions/11415-chocolateTulip/00-firstScript.sql
@@ -0,0 +1 @@
+CREATE INDEX ticket_landed_IDX USING BTREE ON vn.ticket (landed);
diff --git a/db/versions/11418-goldenRuscus/00-firstScript.sql b/db/versions/11418-goldenRuscus/00-firstScript.sql
new file mode 100644
index 0000000000..6c623d7b77
--- /dev/null
+++ b/db/versions/11418-goldenRuscus/00-firstScript.sql
@@ -0,0 +1,130 @@
+-- Place your SQL code here
+CREATE TABLE IF NOT EXISTS `vn`.`itemSoldOutTag` (
+ `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
+ `name` varchar(50) NOT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `name_UNIQUE` (`name`)
+) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT
+ CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
+
+INSERT IGNORE INTO `vn`.`itemSoldOutTag` (`name`) VALUES ('Ultimas unidades');
+INSERT IGNORE INTO `vn`.`itemSoldOutTag` (`name`) VALUES ('Temporalmente');
+INSERT IGNORE INTO `vn`.`itemSoldOutTag` (`name`) VALUES ('Descatalogado');
+INSERT IGNORE INTO `vn`.`itemSoldOutTag` (`name`) VALUES ('Hasta mayo');
+INSERT IGNORE INTO `vn`.`itemSoldOutTag` (`name`) VALUES ('Hasta febrero');
+INSERT IGNORE INTO `vn`.`itemSoldOutTag` (`name`) VALUES ('Hasta diciembre');
+INSERT IGNORE INTO `vn`.`itemSoldOutTag` (`name`) VALUES ('Hasta enero');
+INSERT IGNORE INTO `vn`.`itemSoldOutTag` (`name`) VALUES ('Hasta marzo');
+INSERT IGNORE INTO `vn`.`itemSoldOutTag` (`name`) VALUES ('Hasta nueva temporada');
+INSERT IGNORE INTO `vn`.`itemSoldOutTag` (`name`) VALUES ('Hasta septiembre');
+
+UPDATE vn.tag
+ SET isFree=FALSE,
+ sourceTable='itemSoldOutTag'
+ WHERE name= 'Agotado';
+
+
+CREATE TABLE IF NOT EXISTS `vn`.`itemDurationTag` (
+ `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
+ `name` varchar(50) NOT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `name_UNIQUE` (`name`)
+) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT
+ CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
+
+INSERT IGNORE INTO `vn`.`itemDurationTag` (`name`) VALUES ('10 días');
+INSERT IGNORE INTO `vn`.`itemDurationTag` (`name`) VALUES ('11 días');
+INSERT IGNORE INTO `vn`.`itemDurationTag` (`name`) VALUES ('12 días');
+INSERT IGNORE INTO `vn`.`itemDurationTag` (`name`) VALUES ('13 días');
+INSERT IGNORE INTO `vn`.`itemDurationTag` (`name`) VALUES ('14 días');
+INSERT IGNORE INTO `vn`.`itemDurationTag` (`name`) VALUES ('15 días');
+INSERT IGNORE INTO `vn`.`itemDurationTag` (`name`) VALUES ('17 días');
+INSERT IGNORE INTO `vn`.`itemDurationTag` (`name`) VALUES ('7 días');
+INSERT IGNORE INTO `vn`.`itemDurationTag` (`name`) VALUES ('9 días');
+INSERT IGNORE INTO `vn`.`itemDurationTag` (`name`) VALUES ('16-20 días');
+INSERT IGNORE INTO `vn`.`itemDurationTag` (`name`) VALUES ('17-21 días');
+INSERT IGNORE INTO `vn`.`itemDurationTag` (`name`) VALUES ('19-23 días');
+INSERT IGNORE INTO `vn`.`itemDurationTag` (`name`) VALUES ('3-4 semanas');
+INSERT IGNORE INTO `vn`.`itemDurationTag` (`name`) VALUES ('13-17 días');
+INSERT IGNORE INTO `vn`.`itemDurationTag` (`name`) VALUES ('14-16 días');
+INSERT IGNORE INTO `vn`.`itemDurationTag` (`name`) VALUES ('15-19 días');
+INSERT IGNORE INTO `vn`.`itemDurationTag` (`name`) VALUES ('18-25 días');
+INSERT IGNORE INTO `vn`.`itemDurationTag` (`name`) VALUES ('20 días');
+INSERT IGNORE INTO `vn`.`itemDurationTag` (`name`) VALUES ('6 días');
+INSERT IGNORE INTO `vn`.`itemDurationTag` (`name`) VALUES ('9 días');
+INSERT IGNORE INTO `vn`.`itemDurationTag` (`name`) VALUES ('10-13 días');
+INSERT IGNORE INTO `vn`.`itemDurationTag` (`name`) VALUES ('6 meses');
+INSERT IGNORE INTO `vn`.`itemDurationTag` (`name`) VALUES ('5 años');
+INSERT IGNORE INTO `vn`.`itemDurationTag` (`name`) VALUES ('10 horas');
+INSERT IGNORE INTO `vn`.`itemDurationTag` (`name`) VALUES ('20 horas');
+INSERT IGNORE INTO `vn`.`itemDurationTag` (`name`) VALUES ('35 horas');
+INSERT IGNORE INTO `vn`.`itemDurationTag` (`name`) VALUES ('6 horas');
+INSERT IGNORE INTO `vn`.`itemDurationTag` (`name`) VALUES ('11 horas');
+INSERT IGNORE INTO `vn`.`itemDurationTag` (`name`) VALUES ('12 horas');
+INSERT IGNORE INTO `vn`.`itemDurationTag` (`name`) VALUES ('14 horas');
+INSERT IGNORE INTO `vn`.`itemDurationTag` (`name`) VALUES ('15 horas');
+INSERT IGNORE INTO `vn`.`itemDurationTag` (`name`) VALUES ('18 horas');
+INSERT IGNORE INTO `vn`.`itemDurationTag` (`name`) VALUES ('19 horas');
+INSERT IGNORE INTO `vn`.`itemDurationTag` (`name`) VALUES ('24 horas');
+INSERT IGNORE INTO `vn`.`itemDurationTag` (`name`) VALUES ('25 horas');
+INSERT IGNORE INTO `vn`.`itemDurationTag` (`name`) VALUES ('30 horas');
+INSERT IGNORE INTO `vn`.`itemDurationTag` (`name`) VALUES ('32 horas');
+INSERT IGNORE INTO `vn`.`itemDurationTag` (`name`) VALUES ('4 horas');
+INSERT IGNORE INTO `vn`.`itemDurationTag` (`name`) VALUES ('40 horas');
+INSERT IGNORE INTO `vn`.`itemDurationTag` (`name`) VALUES ('45 horas');
+INSERT IGNORE INTO `vn`.`itemDurationTag` (`name`) VALUES ('50 horas');
+INSERT IGNORE INTO `vn`.`itemDurationTag` (`name`) VALUES ('55 horas');
+INSERT IGNORE INTO `vn`.`itemDurationTag` (`name`) VALUES ('70 horas');
+INSERT IGNORE INTO `vn`.`itemDurationTag` (`name`) VALUES ('8 horas');
+INSERT IGNORE INTO `vn`.`itemDurationTag` (`name`) VALUES ('9 horas');
+
+UPDATE vn.tag
+ SET isFree=FALSE,
+ sourceTable='itemDurationTag'
+ WHERE name= 'Duracion';
+
+
+CREATE TABLE IF NOT EXISTS `vn`.`itemGrowingTag` (
+ `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
+ `name` varchar(50) NOT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `name_UNIQUE` (`name`)
+) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT
+ CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
+
+INSERT IGNORE INTO `vn`.`itemGrowingTag` (`name`) VALUES ('01-05');
+INSERT IGNORE INTO `vn`.`itemGrowingTag` (`name`) VALUES ('01-06');
+INSERT IGNORE INTO `vn`.`itemGrowingTag` (`name`) VALUES ('01-12');
+INSERT IGNORE INTO `vn`.`itemGrowingTag` (`name`) VALUES ('02-06');
+INSERT IGNORE INTO `vn`.`itemGrowingTag` (`name`) VALUES ('03-05');
+INSERT IGNORE INTO `vn`.`itemGrowingTag` (`name`) VALUES ('03-07');
+INSERT IGNORE INTO `vn`.`itemGrowingTag` (`name`) VALUES ('03-08');
+INSERT IGNORE INTO `vn`.`itemGrowingTag` (`name`) VALUES ('03-11');
+INSERT IGNORE INTO `vn`.`itemGrowingTag` (`name`) VALUES ('04-06');
+INSERT IGNORE INTO `vn`.`itemGrowingTag` (`name`) VALUES ('04-09');
+INSERT IGNORE INTO `vn`.`itemGrowingTag` (`name`) VALUES ('04-11');
+INSERT IGNORE INTO `vn`.`itemGrowingTag` (`name`) VALUES ('05-07');
+INSERT IGNORE INTO `vn`.`itemGrowingTag` (`name`) VALUES ('05-08');
+INSERT IGNORE INTO `vn`.`itemGrowingTag` (`name`) VALUES ('05-10');
+INSERT IGNORE INTO `vn`.`itemGrowingTag` (`name`) VALUES ('05-11');
+INSERT IGNORE INTO `vn`.`itemGrowingTag` (`name`) VALUES ('06-09');
+INSERT IGNORE INTO `vn`.`itemGrowingTag` (`name`) VALUES ('06-10');
+INSERT IGNORE INTO `vn`.`itemGrowingTag` (`name`) VALUES ('06-11');
+INSERT IGNORE INTO `vn`.`itemGrowingTag` (`name`) VALUES ('07-09');
+INSERT IGNORE INTO `vn`.`itemGrowingTag` (`name`) VALUES ('07-10');
+INSERT IGNORE INTO `vn`.`itemGrowingTag` (`name`) VALUES ('07-11');
+INSERT IGNORE INTO `vn`.`itemGrowingTag` (`name`) VALUES ('07-12');
+INSERT IGNORE INTO `vn`.`itemGrowingTag` (`name`) VALUES ('09-12');
+INSERT IGNORE INTO `vn`.`itemGrowingTag` (`name`) VALUES ('01-04 / 10-12');
+INSERT IGNORE INTO `vn`.`itemGrowingTag` (`name`) VALUES ('01-04 / 9-12');
+INSERT IGNORE INTO `vn`.`itemGrowingTag` (`name`) VALUES ('01-05 / 10-12');
+INSERT IGNORE INTO `vn`.`itemGrowingTag` (`name`) VALUES ('01-05 / 11-12');
+
+UPDATE vn.tag
+ SET isFree=FALSE,
+ sourceTable='itemGrowingTag'
+ WHERE name= 'Recolecta';
+
+GRANT SELECT, UPDATE, INSERT, DELETE ON TABLE vn.itemSoldOutTag TO logisticAssist;
+GRANT SELECT, UPDATE, INSERT, DELETE ON TABLE vn.itemDurationTag TO logisticAssist;
+GRANT SELECT, UPDATE, INSERT, DELETE ON TABLE vn.itemGrowingTag TO logisticAssist;
diff --git a/db/versions/11419-orangeSalal/00-firstScript.sql b/db/versions/11419-orangeSalal/00-firstScript.sql
new file mode 100644
index 0000000000..432ed70aa2
--- /dev/null
+++ b/db/versions/11419-orangeSalal/00-firstScript.sql
@@ -0,0 +1,2 @@
+ALTER TABLE `vn`.`tag`
+ADD COLUMN IF NOT EXISTS `validationRegex` varchar(50) DEFAULT NULL;
diff --git a/db/versions/11422-blackAsparagus/00-firstScript.sql b/db/versions/11422-blackAsparagus/00-firstScript.sql
new file mode 100644
index 0000000000..bb0e7c3e9f
--- /dev/null
+++ b/db/versions/11422-blackAsparagus/00-firstScript.sql
@@ -0,0 +1,5 @@
+RENAME TABLE vn.sorter TO vn.sorter__;
+ALTER TABLE vn.sorter__ COMMENT='@deprecated 2025-01-22';
+
+RENAME TABLE vn.splitLine TO vn.splitLine__;
+ALTER TABLE vn.splitLine__ COMMENT='@deprecated 2025-01-22';
\ No newline at end of file
diff --git a/db/versions/11423-maroonMonstera/00-firstScript.sql b/db/versions/11423-maroonMonstera/00-firstScript.sql
new file mode 100644
index 0000000000..cf21473d8c
--- /dev/null
+++ b/db/versions/11423-maroonMonstera/00-firstScript.sql
@@ -0,0 +1 @@
+ALTER TABLE vn.address MODIFY COLUMN isEqualizated tinyint(1) NULL;
diff --git a/e2e/paths/05-ticket/01-sale/02_edit_sale.spec.js b/e2e/paths/05-ticket/01-sale/02_edit_sale.spec.js
index d9689e31ad..af1dc56bcd 100644
--- a/e2e/paths/05-ticket/01-sale/02_edit_sale.spec.js
+++ b/e2e/paths/05-ticket/01-sale/02_edit_sale.spec.js
@@ -238,25 +238,11 @@ describe('Ticket Edit sale path', () => {
await page.waitToClick(selectors.globalItems.cancelButton);
});
- it('should select the third sale and create a claim of it', async() => {
- await page.accessToSearchResult('16');
- await page.accessToSection('ticket.card.sale');
- await page.waitToClick(selectors.ticketSales.thirdSaleCheckbox);
- await page.waitToClick(selectors.ticketSales.moreMenu);
- await page.waitToClick(selectors.ticketSales.moreMenuCreateClaim);
- await page.waitToClick(selectors.globalItems.acceptButton);
- await page.waitForNavigation();
- });
-
- it('should search for a ticket then access to the sales section', async() => {
- await page.goBack();
- await page.goBack();
+ it('should select the third sale and delete it', async() => {
await page.loginAndModule('salesPerson', 'ticket');
await page.accessToSearchResult('16');
await page.accessToSection('ticket.card.sale');
- });
- it('should select the third sale and delete it', async() => {
await page.waitToClick(selectors.ticketSales.thirdSaleCheckbox);
await page.waitToClick(selectors.ticketSales.deleteSaleButton);
await page.waitToClick(selectors.globalItems.acceptButton);
diff --git a/e2e/paths/05-ticket/06_basic_data_steps.spec.js b/e2e/paths/05-ticket/06_basic_data_steps.spec.js
index 77f0e0459c..0a3ae4edce 100644
--- a/e2e/paths/05-ticket/06_basic_data_steps.spec.js
+++ b/e2e/paths/05-ticket/06_basic_data_steps.spec.js
@@ -75,7 +75,7 @@ describe('Ticket Edit basic data path', () => {
const result = await page
.waitToGetProperty(selectors.ticketBasicData.stepTwoTotalPriceDif, 'innerText');
- expect(result).toContain('-€228.25');
+ expect(result).toContain('-€111.75');
});
it(`should select a new reason for the changes made then click on finalize`, async() => {
diff --git a/loopback/locale/en.json b/loopback/locale/en.json
index 80da13ae59..06428475fc 100644
--- a/loopback/locale/en.json
+++ b/loopback/locale/en.json
@@ -211,6 +211,7 @@
"Name should be uppercase": "Name should be uppercase",
"You cannot update these fields": "You cannot update these fields",
"CountryFK cannot be empty": "Country cannot be empty",
+ "No tickets to invoice": "There are no tickets to invoice that meet the invoicing requirements",
"You are not allowed to modify the alias": "You are not allowed to modify the alias",
"You already have the mailAlias": "You already have the mailAlias",
"This machine is already in use.": "This machine is already in use.",
@@ -246,9 +247,11 @@
"ticketLostExpedition": "The ticket [{{ticketId}}]({{{ticketUrl}}}) has the following lost expedition:{{ expeditionId }}",
"The raid information is not correct": "The raid information is not correct",
"Payment method is required": "Payment method is required",
- "Sales already moved": "Sales already moved",
- "Holidays to past days not available": "Holidays to past days not available",
"Price cannot be blank": "Price cannot be blank",
"There are tickets to be invoiced": "There are tickets to be invoiced",
- "The address of the customer must have information about Incoterms and Customs Agent": "The address of the customer must have information about Incoterms and Customs Agent"
+ "The address of the customer must have information about Incoterms and Customs Agent": "The address of the customer must have information about Incoterms and Customs Agent",
+ "Sales already moved": "Sales already moved",
+ "Holidays to past days not available": "Holidays to past days not available",
+ "Incorrect delivery order alert on route": "Incorrect delivery order alert on route: {{ route }} zone: {{ zone }}",
+ "Ticket has been delivered out of order": "The ticket {{ticket}} {{{fullUrl}}} has been delivered out of order."
}
\ No newline at end of file
diff --git a/loopback/locale/es.json b/loopback/locale/es.json
index fcee0e1119..f79dad236e 100644
--- a/loopback/locale/es.json
+++ b/loopback/locale/es.json
@@ -339,7 +339,7 @@
"Incorrect pin": "Pin incorrecto.",
"You already have the mailAlias": "Ya tienes este alias de correo",
"The alias cant be modified": "Este alias de correo no puede ser modificado",
- "No tickets to invoice": "No hay tickets para facturar",
+ "No tickets to invoice": "No hay tickets para facturar que cumplan los requisitos de facturación",
"this warehouse has not dms": "El Almacén no acepta documentos",
"This ticket already has a cmr saved": "Este ticket ya tiene un cmr guardado",
"Name should be uppercase": "El nombre debe ir en mayúscula",
@@ -390,13 +390,11 @@
"The web user's email already exists": "El correo del usuario web ya existe",
"Sales already moved": "Ya han sido transferidas",
"The raid information is not correct": "La información de la redada no es correcta",
- "No trips found because input coordinates are not connected": "No se encontraron rutas porque las coordenadas de entrada no están conectadas",
- "This request is not supported": "Esta solicitud no es compatible",
- "Invalid options or too many coordinates": "Opciones invalidas o demasiadas coordenadas",
- "No address has coordinates": "Ninguna dirección tiene coordenadas",
"An item type with the same code already exists": "Un tipo con el mismo código ya existe",
"Holidays to past days not available": "Las vacaciones a días pasados no están disponibles",
"All tickets have a route order": "Todos los tickets tienen orden de ruta",
- "Price cannot be blank": "Price cannot be blank",
- "There are tickets to be invoiced": "La zona tiene tickets por facturar"
+ "There are tickets to be invoiced": "La zona tiene tickets por facturar",
+ "Incorrect delivery order alert on route": "Alerta de orden de entrega incorrecta en ruta: {{ route }} zona: {{ zone }}",
+ "Ticket has been delivered out of order": "El ticket {{ticket}} {{{fullUrl}}} no ha sigo entregado en su orden.",
+ "Price cannot be blank": "El precio no puede estar en blanco"
}
diff --git a/loopback/locale/fr.json b/loopback/locale/fr.json
index 9941358be6..d7d5b7710e 100644
--- a/loopback/locale/fr.json
+++ b/loopback/locale/fr.json
@@ -339,7 +339,7 @@
"Incorrect pin": "Pin incorrect.",
"You already have the mailAlias": "Vous avez déjà cet alias de courrier",
"The alias cant be modified": "Cet alias de courrier ne peut pas être modifié",
- "No tickets to invoice": "Pas de tickets à facturer",
+ "No tickets to invoice": "Il n'y a pas de tickets à facturer qui répondent aux exigences de facturation",
"this warehouse has not dms": "L'entrepôt n'accepte pas les documents",
"This ticket already has a cmr saved": "Ce ticket a déjà un cmr enregistré",
"Name should be uppercase": "Le nom doit être en majuscules",
@@ -362,9 +362,11 @@
"The invoices have been created but the PDFs could not be generated": "La facture a été émise mais le PDF n'a pas pu être généré",
"It has been invoiced but the PDF of refund not be generated": "Il a été facturé mais le PDF de remboursement n'a pas été généré",
"Cannot send mail": "Impossible d'envoyer le mail",
- "Original invoice not found": "Facture originale introuvable",
- "The quantity claimed cannot be greater than the quantity of the line": "Le montant réclamé ne peut pas être supérieur au montant de la ligne",
- "You do not have permission to modify the booked field": "Vous n'avez pas la permission de modifier le champ comptabilisé",
+ "Original invoice not found": "Facture originale introuvable",
+ "The quantity claimed cannot be greater than the quantity of the line": "Le montant réclamé ne peut pas être supérieur au montant de la ligne",
+ "You do not have permission to modify the booked field": "Vous n'avez pas la permission de modifier le champ comptabilisé",
"ticketLostExpedition": "Le ticket [{{ticketId}}]({{{ticketUrl}}}) a l'expédition perdue suivante : {{expeditionId}}",
- "The web user's email already exists": "L'email de l'internaute existe déjà"
-}
+ "The web user's email already exists": "L'email de l'internaute existe déjà",
+ "Incorrect delivery order alert on route": "Alerte de bon de livraison incorrect sur l'itinéraire: {{ route }} zone : {{ zone }}",
+ "Ticket has been delivered out of order": "Le ticket {{ticket}} {{{fullUrl}}} a été livré hors ordre."
+}
\ No newline at end of file
diff --git a/loopback/locale/pt.json b/loopback/locale/pt.json
index e84b30f3d1..d1ac2ef236 100644
--- a/loopback/locale/pt.json
+++ b/loopback/locale/pt.json
@@ -339,7 +339,7 @@
"Incorrect pin": "PIN incorreto.",
"You already have the mailAlias": "Você já tem o alias de e-mail",
"The alias cant be modified": "O alias não pode ser modificado",
- "No tickets to invoice": "Não há tickets para faturar",
+ "No tickets to invoice": "Não há bilhetes para faturar que atendam aos requisitos de faturamento",
"this warehouse has not dms": "Este armazém não tem DMS",
"This ticket already has a cmr saved": "Este ticket já tem um CMR salvo",
"Name should be uppercase": "O nome deve estar em maiúsculas",
@@ -365,5 +365,7 @@
"Cannot send mail": "Não é possível enviar o email",
"The quantity claimed cannot be greater than the quantity of the line": "O valor reclamado não pode ser superior ao valor da linha",
"ticketLostExpedition": "O ticket [{{ticketId}}]({{{ticketUrl}}}) tem a seguinte expedição perdida: {{expeditionId}}",
- "The web user's email already exists": "O e-mail do utilizador da web já existe."
-}
+ "The web user's email already exists": "O e-mail do utilizador da web já existe.",
+ "Incorrect delivery order alert on route": "Alerta de ordem de entrega incorreta na rota: {{ route }} zona: {{ zone }}",
+ "Ticket has been delivered out of order": "O ticket {{ticket}} {{{fullUrl}}} foi entregue fora de ordem."
+}
\ No newline at end of file
diff --git a/modules/claim/back/methods/claim/filter.js b/modules/claim/back/methods/claim/filter.js
index bacdd40216..bf9cd94412 100644
--- a/modules/claim/back/methods/claim/filter.js
+++ b/modules/claim/back/methods/claim/filter.js
@@ -109,6 +109,7 @@ module.exports = Self => {
const args = ctx.args;
const myOptions = {};
let to;
+ let myTeamIds = [];
if (typeof options == 'object')
Object.assign(myOptions, options);
@@ -133,21 +134,8 @@ module.exports = Self => {
claimIdsByClaimResponsibleFk = claims.map(claim => claim.claimFk);
}
- // Apply filter by team
- const teamMembersId = [];
- if (args.myTeam != null) {
- const worker = await models.Worker.findById(userId, {
- include: {
- relation: 'collegues'
- }
- }, myOptions);
- const collegues = worker.collegues() || [];
- for (let collegue of collegues)
- teamMembersId.push(collegue.collegueFk);
-
- if (teamMembersId.length == 0)
- teamMembersId.push(userId);
- }
+ if (args.myTeam != null)
+ myTeamIds = await models.Worker.myTeam(userId);
const where = buildFilter(ctx.args, (param, value) => {
switch (param) {
@@ -184,9 +172,9 @@ module.exports = Self => {
return {'t.zoneFk': value};
case 'myTeam':
if (value)
- return {'cl.workerFk': {inq: teamMembersId}};
+ return {'cl.workerFk': {inq: myTeamIds}};
else
- return {'cl.workerFk': {nin: teamMembersId}};
+ return {'cl.workerFk': {nin: myTeamIds}};
}
});
diff --git a/modules/client/back/methods/client/createAddress.js b/modules/client/back/methods/client/createAddress.js
index 2709632cb9..6bd4a26c1e 100644
--- a/modules/client/back/methods/client/createAddress.js
+++ b/modules/client/back/methods/client/createAddress.js
@@ -52,6 +52,14 @@ module.exports = function(Self) {
arg: 'customsAgentFk',
type: 'number'
},
+ {
+ arg: 'longitude',
+ type: 'number'
+ },
+ {
+ arg: 'latitude',
+ type: 'number'
+ },
{
arg: 'isActive',
type: 'boolean'
diff --git a/modules/client/back/methods/client/extendedListFilter.js b/modules/client/back/methods/client/extendedListFilter.js
index 174970a2fe..0097795e67 100644
--- a/modules/client/back/methods/client/extendedListFilter.js
+++ b/modules/client/back/methods/client/extendedListFilter.js
@@ -43,6 +43,14 @@ module.exports = Self => {
arg: 'postcode',
type: 'string',
},
+ {
+ arg: 'sageTransactionTypeFk',
+ type: 'number',
+ },
+ {
+ arg: 'sageTaxTypeFk',
+ type: 'number',
+ },
{
arg: 'provinceFk',
type: 'number',
@@ -79,6 +87,10 @@ module.exports = Self => {
return /^\d+$/.test(value)
? {'c.id': {inq: value}}
: {'c.name': {like: `%${value}%`}};
+ case 'sageTaxTypeFk':
+ return {'sti.CodigoIva': value};
+ case 'sageTransactionTypeFk':
+ return {'stt.CodigoTransaccion': value};
case 'name':
case 'salesPersonFk':
case 'fi':
diff --git a/modules/client/back/methods/client/specs/updateAddress.spec.js b/modules/client/back/methods/client/specs/updateAddress.spec.js
index 0453332d71..233ab9ccb8 100644
--- a/modules/client/back/methods/client/specs/updateAddress.spec.js
+++ b/modules/client/back/methods/client/specs/updateAddress.spec.js
@@ -157,4 +157,52 @@ describe('Address updateAddress', () => {
throw e;
}
});
+
+ it('should update ticket observations when updateObservations is true', async() => {
+ const tx = await models.Client.beginTransaction({});
+ const client = 1103;
+ const address = 123;
+ const ticket = 31;
+ const observationType = 3;
+
+ const salesAssistantId = 21;
+ const addressObservation = 'nuevo texto';
+ const ticketObservation = 'texto a modificar';
+
+ try {
+ const options = {transaction: tx};
+ ctx.req.accessToken.userId = salesAssistantId;
+ ctx.args = {
+ updateObservations: true,
+ incotermsFk: incotermsId,
+ provinceFk: provinceId,
+ customsAgentFk: customAgentOneId
+ };
+
+ await models.AddressObservation.create({
+ addressFk: address,
+ observationTypeFk: observationType,
+ description: addressObservation
+ }, options);
+
+ await models.TicketObservation.create({
+ ticketFk: ticket,
+ observationTypeFk: observationType,
+ description: ticketObservation
+ }, options);
+
+ await models.Client.updateAddress(ctx, client, address, options);
+
+ const updatedObservation = await models.TicketObservation.findOne({
+ where: {ticketFk: ticket, observationTypeFk: observationType}
+ }, options);
+
+ expect(updatedObservation.description).toEqual(addressObservation);
+
+ await tx.rollback();
+ } catch (e) {
+ await tx.rollback();
+ throw e;
+ }
+ });
});
diff --git a/modules/client/back/methods/client/updateAddress.js b/modules/client/back/methods/client/updateAddress.js
index efef83d6b3..e6e5adb451 100644
--- a/modules/client/back/methods/client/updateAddress.js
+++ b/modules/client/back/methods/client/updateAddress.js
@@ -80,6 +80,10 @@ module.exports = function(Self) {
{
arg: 'latitude',
type: 'any',
+ },
+ {
+ arg: 'updateObservations',
+ type: 'boolean'
}
],
returns: {
@@ -135,6 +139,17 @@ module.exports = function(Self) {
delete args.ctx; // Remove unwanted properties
const updatedAddress = await address.updateAttributes(ctx.args, myOptions);
+ if (args.updateObservations) {
+ const ticket = await Self.rawSql(`
+ UPDATE ticketObservation to2
+ JOIN ticket t ON t.id = to2.ticketFk
+ JOIN address a ON a.id = t.addressFk
+ JOIN addressObservation ao ON ao.addressFk = a.id
+ SET to2.description = ao.description
+ WHERE ao.observationTypeFk = to2.observationTypeFk
+ AND a.id = ?
+ AND t.shipped >= util.VN_CURDATE()`, [addressId], myOptions);
+ }
return updatedAddress;
};
diff --git a/modules/client/back/methods/defaulter/filter.js b/modules/client/back/methods/defaulter/filter.js
index 5359ce4a7d..e00048cf54 100644
--- a/modules/client/back/methods/defaulter/filter.js
+++ b/modules/client/back/methods/defaulter/filter.js
@@ -21,7 +21,7 @@ module.exports = Self => {
}
],
returns: {
- type: ['object'],
+ type: 'object',
root: true
},
http: {
@@ -41,23 +41,28 @@ module.exports = Self => {
switch (param) {
case 'search':
return {or: [
- {'d.clientFk': value},
- {'d.clientName': {like: `%${value}%`}}
+ {'c.id': value},
+ {'c.name': {like: `%${value}%`}}
]};
}
});
- filter = mergeFilters(ctx.args.filter, {where});
+ const date = Date.vnNew();
+ date.setHours(0, 0, 0, 0);
+
+ filter = mergeFilters({where: {'d.created': date, 'd.amount': {gt: 0}}}, ctx.args.filter);
+ filter = mergeFilters(filter, {where});
const stmts = [];
- const date = Date.vnNew();
- date.setHours(0, 0, 0, 0);
- const stmt = new ParameterizedSQL(
- `SELECT *
- FROM (
- SELECT
- DISTINCT c.id clientFk,
+ let stmt = new ParameterizedSQL(
+ `CREATE OR REPLACE TEMPORARY TABLE tmp.defaulters
+ WITH clientObservations AS
+ (SELECT clientFk,text, created, workerFk
+ FROM vn.clientObservation
+ GROUP BY clientFk
+ ORDER BY created DESC
+ )SELECT c.id clientFk,
c.name clientName,
c.salesPersonFk,
c.businessTypeFk = 'worker' isWorker,
@@ -80,36 +85,43 @@ module.exports = Self => {
JOIN client c ON c.id = d.clientFk
JOIN country cn ON cn.id = c.countryFk
JOIN payMethod pm ON pm.id = c.payMethodFk
- LEFT JOIN clientObservation co ON co.clientFk = c.id
+ LEFT JOIN clientObservations co ON co.clientFk = c.id
LEFT JOIN account.user u ON u.id = c.salesPersonFk
LEFT JOIN account.user uw ON uw.id = co.workerFk
LEFT JOIN (
- SELECT r1.started, r1.clientFk, r1.finished
+ SELECT r1.started, r1.clientFk, r1.finished
FROM recovery r1
JOIN (
- SELECT MAX(started) AS maxStarted, clientFk
+ SELECT MAX(started) maxStarted, clientFk
FROM recovery
GROUP BY clientFk
) r2 ON r1.clientFk = r2.clientFk
AND r1.started = r2.maxStarted
+ WHERE r1.finished
+ GROUP BY r1.clientFk
) r ON r.clientFk = c.id
LEFT JOIN workerDepartment wd ON wd.workerFk = u.id
- JOIN department dp ON dp.id = wd.departmentFk
- WHERE
- d.created = ?
- AND d.amount > 0
- ORDER BY co.created DESC) d`
- , [date]);
+ LEFT JOIN department dp ON dp.id = wd.departmentFk`);
stmt.merge(conn.makeWhere(filter.where));
- stmt.merge(`GROUP BY d.clientFk`);
+ stmts.push(stmt);
+
+ stmt = new ParameterizedSQL(`
+ SELECT SUM(amount) amount
+ FROM tmp.defaulters
+ `);
+ stmts.push(stmt);
+
+ stmt = new ParameterizedSQL(`
+ SELECT *
+ FROM tmp.defaulters
+ `);
stmt.merge(conn.makeOrderBy(filter.order));
- stmt.merge(conn.makeLimit(filter));
const itemsIndex = stmts.push(stmt) - 1;
const sql = ParameterizedSQL.join(stmts, ';');
const result = await conn.executeStmt(sql, myOptions);
- return itemsIndex === 0 ? result : result[itemsIndex];
+ return {defaulters: result[itemsIndex], amount: result[itemsIndex - 1][0].amount};
};
};
diff --git a/modules/client/back/methods/defaulter/specs/filter.spec.js b/modules/client/back/methods/defaulter/specs/filter.spec.js
index 0a970823e5..ca7a6b4ffe 100644
--- a/modules/client/back/methods/defaulter/specs/filter.spec.js
+++ b/modules/client/back/methods/defaulter/specs/filter.spec.js
@@ -11,10 +11,10 @@ describe('defaulter filter()', () => {
const ctx = {req: {accessToken: {userId: authUserId}}, args: {filter: filter}};
const result = await models.Defaulter.filter(ctx, null, options);
- const firstRow = result[0];
+ const firstRow = result.defaulters[0];
expect(firstRow.clientFk).toEqual(1101);
- expect(result.length).toEqual(5);
+ expect(result.defaulters.length).toEqual(5);
await tx.rollback();
} catch (e) {
@@ -31,7 +31,7 @@ describe('defaulter filter()', () => {
const ctx = {req: {accessToken: {userId: authUserId}}, args: {search: 1101}};
const result = await models.Defaulter.filter(ctx, null, options);
- const firstRow = result[0];
+ const firstRow = result.defaulters[0];
expect(firstRow.clientFk).toEqual(1101);
@@ -50,7 +50,7 @@ describe('defaulter filter()', () => {
const ctx = {req: {accessToken: {userId: authUserId}}, args: {search: 'Petter Parker'}};
const result = await models.Defaulter.filter(ctx, null, options);
- const firstRow = result[0];
+ const firstRow = result.defaulters[0];
expect(firstRow.clientName).toEqual('Petter Parker');
@@ -60,4 +60,23 @@ describe('defaulter filter()', () => {
throw e;
}
});
+
+ it('should return the defaulter the sum of every defaulters', async() => {
+ const tx = await models.Defaulter.beginTransaction({});
+
+ try {
+ const options = {transaction: tx};
+ const ctx = {req: {accessToken: {userId: authUserId}}, args: {search: 1101}};
+ const {defaulters, amount} = await models.Defaulter.filter(ctx, null, options);
+
+ const total = defaulters.reduce((total, row) => total + row.amount, 0);
+
+ expect(total).toEqual(amount);
+
+ await tx.rollback();
+ } catch (e) {
+ await tx.rollback();
+ throw e;
+ }
+ });
});
diff --git a/modules/client/back/models/client-credit.json b/modules/client/back/models/client-credit.json
index b92639b80c..b57374dc38 100644
--- a/modules/client/back/models/client-credit.json
+++ b/modules/client/back/models/client-credit.json
@@ -19,6 +19,9 @@
},
"created": {
"type": "date"
+ },
+ "workerFk": {
+ "type": "number"
}
},
"relations": {
@@ -33,4 +36,4 @@
"foreignKey": "workerFk"
}
}
-}
\ No newline at end of file
+}
diff --git a/modules/entry/back/methods/entry/filter.js b/modules/entry/back/methods/entry/filter.js
index d7740dd4ee..e5eae85fd3 100644
--- a/modules/entry/back/methods/entry/filter.js
+++ b/modules/entry/back/methods/entry/filter.js
@@ -119,6 +119,16 @@ module.exports = Self => {
arg: 'invoiceAmount',
type: 'number',
description: `The invoice amount`
+ },
+ {
+ arg: 'initialTemperature',
+ type: 'number',
+ description: 'Initial temperature value'
+ },
+ {
+ arg: 'finalTemperature',
+ type: 'number',
+ description: 'Final temperature value'
}
],
returns: {
@@ -170,6 +180,10 @@ module.exports = Self => {
case 'invoiceInFk':
param = `e.${param}`;
return {[param]: value};
+ case 'initialTemperature':
+ return {'e.initialTemperature': {lte: value}};
+ case 'finalTemperature':
+ return {'e.finalTemperature': {gte: value}};
}
});
filter = mergeFilters(ctx.args.filter, {where});
@@ -204,6 +218,8 @@ module.exports = Self => {
e.gestDocFk,
e.invoiceInFk,
e.invoiceAmount,
+ e.initialTemperature,
+ e.finalTemperature,
t.landed,
s.name supplierName,
s.nickname supplierAlias,
diff --git a/modules/entry/back/methods/entry/specs/transfer.spec.js b/modules/entry/back/methods/entry/specs/transfer.spec.js
new file mode 100644
index 0000000000..bf0b2b974a
--- /dev/null
+++ b/modules/entry/back/methods/entry/specs/transfer.spec.js
@@ -0,0 +1,43 @@
+const models = require('vn-loopback/server/server').models;
+
+describe('Transfer merchandise from one entry to the next day()', () => {
+ it('should Transfer buys not located', async() => {
+ const tx = await models.ItemShelving.beginTransaction({});
+ const options = {transaction: tx};
+
+ try {
+ const id = 3;
+ const item = 8;
+ const buy = 6;
+ const originalEntry = 4;
+ const ctx = {req: {accessToken: {userId: 48}}};
+
+ const currentItemShelving = await models.ItemShelving.findOne({where: {id}}, options);
+ await currentItemShelving.updateAttributes({itemFk: item, buyFk: buy}, options);
+
+ const {newEntryFk} = await models.Entry.transfer(ctx, originalEntry, options);
+ const originalEntrybuys = await models.Buy.find({where: {entryFk: originalEntry}}, options);
+
+ const newEntrybuys = await models.Buy.find({where: {entryFk: newEntryFk}}, options);
+
+ const itemShelvingsWithBuys = await models.Buy.find({
+ include: {
+ relation: 'itemShelving',
+ scope: {
+ fields: ['id'],
+ },
+ },
+ where: {entryFk: originalEntry},
+ }, options);
+
+ const hasItemShelving = await itemShelvingsWithBuys.filter(buy => buy.itemShelving().length);
+
+ expect(newEntrybuys.length).toEqual(originalEntrybuys.length - hasItemShelving.length);
+
+ await tx.rollback();
+ } catch (e) {
+ await tx.rollback();
+ throw e;
+ }
+ });
+});
diff --git a/modules/entry/back/methods/entry/transfer.js b/modules/entry/back/methods/entry/transfer.js
new file mode 100644
index 0000000000..db68736633
--- /dev/null
+++ b/modules/entry/back/methods/entry/transfer.js
@@ -0,0 +1,45 @@
+module.exports = Self => {
+ Self.remoteMethodCtx('transfer', {
+ description: 'Transfer merchandise from one entry to the next day',
+ accepts: [
+ {
+ arg: 'id',
+ type: 'number',
+ required: true,
+ http: {source: 'path'}
+ }
+ ],
+ http: {
+ path: '/:id/transfer',
+ verb: 'POST'
+ },
+ returns: {
+ arg: 'newEntryFk',
+ type: 'number'
+ }
+ });
+
+ Self.transfer = async(ctx, id, options) => {
+ const myOptions = {userId: ctx.req.accessToken.userId};
+ let tx;
+
+ if (typeof options == 'object')
+ Object.assign(myOptions, options);
+
+ if (!myOptions.transaction) {
+ tx = await Self.beginTransaction({});
+ myOptions.transaction = tx;
+ }
+
+ try {
+ await Self.rawSql('CALL vn.entry_transfer(?, @vNewEntry)', [id], myOptions);
+ const [newEntryFk] = await Self.rawSql('SELECT @vNewEntry newEntryFk', null, myOptions);
+
+ if (tx) await tx.commit();
+ return newEntryFk;
+ } catch (e) {
+ if (tx) await tx.rollback();
+ throw e;
+ }
+ };
+};
diff --git a/modules/entry/back/models/buy.json b/modules/entry/back/models/buy.json
index 14cafde06b..cd1e54de73 100644
--- a/modules/entry/back/models/buy.json
+++ b/modules/entry/back/models/buy.json
@@ -114,6 +114,11 @@
"type": "belongsTo",
"model": "Delivery",
"foreignKey": "deliveryFk"
- }
+ },
+ "itemShelving": {
+ "type": "hasMany",
+ "model": "ItemShelving",
+ "foreignKey": "buyFk"
+ }
}
}
diff --git a/modules/entry/back/models/entry.js b/modules/entry/back/models/entry.js
index 55a23bb0a2..03cbd6e7f9 100644
--- a/modules/entry/back/models/entry.js
+++ b/modules/entry/back/models/entry.js
@@ -12,6 +12,7 @@ module.exports = Self => {
require('../methods/entry/addFromPackaging')(Self);
require('../methods/entry/addFromBuy')(Self);
require('../methods/entry/buyLabel')(Self);
+ require('../methods/entry/transfer')(Self);
require('../methods/entry/labelSupplier')(Self);
require('../methods/entry/buyLabelSupplier')(Self);
diff --git a/modules/entry/back/models/entry.json b/modules/entry/back/models/entry.json
index 4a09c7d6a5..1ff0621196 100644
--- a/modules/entry/back/models/entry.json
+++ b/modules/entry/back/models/entry.json
@@ -68,6 +68,12 @@
},
"invoiceAmount": {
"type": "number"
+ },
+ "initialTemperature": {
+ "type": "number"
+ },
+ "finalTemperature": {
+ "type": "number"
}
},
"relations": {
diff --git a/modules/invoiceIn/back/methods/invoice-in/exchangeRateUpdate.js b/modules/invoiceIn/back/methods/invoice-in/exchangeRateUpdate.js
index 989b1d4a24..99ff4cd79a 100644
--- a/modules/invoiceIn/back/methods/invoice-in/exchangeRateUpdate.js
+++ b/modules/invoiceIn/back/methods/invoice-in/exchangeRateUpdate.js
@@ -13,66 +13,114 @@ module.exports = Self => {
}
});
- Self.exchangeRateUpdate = async() => {
- const response = await axios.get('http://www.ecb.europa.eu/stats/eurofxref/eurofxref-hist-90d.xml');
- const xmlData = response.data;
-
- const doc = new DOMParser({errorHandler: {warning: () => {}}})?.parseFromString(xmlData, 'text/xml');
- const cubes = doc?.getElementsByTagName('Cube');
- if (!cubes || cubes.length === 0)
- throw new UserError('No cubes found. Exiting the method.');
-
+ Self.exchangeRateUpdate = async(options = {}) => {
const models = Self.app.models;
+ const myOptions = {};
+ let tx;
- const maxDateRecord = await models.ReferenceRate.findOne({order: 'dated DESC'});
+ if (typeof options == 'object')
+ Object.assign(myOptions, options);
- const maxDate = maxDateRecord?.dated ? new Date(maxDateRecord.dated) : null;
+ if (!myOptions.transaction) {
+ tx = await Self.beginTransaction({});
+ myOptions.transaction = tx;
+ }
+
+ try {
+ const response = await axios.get('http://www.ecb.europa.eu/stats/eurofxref/eurofxref-hist-90d.xml');
+ const xmlData = response.data;
+
+ const doc = new DOMParser({errorHandler: {warning: () => {}}})
+ .parseFromString(xmlData, 'text/xml');
+ const cubes = doc?.getElementsByTagName('Cube');
+ if (!cubes || cubes.length === 0)
+ throw new UserError('No cubes found. Exiting the method.');
+
+ const currencies = await models.Currency.find({where: {hasToDownloadRate: true}}, myOptions);
+ const maxDateRecord = await models.ReferenceRate.findOne({order: 'dated DESC'}, myOptions);
+ const maxDate = maxDateRecord?.dated ? new Date(maxDateRecord.dated) : null;
+ let lastProcessedDate = maxDate;
+
+ for (const cube of Array.from(cubes)) {
+ if (cube.nodeType === doc.ELEMENT_NODE && cube.attributes.getNamedItem('time')) {
+ const xmlDate = new Date(cube.getAttribute('time'));
+ const xmlDateWithoutTime = new Date(
+ xmlDate.getFullYear(),
+ xmlDate.getMonth(),
+ xmlDate.getDate()
+ );
+
+ if (!maxDate || xmlDateWithoutTime > maxDate) {
+ if (lastProcessedDate && xmlDateWithoutTime > lastProcessedDate) {
+ for (const currency of currencies) {
+ await fillMissingDates(
+ models, currency, lastProcessedDate, xmlDateWithoutTime, myOptions
+ );
+ }
+ }
+ }
- for (const cube of Array.from(cubes)) {
- if (cube.nodeType === doc.ELEMENT_NODE && cube.attributes.getNamedItem('time')) {
- const xmlDate = new Date(cube.getAttribute('time'));
- const xmlDateWithoutTime = new Date(xmlDate.getFullYear(), xmlDate.getMonth(), xmlDate.getDate());
- if (!maxDate || maxDate < xmlDateWithoutTime) {
for (const rateCube of Array.from(cube.childNodes)) {
if (rateCube.nodeType === doc.ELEMENT_NODE) {
const currencyCode = rateCube.getAttribute('currency');
const rate = rateCube.getAttribute('rate');
- if (['USD', 'CNY', 'GBP'].includes(currencyCode)) {
- const currency = await models.Currency.findOne({where: {code: currencyCode}});
- if (!currency) throw new UserError(`Currency not found for code: ${currencyCode}`);
+ const currency = currencies.find(c => c.code === currencyCode);
+ if (currency) {
const existingRate = await models.ReferenceRate.findOne({
- where: {currencyFk: currency.id, dated: xmlDate}
- });
+ where: {currencyFk: currency.id, dated: xmlDateWithoutTime}
+ }, myOptions);
if (existingRate) {
if (existingRate.value !== rate)
- await existingRate.updateAttributes({value: rate});
+ await existingRate.updateAttributes({value: rate}, myOptions);
} else {
await models.ReferenceRate.create({
currencyFk: currency.id,
- dated: xmlDate,
+ dated: xmlDateWithoutTime,
value: rate
- });
- }
- const monday = 1;
- if (xmlDateWithoutTime.getDay() === monday) {
- const saturday = new Date(xmlDateWithoutTime);
- saturday.setDate(xmlDateWithoutTime.getDate() - 2);
- const sunday = new Date(xmlDateWithoutTime);
- sunday.setDate(xmlDateWithoutTime.getDate() - 1);
-
- for (const date of [saturday, sunday]) {
- await models.ReferenceRate.upsertWithWhere(
- {currencyFk: currency.id, dated: date},
- {currencyFk: currency.id, dated: date, value: rate}
- );
- }
+ }, myOptions);
}
}
}
}
+
+ lastProcessedDate = xmlDateWithoutTime;
}
}
+
+ if (tx) await tx.commit();
+ } catch (error) {
+ if (tx) await tx.rollback();
+ throw error;
}
};
+
+ async function getLastValidRate(models, currencyId, date, myOptions) {
+ return models.ReferenceRate.findOne({
+ where: {currencyFk: currencyId, dated: {lt: date}},
+ order: 'dated DESC'
+ }, myOptions);
+ }
+
+ async function fillMissingDates(models, currency, startDate, endDate, myOptions) {
+ const cursor = new Date(startDate);
+ cursor.setDate(cursor.getDate() + 1);
+ while (cursor < endDate) {
+ const existingRate = await models.ReferenceRate.findOne({
+ where: {currencyFk: currency.id, dated: cursor}
+ }, myOptions);
+
+ if (!existingRate) {
+ const lastValid = await getLastValidRate(models, currency.id, cursor, myOptions);
+ if (lastValid) {
+ await models.ReferenceRate.create({
+ currencyFk: currency.id,
+ dated: new Date(cursor),
+ value: lastValid.value
+ }, myOptions);
+ }
+ }
+ cursor.setDate(cursor.getDate() + 1);
+ }
+ }
};
diff --git a/modules/invoiceIn/back/methods/invoice-in/specs/exchangeRateUpdate.spec.js b/modules/invoiceIn/back/methods/invoice-in/specs/exchangeRateUpdate.spec.js
index 0fd7ea165d..c3dcca5ae3 100644
--- a/modules/invoiceIn/back/methods/invoice-in/specs/exchangeRateUpdate.spec.js
+++ b/modules/invoiceIn/back/methods/invoice-in/specs/exchangeRateUpdate.spec.js
@@ -1,52 +1,190 @@
describe('exchangeRateUpdate functionality', function() {
const axios = require('axios');
const models = require('vn-loopback/server/server').models;
+ let tx; let options;
- beforeEach(function() {
- spyOn(axios, 'get').and.returnValue(Promise.resolve({
- data: `
-
-
-
-
- `
- }));
+ function formatYmd(d) {
+ const mm = (d.getMonth() + 1).toString().padStart(2, '0');
+ const dd = d.getDate().toString().padStart(2, '0');
+ return `${d.getFullYear()}-${mm}-${dd}`;
+ }
+
+ afterEach(async() => {
+ await tx.rollback();
});
- it('should process XML data and update or create rates in the database', async function() {
+ beforeEach(async() => {
+ tx = await models.Sale.beginTransaction({});
+ options = {transaction: tx};
+ spyOn(axios, 'get').and.returnValue(Promise.resolve({data: ''}));
+ });
+
+ it('should process XML data and create rates', async function() {
+ const d1 = Date.vnNew();
+ const d4 = Date.vnNew();
+ d4.setDate(d4.getDate() + 1);
+ const xml = `
+
+
+
+
+
+
+
+ `;
+ axios.get.and.returnValue(Promise.resolve({data: xml}));
spyOn(models.ReferenceRate, 'findOne').and.returnValue(Promise.resolve(null));
spyOn(models.ReferenceRate, 'create').and.returnValue(Promise.resolve());
+ await models.InvoiceIn.exchangeRateUpdate(options);
- await models.InvoiceIn.exchangeRateUpdate();
-
- expect(models.ReferenceRate.create).toHaveBeenCalledTimes(2);
+ expect(models.ReferenceRate.create).toHaveBeenCalledTimes(3);
});
- it('should not create or update rates when no XML data is available', async function() {
+ it('should handle no data', async function() {
axios.get.and.returnValue(Promise.resolve({}));
spyOn(models.ReferenceRate, 'create');
-
- let thrownError = null;
+ let e;
try {
- await models.InvoiceIn.exchangeRateUpdate();
- } catch (error) {
- thrownError = error;
+ await models.InvoiceIn.exchangeRateUpdate(options);
+ } catch (err) {
+ e = err;
}
- expect(thrownError.message).toBe('No cubes found. Exiting the method.');
+ expect(e.message).toBe('No cubes found. Exiting the method.');
+ expect(models.ReferenceRate.create).not.toHaveBeenCalled();
});
- it('should handle errors gracefully', async function() {
+ it('should handle errors', async function() {
axios.get.and.returnValue(Promise.reject(new Error('Network error')));
- let error;
-
+ let e;
try {
- await models.InvoiceIn.exchangeRateUpdate();
- } catch (e) {
- error = e;
+ await models.InvoiceIn.exchangeRateUpdate(options);
+ } catch (err) {
+ e = err;
}
- expect(error).toBeDefined();
- expect(error.message).toBe('Network error');
+ expect(e).toBeDefined();
+ expect(e.message).toBe('Network error');
+ });
+
+ it('should update existing rate', async function() {
+ const existingRate = await models.ReferenceRate.findOne({
+ order: 'id DESC'
+ }, options);
+
+ if (!existingRate) return fail('No ReferenceRate records in DB');
+
+ const currency = await models.Currency.findById(existingRate.currencyFk, null, options);
+
+ const xml = `
+
+
+
+ `;
+
+ axios.get.and.returnValue(Promise.resolve({data: xml}));
+
+ await models.InvoiceIn.exchangeRateUpdate(options);
+
+ const updatedRate = await models.ReferenceRate.findById(existingRate.id, null, options);
+
+ expect(updatedRate.value).toBeCloseTo('2.22');
+ });
+
+ it('should not update if same rate', async function() {
+ const existingRate = await models.ReferenceRate.findOne({order: 'id DESC'}, options);
+ if (!existingRate) return fail('No existing ReferenceRate in DB');
+
+ const currency = await models.Currency.findById(existingRate.currencyFk, null, options);
+
+ const oldValue = existingRate.value;
+ const xml = `
+
+
+
+ `;
+
+ axios.get.and.returnValue(Promise.resolve({data: xml}));
+
+ await models.InvoiceIn.exchangeRateUpdate(options);
+
+ const updatedRate = await models.ReferenceRate.findById(existingRate.id, null, options);
+
+ expect(updatedRate.value).toBe(oldValue);
+ });
+
+ it('should backfill missing dates', async function() {
+ const lastRate = await models.ReferenceRate.findOne({order: 'dated DESC'}, options);
+ if (!lastRate) return fail('No existing ReferenceRate data in DB');
+
+ const currency = await models.Currency.findById(lastRate.currencyFk, null, options);
+
+ const d1 = new Date(lastRate.dated);
+ d1.setDate(d1.getDate() + 1);
+ const d4 = new Date(lastRate.dated);
+ d4.setDate(d4.getDate() + 4);
+
+ const xml = `
+
+
+
+
+
+
+ `;
+
+ axios.get.and.returnValue(Promise.resolve({data: xml}));
+
+ const beforeCount = await models.ReferenceRate.count({}, options);
+ await models.InvoiceIn.exchangeRateUpdate(options);
+ const afterCount = await models.ReferenceRate.count({}, options);
+
+ expect(afterCount - beforeCount).toBe(4);
+ });
+
+ it('should create entries for day1 and day2 from the feed, and not backfill day3', async function() {
+ const lastRate = await models.ReferenceRate.findOne({order: 'dated DESC'}, options);
+ if (!lastRate) return fail('No existing ReferenceRate data in DB');
+
+ const currency = await models.Currency.findById(lastRate.currencyFk, null, options);
+ if (!currency) return fail(`No currency for ID ${lastRate.currencyFk}`);
+
+ const day1 = new Date(lastRate.dated);
+ day1.setDate(day1.getDate() + 1);
+
+ const day2 = new Date(lastRate.dated);
+ day2.setDate(day2.getDate() + 2);
+
+ const day3 = new Date(lastRate.dated);
+ day3.setDate(day3.getDate() + 3);
+
+ const xml = `
+
+
+
+
+
+
+ `;
+
+ axios.get.and.returnValue(Promise.resolve({data: xml}));
+
+ await models.InvoiceIn.exchangeRateUpdate(options);
+
+ const day3Record = await models.ReferenceRate.findOne({
+ where: {currencyFk: currency.id, dated: day3}
+ }, options);
+
+ expect(day3Record).toBeNull();
+
+ const day1Record = await models.ReferenceRate.findOne({
+ where: {currencyFk: currency.id, dated: day1}
+ }, options);
+ const day2Record = await models.ReferenceRate.findOne({
+ where: {currencyFk: currency.id, dated: day2}
+ }, options);
+
+ expect(day1Record.value).toBeCloseTo('1.1');
+ expect(day2Record.value).toBeCloseTo('2.2');
});
});
diff --git a/modules/invoiceOut/back/methods/invoiceOut/clientsToInvoice.js b/modules/invoiceOut/back/methods/invoiceOut/clientsToInvoice.js
index 7befdcbeb9..78fce348e5 100644
--- a/modules/invoiceOut/back/methods/invoiceOut/clientsToInvoice.js
+++ b/modules/invoiceOut/back/methods/invoiceOut/clientsToInvoice.js
@@ -49,12 +49,6 @@ module.exports = Self => {
}
try {
- const clientCanBeInvoiced =
- await Self.app.models.Client.canBeInvoiced(clientId, companyFk, myOptions);
-
- if (!clientCanBeInvoiced)
- throw new UserError(`This client can't be invoiced`);
-
const vIsAllInvoiceable = false;
await Self.rawSql('CALL ticketPackaging_add(?, ?, ?, ?)', [
clientId,
@@ -80,7 +74,8 @@ module.exports = Self => {
AND t.companyFk = ?
AND NOT t.isDeleted
GROUP BY IF(c.hasToInvoiceByAddress, a.id, c.id)
- HAVING SUM(t.totalWithVat) > 0;`;
+ HAVING SUM(t.totalWithVat) > 0
+ ORDER BY c.id`;
const addresses = await Self.rawSql(query, [
minShipped,
diff --git a/modules/invoiceOut/back/methods/invoiceOut/specs/clientsToInvoice.spec.js b/modules/invoiceOut/back/methods/invoiceOut/specs/clientsToInvoice.spec.js
index df0566c540..6e536f4331 100644
--- a/modules/invoiceOut/back/methods/invoiceOut/specs/clientsToInvoice.spec.js
+++ b/modules/invoiceOut/back/methods/invoiceOut/specs/clientsToInvoice.spec.js
@@ -1,4 +1,5 @@
const models = require('vn-loopback/server/server').models;
+const LoopBackContext = require('loopback-context');
describe('InvoiceOut clientsToInvoice()', () => {
const userId = 1;
@@ -20,6 +21,21 @@ describe('InvoiceOut clientsToInvoice()', () => {
headers: {origin: 'http://localhost'}
};
const ctx = {req: activeCtx};
+ let tx;
+ let options;
+
+ beforeEach(async() => {
+ LoopBackContext.getCurrentContext = () => ({
+ active: activeCtx,
+ });
+
+ tx = await models.InvoiceOut.beginTransaction({});
+ options = {transaction: tx};
+ });
+
+ afterEach(async() => {
+ await tx.rollback();
+ });
it('should return a list of clients to invoice', async() => {
spyOn(models.InvoiceOut, 'rawSql').and.callFake(query => {
@@ -37,24 +53,14 @@ describe('InvoiceOut clientsToInvoice()', () => {
}
});
- const tx = await models.InvoiceOut.beginTransaction({});
- const options = {transaction: tx};
+ const addresses = await models.InvoiceOut.clientsToInvoice(
+ ctx, clientId, invoiceDate, maxShipped, companyFk, options);
- try {
- const addresses = await models.InvoiceOut.clientsToInvoice(
- ctx, clientId, invoiceDate, maxShipped, companyFk, options);
-
- expect(addresses.length).toBeGreaterThan(0);
- expect(addresses[0].clientId).toBe(clientId);
- expect(addresses[0].clientName).toBe('Test Client');
- expect(addresses[0].id).toBe(1);
- expect(addresses[0].nickname).toBe('Address 1');
-
- await tx.rollback();
- } catch (e) {
- await tx.rollback();
- throw e;
- }
+ expect(addresses.length).toBeGreaterThan(0);
+ expect(addresses[0].clientId).toBe(clientId);
+ expect(addresses[0].clientName).toBe('Test Client');
+ expect(addresses[0].id).toBe(1);
+ expect(addresses[0].nickname).toBe('Address 1');
});
it('should handle errors and rollback transaction', async() => {
@@ -62,14 +68,20 @@ describe('InvoiceOut clientsToInvoice()', () => {
return Promise.reject(new Error('Test Error'));
});
- const tx = await models.InvoiceOut.beginTransaction({});
- const options = {transaction: tx};
-
try {
await models.InvoiceOut.clientsToInvoice(ctx, clientId, invoiceDate, maxShipped, companyFk, options);
} catch (e) {
expect(e.message).toBe('Test Error');
- await tx.rollback();
}
});
+
+ it('should return all list', async() => {
+ const minShipped = Date.vnNew();
+ minShipped.setFullYear(maxShipped.getFullYear() - 1);
+
+ const toInvoice = await models.InvoiceOut.clientsToInvoice(
+ ctx, null, invoiceDate, maxShipped, companyFk, options);
+
+ expect(toInvoice).toBeDefined();
+ });
});
diff --git a/modules/item/back/models/item-shelving.json b/modules/item/back/models/item-shelving.json
index 483d6bf3dc..5c31e9e4e1 100644
--- a/modules/item/back/models/item-shelving.json
+++ b/modules/item/back/models/item-shelving.json
@@ -61,6 +61,11 @@
"type": "belongsTo",
"model": "Shelving",
"foreignKey": "shelvingFk"
- }
+ },
+ "buy": {
+ "type": "belongsTo",
+ "model": "Buy",
+ "foreignKey": "buyFk"
+ }
}
-}
\ No newline at end of file
+}
diff --git a/modules/item/back/models/item-tag.js b/modules/item/back/models/item-tag.js
index 5b71639130..2cd2e5f9bf 100644
--- a/modules/item/back/models/item-tag.js
+++ b/modules/item/back/models/item-tag.js
@@ -10,4 +10,27 @@ module.exports = Self => {
return new UserError(`Tag value cannot be blank`);
return err;
});
+
+ Self.observe('before save', async ctx => {
+ let tagFk;
+ let value;
+
+ if (ctx.isNewInstance) {
+ tagFk = ctx.instance.tagFk;
+ value = ctx.instance.value;
+ } else {
+ tagFk = ctx.currentInstance.tagFk;
+ value = ctx.data.value;
+ }
+ const models = Self.app.models;
+ const validTag = await models.Tag.findById(tagFk);
+
+ if (validTag.validationRegex) {
+ const regexString = validTag.validationRegex.replace(/\\\\/g, '\\');
+ const validExpresion = new RegExp(regexString);
+
+ if (value && !validExpresion.test(value))
+ throw new UserError('The value must be a number or a range of numbers');
+ }
+ });
};
diff --git a/modules/item/back/models/tag.json b/modules/item/back/models/tag.json
index 6c5f5c0ba1..5269b849f9 100644
--- a/modules/item/back/models/tag.json
+++ b/modules/item/back/models/tag.json
@@ -30,6 +30,9 @@
"mysql": {
"columnName": "isQuantitatif"
}
+ },
+ "validationRegex": {
+ "type": "string"
}
},
"acls": [
diff --git a/modules/monitor/back/methods/sales-monitor/salesFilter.js b/modules/monitor/back/methods/sales-monitor/salesFilter.js
index 740fae6576..ab2a64293e 100644
--- a/modules/monitor/back/methods/sales-monitor/salesFilter.js
+++ b/modules/monitor/back/methods/sales-monitor/salesFilter.js
@@ -123,25 +123,13 @@ module.exports = Self => {
date.setHours(0, 0, 0, 0);
const args = ctx.args;
const myOptions = {};
+ let myTeamIds = [];
if (typeof options == 'object')
Object.assign(myOptions, options);
- // Apply filter by team
- const teamMembersId = [];
- if (args.myTeam != null) {
- const worker = await models.Worker.findById(userId, {
- include: {
- relation: 'collegues'
- }
- }, myOptions);
- const collegues = worker.collegues() || [];
- for (let collegue of collegues)
- teamMembersId.push(collegue.collegueFk);
-
- if (teamMembersId.length == 0)
- teamMembersId.push(userId);
- }
+ if (args.myTeam != null)
+ myTeamIds = await models.Worker.myTeam(userId);
if (ctx.args && args.to) {
const dateTo = args.to;
@@ -163,9 +151,9 @@ module.exports = Self => {
case 'mine':
case 'myTeam':
if (value)
- return {'c.salesPersonFk': {inq: teamMembersId}};
+ return {'c.salesPersonFk': {inq: myTeamIds}};
else
- return {'c.salesPersonFk': {nin: teamMembersId}};
+ return {'c.salesPersonFk': {nin: myTeamIds}};
case 'id':
case 'clientFk':
param = `t.${param}`;
diff --git a/modules/order/back/methods/order/filter.js b/modules/order/back/methods/order/filter.js
index 2aeb1aac56..f24d9b2258 100644
--- a/modules/order/back/methods/order/filter.js
+++ b/modules/order/back/methods/order/filter.js
@@ -80,29 +80,15 @@ module.exports = Self => {
const conn = Self.dataSource.connector;
const myOptions = {};
const userId = ctx.req.accessToken.userId;
+ let myTeamIds = [];
if (typeof options == 'object')
Object.assign(myOptions, options);
const args = ctx.args;
- // Apply filter by team
- const teamMembersId = [];
- if (args.myTeam != null) {
- const worker = await models.Worker.findById(userId, {
- include: {
- relation: 'collegues'
- }
- }, myOptions);
- const collegues = worker.collegues() || [];
- for (let collegue of collegues)
- teamMembersId.push(collegue.collegueFk);
- if (teamMembersId.length == 0)
- teamMembersId.push(userId);
- }
-
- if (args?.myTeam)
- args.teamIds = teamIds;
+ if (args.myTeam != null)
+ myTeamIds = await models.Worker.myTeam(userId);
if (args?.to)
args.to.setHours(23, 59, 0, 0);
@@ -133,9 +119,9 @@ module.exports = Self => {
return {'o.confirmed': value ? 1 : 0};
case 'myTeam':
if (value)
- return {'c.salesPersonFk': {inq: teamMembersId}};
+ return {'c.salesPersonFk': {inq: myTeamIds}};
else
- return {'c.salesPersonFk': {nin: teamMembersId}};
+ return {'c.salesPersonFk': {nin: myTeamIds}};
case 'showEmpty':
return {'o.total': {neq: value}};
case 'id':
diff --git a/modules/supplier/back/methods/supplier/newSupplier.js b/modules/supplier/back/methods/supplier/newSupplier.js
index 3cca4195ff..eb941ed692 100644
--- a/modules/supplier/back/methods/supplier/newSupplier.js
+++ b/modules/supplier/back/methods/supplier/newSupplier.js
@@ -28,6 +28,7 @@ module.exports = Self => {
delete args.ctx;
if (!args.name) throw new UserError('The social name cannot be empty');
+ if (args.name !== args.name.toUpperCase()) throw new UserError('Social name should be uppercase');
const data = {...args, ...{nickname: args.name}};
const supplier = await models.Supplier.create(data, myOptions);
diff --git a/modules/ticket/back/methods/ticket-request/filter.js b/modules/ticket/back/methods/ticket-request/filter.js
index c2edcae81a..1318c1ab35 100644
--- a/modules/ticket/back/methods/ticket-request/filter.js
+++ b/modules/ticket/back/methods/ticket-request/filter.js
@@ -87,6 +87,7 @@ module.exports = Self => {
const myOptions = {};
const models = Self.app.models;
const args = ctx.args;
+ let myTeamIds = [];
if (typeof options == 'object')
Object.assign(myOptions, options);
@@ -94,20 +95,8 @@ module.exports = Self => {
if (ctx.args.mine)
ctx.args.attenderFk = userId;
- const teamMembersId = [];
- if (args.myTeam != null) {
- const worker = await models.Worker.findById(userId, {
- include: {
- relation: 'collegues'
- }
- }, myOptions);
- const collegues = worker.collegues() || [];
- for (let collegue of collegues)
- teamMembersId.push(collegue.collegueFk);
-
- if (teamMembersId.length == 0)
- teamMembersId.push(userId);
- }
+ if (args.myTeam != null)
+ myTeamIds = await models.Worker.myTeam(userId);
const today = Date.vnNew();
const future = Date.vnNew();
@@ -145,9 +134,9 @@ module.exports = Self => {
return {'c.salesPersonFk': value};
case 'myTeam':
if (value)
- return {'tr.requesterFk': {inq: teamMembersId}};
+ return {'tr.requesterFk': {inq: myTeamIds}};
else
- return {'tr.requesterFk': {nin: teamMembersId}};
+ return {'tr.requesterFk': {nin: myTeamIds}};
case 'daysOnward':
today.setHours(0, 0, 0, 0);
future.setDate(today.getDate() + value);
diff --git a/modules/ticket/back/methods/ticket-request/getItemTypeWorker.js b/modules/ticket/back/methods/ticket-request/getItemTypeWorker.js
index f160cfaaca..2f2a85abbf 100644
--- a/modules/ticket/back/methods/ticket-request/getItemTypeWorker.js
+++ b/modules/ticket/back/methods/ticket-request/getItemTypeWorker.js
@@ -30,7 +30,7 @@ module.exports = Self => {
Object.assign(myOptions, options);
const query =
- `SELECT DISTINCT u.id, u.nickname
+ `SELECT DISTINCT u.id, u.nickname, w.firstName, w.lastName
FROM itemType it
JOIN worker w ON w.id = it.workerFk
JOIN account.user u ON u.id = w.id`;
diff --git a/modules/ticket/back/methods/ticket/filter.js b/modules/ticket/back/methods/ticket/filter.js
index 632634a37f..32b2197ad5 100644
--- a/modules/ticket/back/methods/ticket/filter.js
+++ b/modules/ticket/back/methods/ticket/filter.js
@@ -142,28 +142,14 @@ module.exports = Self => {
date.setHours(0, 0, 0, 0);
const models = Self.app.models;
const args = ctx.args;
-
+ let myTeamIds = [];
const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
- // Apply filter by team
- const teamMembersId = [];
- if (args.myTeam != null) {
- const worker = await models.Worker.findById(userId, {
- include: {
- relation: 'collegues'
- }
- }, myOptions);
-
- const collegues = worker.collegues() || [];
- for (let collegue of collegues)
- teamMembersId.push(collegue.collegueFk);
-
- if (teamMembersId.length == 0)
- teamMembersId.push(userId);
- }
+ if (args.myTeam != null)
+ myTeamIds = await models.Worker.myTeam(userId);
if (ctx.args && args.to) {
const dateTo = args.to;
@@ -195,9 +181,9 @@ module.exports = Self => {
case 'mine':
case 'myTeam':
if (value)
- return {'c.salesPersonFk': {inq: teamMembersId}};
+ return {'c.salesPersonFk': {inq: myTeamIds}};
else
- return {'c.salesPersonFk': {nin: teamMembersId}};
+ return {'c.salesPersonFk': {nin: myTeamIds}};
case 'alertLevel':
return {'ts.alertLevel': value};
diff --git a/modules/ticket/back/methods/ticket/merge.js b/modules/ticket/back/methods/ticket/merge.js
index 1106cef06f..6922ad1701 100644
--- a/modules/ticket/back/methods/ticket/merge.js
+++ b/modules/ticket/back/methods/ticket/merge.js
@@ -40,21 +40,23 @@ module.exports = Self => {
try {
for (let ticket of tickets) {
- const originFullPath = `${url}ticket/${ticket.originId}/summary`;
- const destinationFullPath = `${url}ticket/${ticket.destinationId}/summary`;
- const message = $t('Ticket merged', {
- originDated: dateUtil.toString(new Date(ticket.originShipped)),
- destinationDated: dateUtil.toString(new Date(ticket.destinationShipped)),
- originId: ticket.originId,
- destinationId: ticket.destinationId,
- originFullPath,
- destinationFullPath
- });
if (!ticket.originId || !ticket.destinationId) continue;
await models.Sale.updateAll({ticketFk: ticket.originId}, {ticketFk: ticket.destinationId}, myOptions);
- if (await models.Ticket.setDeleted(ctx, ticket.originId, myOptions))
- await models.Chat.sendCheckingPresence(ctx, ticket.workerFk, message);
+ if (await models.Ticket.setDeleted(ctx, ticket.originId, myOptions)) {
+ if (!ticket.salesPersonFk) continue;
+ const originFullPath = `${url}ticket/${ticket.originId}/summary`;
+ const destinationFullPath = `${url}ticket/${ticket.destinationId}/summary`;
+ const message = $t('Ticket merged', {
+ originDated: dateUtil.toString(new Date(ticket.originShipped)),
+ destinationDated: dateUtil.toString(new Date(ticket.destinationShipped)),
+ originId: ticket.originId,
+ destinationId: ticket.destinationId,
+ originFullPath,
+ destinationFullPath
+ });
+ await models.Chat.sendCheckingPresence(ctx, ticket.salesPersonFk, message);
+ }
}
if (tx)
await tx.commit();
diff --git a/modules/ticket/back/methods/ticket/priceDifference.js b/modules/ticket/back/methods/ticket/priceDifference.js
index 7db03e2685..7e4fe82835 100644
--- a/modules/ticket/back/methods/ticket/priceDifference.js
+++ b/modules/ticket/back/methods/ticket/priceDifference.js
@@ -108,7 +108,10 @@ module.exports = Self => {
// Get items movable
const ticketOrigin = await models.Ticket.findById(args.id, null, myOptions);
- const differenceShipped = ticketOrigin.shipped.getTime() > args.shipped.getTime();
+ let shipped = ticketOrigin.shipped ?? ticketOrigin.updated;
+
+ const differenceShipped = shipped.getTime() > args.shipped.getTime();
+
const differenceWarehouse = ticketOrigin.warehouseFk != args.warehouseId;
salesObj.haveDifferences = differenceShipped || differenceWarehouse;
diff --git a/modules/ticket/back/methods/ticket/saveSign.js b/modules/ticket/back/methods/ticket/saveSign.js
index ac2a7bc669..f99311c392 100644
--- a/modules/ticket/back/methods/ticket/saveSign.js
+++ b/modules/ticket/back/methods/ticket/saveSign.js
@@ -28,7 +28,6 @@ module.exports = Self => {
verb: 'POST'
}
});
-
Self.saveSign = async(ctx, tickets, location, signedTime, options) => {
const models = Self.app.models;
const myOptions = {userId: ctx.req.accessToken.userId};
@@ -111,6 +110,12 @@ module.exports = Self => {
scope: {
fields: ['id']
}
+ },
+ {
+ relation: 'zone',
+ scope: {
+ fields: ['id', 'zoneFk,', 'name']
+ }
}]
}, myOptions);
@@ -151,6 +156,28 @@ module.exports = Self => {
await Self.rawSql(`CALL vn.ticket_setState(?, ?)`, [ticketId, stateCode], myOptions);
+ if (stateCode == 'DELIVERED' && ticket.priority) {
+ const orderState = await models.State.findOne({
+ where: {code: 'DELIVERED'},
+ fields: ['id']
+ }, myOptions);
+
+ const ticketIncorrect = await Self.rawSql(`
+ SELECT t.id
+ FROM ticket t
+ JOIN ticketState ts ON ts.ticketFk = t.id
+ JOIN state s ON s.code = ts.code
+ WHERE t.routeFk = ?
+ AND s.\`order\` < ?
+ AND priority <(SELECT t.priority
+ FROM ticket t
+ WHERE t.id = ?)`
+ , [ticket.routeFk, orderState.id, ticket.id], myOptions);
+
+ if (ticketIncorrect?.length > 0)
+ await sendMail(ctx, ticket.routeFk, ticket.id, ticket.zone().name);
+ }
+
if (ticket?.address()?.province()?.country()?.code != 'ES' && ticket.$cmrFk) {
await models.Ticket.saveCmr(ctx, [ticketId], myOptions);
externalTickets.push(ticketId);
@@ -163,4 +190,25 @@ module.exports = Self => {
}
await models.Ticket.sendCmrEmail(ctx, externalTickets);
};
+
+ async function sendMail(ctx, route, ticket, zoneName) {
+ const $t = ctx.req.__;
+ const url = await Self.app.models.Url.getUrl();
+ const sendTo = 'repartos@verdnatura.es';
+ const fullUrl = `${url}route/${route}/summary`;
+ const emailSubject = $t('Incorrect delivery order alert on route', {
+ route,
+ zone: zoneName
+ });
+ const emailBody = $t('Ticket has been delivered out of order', {
+ ticket,
+ fullUrl
+ });
+
+ await Self.app.models.Mail.create({
+ receiver: sendTo,
+ subject: emailSubject,
+ body: emailBody
+ });
+ }
};
diff --git a/modules/ticket/back/methods/ticket/specs/merge.spec.js b/modules/ticket/back/methods/ticket/specs/merge.spec.js
index 68f9d33936..99e0c6e819 100644
--- a/modules/ticket/back/methods/ticket/specs/merge.spec.js
+++ b/modules/ticket/back/methods/ticket/specs/merge.spec.js
@@ -7,7 +7,7 @@ describe('ticket merge()', () => {
destinationId: 12,
originShipped: Date.vnNew(),
destinationShipped: Date.vnNew(),
- workerFk: 1
+ salesPersonFk: 1
};
it('should merge two tickets', async() => {
diff --git a/modules/ticket/back/methods/ticket/specs/saveSign.spec.js b/modules/ticket/back/methods/ticket/specs/saveSign.spec.js
index e93408973a..3b426c2cf9 100644
--- a/modules/ticket/back/methods/ticket/specs/saveSign.spec.js
+++ b/modules/ticket/back/methods/ticket/specs/saveSign.spec.js
@@ -1,12 +1,20 @@
const models = require('vn-loopback/server/server').models;
+const LoopBackContext = require('loopback-context');
describe('Ticket saveSign()', () => {
let ctx = {req: {
getLocale: () => {
return 'en';
},
+ __: () => {},
accessToken: {userId: 9}
- }};
+ }
+ };
+ beforeEach(() => {
+ spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
+ active: ctx
+ });
+ });
it(`should throw error if the ticket's alert level is lower than 2`, async() => {
const tx = await models.TicketDms.beginTransaction({});
@@ -51,4 +59,46 @@ describe('Ticket saveSign()', () => {
expect(ticketTrackingAfter.name).toBe('Entregado en parte');
});
+
+ it('should send an email to notify that the delivery order is not correct', async() => {
+ const tx = await models.Ticket.beginTransaction({});
+ const ticketFk = 8;
+ const priority = 5;
+ const stateFk = 10;
+ const stateTicketFk = 2;
+ const expeditionFk = 11;
+ const expeditionStateFK = 2;
+
+ let mailCountBefore;
+ let mailCountAfter;
+ spyOn(models.Dms, 'uploadFile').and.returnValue([{id: 1}]);
+
+ const options = {transaction: tx};
+ const tickets = [ticketFk];
+
+ const expedition = await models.Expedition.findById(expeditionFk, null, options);
+ expedition.updateAttribute('stateTypeFk', expeditionStateFK, options);
+
+ const ticket = await models.Ticket.findById(ticketFk, null, options);
+ ticket.updateAttribute('priority', priority, options);
+
+ const filter = {where: {
+ ticketFk: ticketFk,
+ stateFk: stateTicketFk}
+ };
+ try {
+ const ticketTracking = await models.TicketTracking.findOne(filter, options);
+ ticketTracking.updateAttribute('stateFk', stateFk, options);
+ mailCountBefore = await models.Mail.count(options);
+ await models.Ticket.saveSign(ctx, tickets, null, null, options);
+ mailCountAfter = await models.Mail.count(options);
+
+ await tx.rollback();
+ } catch (e) {
+ await tx.rollback();
+ throw e;
+ }
+
+ expect(mailCountAfter).toBeGreaterThan(mailCountBefore);
+ });
});
diff --git a/modules/ticket/back/methods/ticket/specs/transferClient.spec.js b/modules/ticket/back/methods/ticket/specs/transferClient.spec.js
index d3ac3c6aa6..063433680b 100644
--- a/modules/ticket/back/methods/ticket/specs/transferClient.spec.js
+++ b/modules/ticket/back/methods/ticket/specs/transferClient.spec.js
@@ -22,14 +22,16 @@ describe('Ticket transferClient()', () => {
it('should throw an error as the ticket is not editable', async() => {
try {
const ticketId = 4;
- await models.Ticket.transferClient(ctx, ticketId, clientId, options);
+ const addressFk = null;
+ await models.Ticket.transferClient(ctx, ticketId, clientId, addressFk, options);
} catch (e) {
expect(e.message).toEqual('This ticket is locked');
}
});
it('should be assigned a different clientFk and nickname in the original ticket', async() => {
- await models.Ticket.transferClient(ctx, 2, clientId, options);
+ const addressFk = null;
+ await models.Ticket.transferClient(ctx, 2, clientId, addressFk, options);
const afterTransfer = await models.Ticket.findById(2, null, options);
const client = await models.Client.findById(clientId, {fields: ['defaultAddressFk']}, options);
const address = await models.Address.findById(client.defaultAddressFk, {fields: ['nickname']}, options);
@@ -39,7 +41,8 @@ describe('Ticket transferClient()', () => {
});
it('should be assigned a different clientFk and nickname in the original and refund ticket and claim', async() => {
- await models.Ticket.transferClient(ctx, originalTicketId, clientId, options);
+ const addressFk = null;
+ await models.Ticket.transferClient(ctx, originalTicketId, clientId, addressFk, options);
const [originalTicket, refundTicket] = await models.Ticket.find({
where: {id: {inq: [originalTicketId, refundTicketId]}}
@@ -59,4 +62,39 @@ describe('Ticket transferClient()', () => {
expect(originalTicket.nickname).toEqual(address.nickname);
expect(refundTicket.nickname).toEqual(address.nickname);
});
+
+ it('should be assigned a different addressFk and nickname in the original and refund ticket', async() => {
+ const addressFk = 131;
+ await models.Ticket.transferClient(ctx, originalTicketId, clientId, addressFk, options);
+
+ const [originalTicket, refundTicket] = await models.Ticket.find({
+ where: {id: {inq: [originalTicketId, refundTicketId]}}
+ }, options);
+
+ const claim = await models.Claim.findOne({
+ where: {ticketFk: originalTicketId}
+ }, options);
+
+ const address = await models.Address.findById(addressFk, {fields: ['id', 'nickname', 'clientFk']}, options);
+
+ expect(originalTicket.clientFk).toEqual(clientId);
+ expect(originalTicket.clientFk).toEqual(address.clientFk);
+ expect(refundTicket.clientFk).toEqual(clientId);
+ expect(refundTicket.clientFk).toEqual(address.clientFk);
+ expect(claim.clientFk).toEqual(clientId);
+ expect(claim.clientFk).toEqual(address.clientFk);
+
+ expect(originalTicket.nickname).toEqual(address.nickname);
+ expect(refundTicket.nickname).toEqual(address.nickname);
+ });
+
+ it('should be thrown an error if the new address is not belong to the client', async() => {
+ const addressFk = 1;
+ try {
+ await models.Ticket.transferClient(ctx, originalTicketId, clientId, addressFk, options);
+ fail('Expected an error to be thrown, but none was thrown.');
+ } catch (e) {
+ expect(e.message).toEqual('The address does not belong to the client');
+ }
+ });
});
diff --git a/modules/ticket/back/methods/ticket/summary.js b/modules/ticket/back/methods/ticket/summary.js
index 6bfa478ecc..88894cef77 100644
--- a/modules/ticket/back/methods/ticket/summary.js
+++ b/modules/ticket/back/methods/ticket/summary.js
@@ -72,7 +72,8 @@ module.exports = Self => {
}, {
relation: 'address',
scope: {
- fields: ['street', 'city', 'provinceFk', 'phone', 'mobile', 'postalCode', 'isEqualizated'],
+ fields: ['street', 'city', 'provinceFk', 'phone', 'mobile',
+ 'postalCode', 'isEqualizated', 'nickname'],
include: {
relation: 'province',
scope: {
diff --git a/modules/ticket/back/methods/ticket/transferClient.js b/modules/ticket/back/methods/ticket/transferClient.js
index 95bee008da..2e845144ed 100644
--- a/modules/ticket/back/methods/ticket/transferClient.js
+++ b/modules/ticket/back/methods/ticket/transferClient.js
@@ -1,3 +1,4 @@
+const UserError = require('vn-loopback/util/user-error');
module.exports = Self => {
Self.remoteMethodCtx('transferClient', {
description: 'Transferring ticket to another client',
@@ -12,6 +13,10 @@ module.exports = Self => {
arg: 'clientFk',
type: 'number',
required: true,
+ }, {
+ arg: 'addressFk',
+ type: 'number',
+ required: false,
}],
http: {
path: `/:id/transferClient`,
@@ -19,7 +24,7 @@ module.exports = Self => {
}
});
- Self.transferClient = async(ctx, id, clientFk, options) => {
+ Self.transferClient = async(ctx, id, clientFk, addressFk, options) => {
const models = Self.app.models;
const myOptions = {};
let tx;
@@ -43,10 +48,12 @@ module.exports = Self => {
const client = await models.Client.findById(clientFk,
{fields: ['id', 'defaultAddressFk']}, myOptions);
- const address = await models.Address.findById(client.defaultAddressFk,
- {fields: ['id', 'nickname']}, myOptions);
+ const address = await models.Address.findById(addressFk ? addressFk : client.defaultAddressFk,
+ {fields: ['id', 'nickname', 'clientFk']}, myOptions);
- const attributes = {clientFk, addressFk: client.defaultAddressFk, nickname: address.nickname};
+ if (address.clientFk !== clientFk) throw new UserError('The address does not belong to the client');
+
+ const attributes = {clientFk, addressFk: address.id, nickname: address.nickname};
const tickets = [];
const ticketIds = [];
diff --git a/modules/travel/back/methods/travel/filter.js b/modules/travel/back/methods/travel/filter.js
index 30c1a45fad..837e30b305 100644
--- a/modules/travel/back/methods/travel/filter.js
+++ b/modules/travel/back/methods/travel/filter.js
@@ -1,4 +1,3 @@
-
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
const buildFilter = require('vn-loopback/util/filter').buildFilter;
const mergeFilters = require('vn-loopback/util/filter').mergeFilters;
@@ -91,6 +90,11 @@ module.exports = Self => {
arg: 'landed',
type: 'date',
description: 'The landed date'
+ },
+ {
+ arg: 'awbFk',
+ type: 'number',
+ description: 'The awbFk id'
}
],
returns: {
@@ -168,14 +172,17 @@ module.exports = Self => {
t.totalEntries,
t.isRaid,
t.daysInForward,
+ t.awbFk,
am.name agencyModeName,
+ a.code awbCode,
win.name warehouseInName,
wout.name warehouseOutName,
cnt.code continent
- FROM vn.travel t
- JOIN vn.agencyMode am ON am.id = t.agencyModeFk
- JOIN vn.warehouse win ON win.id = t.warehouseInFk
- JOIN vn.warehouse wout ON wout.id = t.warehouseOutFk
+ FROM travel t
+ JOIN agencyMode am ON am.id = t.agencyModeFk
+ JOIN warehouse win ON win.id = t.warehouseInFk
+ JOIN warehouse wout ON wout.id = t.warehouseOutFk
+ LEFT JOIN awb a ON a.id = t.awbFk
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) AS t`
diff --git a/modules/travel/back/methods/travel/getEntries.js b/modules/travel/back/methods/travel/getEntries.js
index 50088ccfaf..2399f8bc48 100644
--- a/modules/travel/back/methods/travel/getEntries.js
+++ b/modules/travel/back/methods/travel/getEntries.js
@@ -41,7 +41,9 @@ module.exports = Self => {
* b.stickers)/1000000) AS DECIMAL(10,2)) m3,
TRUNCATE(SUM(b.stickers)/(COUNT( b.id) / COUNT( DISTINCT b.id)),0) hb,
CAST(SUM(b.freightValue*b.quantity) AS DECIMAL(10,2)) freightValue,
- CAST(SUM(b.packageValue*b.quantity) AS DECIMAL(10,2)) packageValue
+ CAST(SUM(b.packageValue*b.quantity) AS DECIMAL(10,2)) packageValue,
+ e.initialTemperature,
+ e.finalTemperature
FROM vn.travel t
LEFT JOIN vn.entry e ON t.id = e.travelFk
LEFT JOIN vn.buy b ON b.entryFk = e.id
diff --git a/modules/travel/back/methods/travel/saveThermograph.js b/modules/travel/back/methods/travel/saveThermograph.js
index 6f7e1c8bf6..2517b0b8c9 100644
--- a/modules/travel/back/methods/travel/saveThermograph.js
+++ b/modules/travel/back/methods/travel/saveThermograph.js
@@ -57,6 +57,10 @@ module.exports = Self => {
arg: 'hasFileAttached',
type: 'Boolean',
description: 'True if has an attached file'
+ }, {
+ arg: 'agencyModeFk',
+ type: 'Number',
+ description: 'Carrier'
}],
returns: {type: 'object', root: true},
http: {path: `/:id/saveThermograph`, verb: 'POST'}
@@ -76,6 +80,7 @@ module.exports = Self => {
reference,
description,
hasFileAttached,
+ agencyModeFk,
options
) => {
const models = Self.app.models;
@@ -119,6 +124,7 @@ module.exports = Self => {
minTemperature,
temperatureFk,
warehouseFk: warehouseId,
+ agencyModeFk,
}, myOptions);
if (tx) await tx.commit();
diff --git a/modules/travel/back/methods/travel/specs/saveThermograph.spec.js b/modules/travel/back/methods/travel/specs/saveThermograph.spec.js
index c2da4234ec..0f5f248bfb 100644
--- a/modules/travel/back/methods/travel/specs/saveThermograph.spec.js
+++ b/modules/travel/back/methods/travel/specs/saveThermograph.spec.js
@@ -9,6 +9,7 @@ describe('Thermograph saveThermograph()', () => {
const maxTemperature = 30;
const minTemperature = 10;
const temperatureFk = 'COOL';
+ const agencyModeFk = 1;
let tx;
let options;
@@ -46,13 +47,16 @@ describe('Thermograph saveThermograph()', () => {
null,
null,
null,
- null, options
+ null,
+ agencyModeFk,
+ options
);
expect(updatedThermograph.result).toEqual(state);
expect(updatedThermograph.maxTemperature).toEqual(maxTemperature);
expect(updatedThermograph.minTemperature).toEqual(minTemperature);
expect(updatedThermograph.temperatureFk).toEqual(temperatureFk);
+ expect(updatedThermograph.agencyModeFk).toEqual(agencyModeFk);
expect(updatedThermograph.dmsFk).toEqual(dmsFk);
});
diff --git a/modules/travel/back/model-config.json b/modules/travel/back/model-config.json
index 952ce0d20f..e7a6441800 100644
--- a/modules/travel/back/model-config.json
+++ b/modules/travel/back/model-config.json
@@ -22,5 +22,8 @@
},
"Temperature": {
"dataSource": "vn"
+ },
+ "AgencyModeIncoming": {
+ "dataSource": "vn"
}
-}
\ No newline at end of file
+}
diff --git a/modules/travel/back/models/agency-mode-incoming.json b/modules/travel/back/models/agency-mode-incoming.json
new file mode 100644
index 0000000000..efefaf8729
--- /dev/null
+++ b/modules/travel/back/models/agency-mode-incoming.json
@@ -0,0 +1,27 @@
+{
+ "name": "AgencyModeIncoming",
+ "base": "VnModel",
+ "options": {
+ "mysql": {
+ "table": "agencyModeIncoming"
+ }
+ },
+ "properties": {
+ "id": {
+ "type": "number",
+ "id": true,
+ "description": "Identifier"
+ },
+ "name": {
+ "type": "string"
+ }
+ },
+ "acls": [
+ {
+ "accessType": "READ",
+ "principalType": "ROLE",
+ "principalId": "$everyone",
+ "permission": "ALLOW"
+ }
+ ]
+}
diff --git a/modules/travel/back/models/currency.json b/modules/travel/back/models/currency.json
index f3241fad1b..427a18e312 100644
--- a/modules/travel/back/models/currency.json
+++ b/modules/travel/back/models/currency.json
@@ -20,6 +20,9 @@
},
"ratio": {
"type": "number"
+ },
+ "hasToDownloadRate": {
+ "type": "boolean"
}
},
"acls": [
diff --git a/modules/travel/back/models/travel-thermograph.json b/modules/travel/back/models/travel-thermograph.json
index cb0a9b4f8f..79b6925078 100644
--- a/modules/travel/back/models/travel-thermograph.json
+++ b/modules/travel/back/models/travel-thermograph.json
@@ -58,6 +58,11 @@
"type": "belongsTo",
"model": "Thermograph",
"foreignKey": "thermographFk"
+ },
+ "agencyMode": {
+ "type": "belongsTo",
+ "model": "AgencyMode",
+ "foreignKey": "agencyModeFk"
}
}
}
diff --git a/modules/worker/back/methods/worker/filter.js b/modules/worker/back/methods/worker/filter.js
index 52c60572a7..087f080bd7 100644
--- a/modules/worker/back/methods/worker/filter.js
+++ b/modules/worker/back/methods/worker/filter.js
@@ -73,6 +73,11 @@ module.exports = Self => {
type: 'String',
description: 'The user email',
http: {source: 'query'}
+ },
+ {
+ arg: 'myTeam',
+ type: 'boolean',
+ description: 'Whether to show only tickets for the current logged user team (currently user tickets)'
}
],
returns: {
@@ -85,10 +90,21 @@ module.exports = Self => {
}
});
- Self.filter = async(ctx, filter) => {
- let conn = Self.dataSource.connector;
+ Self.filter = async(ctx, filter, options) => {
+ const userId = ctx.req.accessToken.userId;
+ const conn = Self.dataSource.connector;
+ const models = Self.app.models;
+ const args = ctx.args;
+ let myTeamIds = [];
+ const myOptions = {};
- let where = buildFilter(ctx.args, (param, value) => {
+ if (typeof options == 'object')
+ Object.assign(myOptions, options);
+
+ if (args.myTeam != null)
+ myTeamIds = await models.Worker.myTeam(userId);
+
+ const where = buildFilter(ctx.args, (param, value) => {
switch (param) {
case 'search':
return /^\d+$/.test(value)
@@ -117,12 +133,17 @@ module.exports = Self => {
return {'u.name': {like: `%${value}%`}};
case 'email':
return {'eu.email': {like: `%${value}%`}};
+ case 'myTeam':
+ if (value)
+ return {'c.salesPersonFk': {inq: myTeamIds}};
+ else
+ return {'c.salesPersonFk': {nin: myTeamIds}};
}
});
- filter = mergeFilters(ctx.args.filter, {where});
+ filter = mergeFilters(filter, {where});
- let stmts = [];
+ const stmts = [];
let stmt;
stmt = new ParameterizedSQL(
@@ -145,11 +166,12 @@ module.exports = Self => {
LEFT JOIN account.emailUser eu ON eu.userFk = u.id`
);
- stmt.merge(conn.makeSuffix(filter));
- let itemsIndex = stmts.push(stmt) - 1;
+ stmt.merge(conn.makeWhere(filter.where));
+ stmts.push(stmt);
- let sql = ParameterizedSQL.join(stmts, ';');
- let result = await conn.executeStmt(sql);
- return itemsIndex === 0 ? result : result[itemsIndex];
+ const itemsIndex = stmts.push(stmt) - 1;
+ const sql = ParameterizedSQL.join(stmts, ';');
+ const result = await conn.executeStmt(sql, myOptions);
+ return result[itemsIndex];
};
};
diff --git a/modules/worker/back/methods/worker/myTeam.js b/modules/worker/back/methods/worker/myTeam.js
new file mode 100644
index 0000000000..25c5916fb6
--- /dev/null
+++ b/modules/worker/back/methods/worker/myTeam.js
@@ -0,0 +1,43 @@
+module.exports = Self => {
+ Self.remoteMethod('myTeam', {
+ description: 'Return the members of the user team',
+ accessType: 'READ',
+ accepts: [{
+ arg: 'userId',
+ type: 'string',
+ required: true
+ }],
+ returns: {
+ type: 'string',
+ root: true
+ },
+ http: {
+ path: `/myTeam`,
+ verb: 'GET'
+ }
+ });
+
+ Self.myTeam = async(userId, options) => {
+ const models = Self.app.models;
+ const myOptions = {};
+ const teamMembersId = [];
+
+ if (typeof options == 'object')
+ Object.assign(myOptions, options);
+
+ const worker = await models.Worker.findById(userId, {
+ include: {
+ relation: 'collegues'
+ }
+ }, myOptions);
+ const collegues = worker.collegues() || [];
+ for (let collegue of collegues)
+ teamMembersId.push(collegue.collegueFk);
+
+ if (teamMembersId.length == 0)
+ teamMembersId.push(userId);
+
+ return teamMembersId;
+ };
+};
+
diff --git a/modules/worker/back/methods/worker/specs/filter.spec.js b/modules/worker/back/methods/worker/specs/filter.spec.js
index 2eb3535763..27eb79cdb1 100644
--- a/modules/worker/back/methods/worker/specs/filter.spec.js
+++ b/modules/worker/back/methods/worker/specs/filter.spec.js
@@ -1,25 +1,69 @@
+const models = require('vn-loopback/server/server').models;
const app = require('vn-loopback/server/server');
describe('worker filter()', () => {
- it('should return 1 result filtering by id', async() => {
- let result = await app.models.Worker.filter({args: {filter: {}, search: 1}});
+ const ctx = beforeAll.getCtx();
- expect(result.length).toEqual(1);
- expect(result[0].id).toEqual(1);
+ it('should return 1 result filtering by id', async() => {
+ const tx = await models.Worker.beginTransaction({});
+
+ try {
+ const options = {transaction: tx};
+ const filter = {};
+ const args = {search: 1};
+ ctx.args = args;
+
+ let result = await app.models.Worker.filter(ctx, filter, options);
+
+ expect(result.length).toEqual(1);
+ expect(result[0].id).toEqual(1);
+
+ await tx.rollback();
+ } catch (e) {
+ await tx.rollback();
+ throw e;
+ }
});
it('should return 1 result filtering by string', async() => {
- let result = await app.models.Worker.filter({args: {filter: {}, search: 'administrativeNick'}});
+ const tx = await models.Worker.beginTransaction({});
- expect(result.length).toEqual(1);
- expect(result[0].id).toEqual(5);
+ try {
+ const options = {transaction: tx};
+ const filter = {};
+ const args = {search: 'administrativeNick'};
+ ctx.args = args;
+
+ let result = await app.models.Worker.filter(ctx, filter, options);
+
+ expect(result.length).toEqual(1);
+ expect(result[0].id).toEqual(5);
+
+ await tx.rollback();
+ } catch (e) {
+ await tx.rollback();
+ throw e;
+ }
});
- it('should return 2 results filtering by name', async() => {
- let result = await app.models.Worker.filter({args: {filter: {}, firstName: 'agency'}});
+ it('should return 2 result filtering by name', async() => {
+ const tx = await models.Worker.beginTransaction({});
- expect(result.length).toEqual(2);
- expect(result[0].nickname).toEqual('agencyNick');
- expect(result[1].nickname).toEqual('agencyBossNick');
+ try {
+ const options = {transaction: tx};
+ const filter = {};
+ const args = {firstName: 'agency'};
+ ctx.args = args;
+
+ let result = await app.models.Worker.filter(ctx, filter, options);
+
+ expect(result[0].nickname).toEqual('agencyNick');
+ expect(result[1].nickname).toEqual('agencyBossNick');
+
+ await tx.rollback();
+ } catch (e) {
+ await tx.rollback();
+ throw e;
+ }
});
});
diff --git a/modules/worker/back/models/worker.js b/modules/worker/back/models/worker.js
index 2e45b78da7..97e6a283c3 100644
--- a/modules/worker/back/models/worker.js
+++ b/modules/worker/back/models/worker.js
@@ -21,6 +21,7 @@ module.exports = Self => {
require('../methods/worker/isAuthorized')(Self);
require('../methods/worker/setPassword')(Self);
require('../methods/worker/getAvailablePda')(Self);
+ require('../methods/worker/myTeam')(Self);
Self.validateAsync('fi', tinIsValid, {
message: 'Invalid TIN'
diff --git a/modules/zone/back/models/zone-event.json b/modules/zone/back/models/zone-event.json
index 366bdec9d9..cf5045a8cb 100644
--- a/modules/zone/back/models/zone-event.json
+++ b/modules/zone/back/models/zone-event.json
@@ -42,6 +42,9 @@
"price": {
"type": "number"
},
+ "priceOptimum": {
+ "type": "number"
+ },
"bonus": {
"type": "number"
},
diff --git a/modules/zone/back/models/zone.json b/modules/zone/back/models/zone.json
index 141b287501..4f963568f1 100644
--- a/modules/zone/back/models/zone.json
+++ b/modules/zone/back/models/zone.json
@@ -28,6 +28,9 @@
"price": {
"type": "number"
},
+ "priceOptimum": {
+ "type": "number"
+ },
"bonus": {
"type": "number"
},
diff --git a/package.json b/package.json
index e4cbf1406b..72f8e2d1ba 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "salix-back",
- "version": "25.04.0",
+ "version": "25.06.0",
"author": "Verdnatura Levante SL",
"description": "Salix backend",
"license": "GPL-3.0",