Merge branch 'dev' into 6629-addressObservationBack2
gitea/salix/pipeline/pr-dev This commit looks good Details

This commit is contained in:
Robert Ferrús 2025-01-19 07:54:37 +00:00
commit de2f12bdb5
38 changed files with 555 additions and 185 deletions

View File

@ -1,3 +1,31 @@
# 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 # Version 24.52 - 2024-01-07
### Added 🆕 ### Added 🆕

View File

@ -27,38 +27,46 @@ module.exports = Self => {
}); });
Self.sendCheckingPresence = async(ctx, recipientId, message) => { Self.sendCheckingPresence = async(ctx, recipientId, message) => {
if (!recipientId) return false;
const models = Self.app.models;
const userId = ctx.req.accessToken.userId; 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 { try {
await Self.sendCheckingUserStatus(chat); const models = Self.app.models;
await Self.updateChat(chat, 'sent'); const sender = await models.VnUser.findById(userId, {fields: ['id']});
} catch (error) { const error = `Could not send message from user ${userId}`;
await Self.updateChat(chat, 'error', error);
}
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}`]);
}
}; };
}; };

View File

@ -4,7 +4,7 @@ USE `util`;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; /*!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','11391','43edb1f82e88dcc44eedc8501b93c1fac66d71e9','2025-01-14 07:32:09','11407');
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','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); INSERT INTO `versionLog` VALUES ('vn-database','10112','00-firstScript.sql','jenkins@10.0.2.69','2022-05-09 09:14:53',NULL,NULL);
@ -1078,6 +1078,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','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','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','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','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','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); 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 +1140,9 @@ 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','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','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','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','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','11400','00-firstScript.sql','jenkins@db-proxy1.servers.dc.verdnatura.es','2025-01-09 09:55:24',NULL,NULL);
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
@ -1515,6 +1519,7 @@ INSERT INTO `roleInherit` VALUES (378,101,15,19294);
INSERT INTO `roleInherit` VALUES (379,103,121,19294); INSERT INTO `roleInherit` VALUES (379,103,121,19294);
INSERT INTO `roleInherit` VALUES (381,119,123,19295); INSERT INTO `roleInherit` VALUES (381,119,123,19295);
INSERT INTO `roleInherit` VALUES (382,48,72,783); INSERT INTO `roleInherit` VALUES (382,48,72,783);
INSERT INTO `roleInherit` VALUES (383,114,111,19295);
INSERT INTO `userPassword` VALUES (1,7,1,0,2,1); INSERT INTO `userPassword` VALUES (1,7,1,0,2,1);
@ -2311,9 +2316,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 (939,'Machine','*','*','ALLOW','ROLE','productionBoss',10578);
INSERT INTO `ACL` VALUES (940,'ItemTypeLog','find','READ','ALLOW','ROLE','employee',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 (941,'Entry','buyLabel','READ','ALLOW','ROLE','employee',10578);
INSERT INTO `ACL` VALUES (942,'Cmr','filter','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','production',10578); INSERT INTO `ACL` VALUES (943,'Cmr','downloadZip','READ','ALLOW','ROLE','employee',19295);
INSERT INTO `ACL` VALUES (944,'Cmr','print','READ','ALLOW','ROLE','production',10578); 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 (945,'Collection','create','WRITE','ALLOW','ROLE','productionBoss',10578);
INSERT INTO `ACL` VALUES (946,'Collection','upsert','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); INSERT INTO `ACL` VALUES (947,'Collection','replaceById','WRITE','ALLOW','ROLE','productionBoss',10578);
@ -2327,7 +2332,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 (955,'RouteComplement','create','WRITE','ALLOW','ROLE','delivery',10578);
INSERT INTO `ACL` VALUES (956,'RouteComplement','deleteById','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 (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 (959,'WorkerRelative','updateAttributes','*','ALLOW','ROLE','hr',10578);
INSERT INTO `ACL` VALUES (960,'WorkerRelative','crud','WRITE','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); INSERT INTO `ACL` VALUES (961,'WorkerRelative','findById','*','ALLOW','ROLE','hr',10578);
@ -2383,6 +2387,8 @@ 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 (1011,'SiiTypeInvoiceIn','find','READ','ALLOW','ROLE','salesPerson',10578);
INSERT INTO `ACL` VALUES (1012,'OsrmConfig','optimize','READ','ALLOW','ROLE','employee',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 (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 `fieldAcl` VALUES (1,'Client','name','update','employee'); INSERT INTO `fieldAcl` VALUES (1,'Client','name','update','employee');
INSERT INTO `fieldAcl` VALUES (2,'Client','contact','update','employee'); INSERT INTO `fieldAcl` VALUES (2,'Client','contact','update','employee');
@ -2725,7 +2731,7 @@ INSERT INTO `department` VALUES (124,NULL,'CONTROL INTERNO',122,123,NULL,72,0,0,
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 (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 (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 (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 (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 (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',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 (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 (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 (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);
@ -2740,12 +2746,12 @@ INSERT INTO `department` VALUES (146,NULL,'VERDNACOLOMBIA',3,4,NULL,72,0,0,2,0,2
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 (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 (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 (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 (150,'spainTeamLevanteIslands','EQUIPO ESPAÑA LEVANTE',77,78,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',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 (151,'spainTeamNorthwest','EQUIPO ESPAÑA NOROESTE',79,80,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',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 (152,'spainTeamNortheast','EQUIPO ESPAÑA NORESTE',81,82,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',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 (153,'spainTeamSouth','EQUIPO ESPAÑA SUR',83,84,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',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 (154,'spainTeamCenter','EQUIPO ESPAÑA CENTRO',85,86,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',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 (155,'spainTeamVip','EQUIPO ESPAÑA VIP',87,88,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 `docuware` VALUES (1,'deliveryNote','Albaranes cliente','find','find','N__ALBAR_N',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); INSERT INTO `docuware` VALUES (2,'deliveryNote','Albaranes cliente','store','Archivar','N__ALBAR_N',NULL);
@ -3046,6 +3052,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 (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 (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 (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 (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.'); 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.');

View File

@ -1494,6 +1494,10 @@ 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 ('','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 ('','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','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','');
/*!40000 ALTER TABLE `tables_priv` ENABLE KEYS */; /*!40000 ALTER TABLE `tables_priv` ENABLE KEYS */;
/*!40000 ALTER TABLE `columns_priv` DISABLE KEYS */; /*!40000 ALTER TABLE `columns_priv` DISABLE KEYS */;

View File

@ -6249,19 +6249,27 @@ BEGIN
* @param vDateFrom Fecha desde * @param vDateFrom Fecha desde
* @param vDateTo Fecha hasta * @param vDateTo Fecha hasta
*/ */
IF vDateFrom IS NULL THEN DECLARE vDaysInYear INT;
SET vDateFrom = util.VN_CURDATE() - INTERVAL WEEKDAY(util.VN_CURDATE()) DAY; 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; END IF;
IF vDateTo IS NULL THEN -- Obtiene el primer día de la semana de esa fecha
SET vDateTo = vDateFrom + INTERVAL 6 DAY; SET vDateFrom = DATE_SUB(vDateFrom, INTERVAL ((WEEKDAY(vDateFrom) + 1) % 7) DAY);
END IF;
-- 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); CALL cache.last_buy_refresh(FALSE);
REPLACE bs.waste REPLACE bs.waste
SELECT YEAR(t.shipped), SELECT YEARWEEK(t.shipped, 6) DIV 100,
WEEK(t.shipped, 4), WEEK(t.shipped, 6),
it.workerFk, it.workerFk,
it.id, it.id,
s.itemFk, s.itemFk,
@ -6307,9 +6315,9 @@ BEGIN
JOIN cache.last_buy lb ON lb.item_id = i.id JOIN cache.last_buy lb ON lb.item_id = i.id
AND lb.warehouse_id = w.id AND lb.warehouse_id = w.id
JOIN vn.buy b ON b.id = lb.buy_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 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 ;; END ;;
DELIMITER ; DELIMITER ;
/*!50003 SET sql_mode = @saved_sql_mode */ ; /*!50003 SET sql_mode = @saved_sql_mode */ ;
@ -13807,7 +13815,7 @@ BEGIN
) INTO vHas0Amount; ) INTO vHas0Amount;
IF vHas0Amount THEN IF vHas0Amount THEN
CALL util.throw('Hay líneas vacías. Por favor, elimínelas'); CALL util.throw('orderLinesWithZero');
END IF; END IF;
START TRANSACTION; START TRANSACTION;
@ -28922,6 +28930,7 @@ CREATE TABLE `country` (
`isSocialNameUnique` tinyint(1) NOT NULL DEFAULT 1, `isSocialNameUnique` tinyint(1) NOT NULL DEFAULT 1,
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
UNIQUE KEY `country_unique` (`code`), UNIQUE KEY `country_unique` (`code`),
UNIQUE KEY `country_unique_name` (`name`),
KEY `currency_id_fk_idx` (`currencyFk`), KEY `currency_id_fk_idx` (`currencyFk`),
KEY `country_Ix4` (`name`), KEY `country_Ix4` (`name`),
KEY `continent_id_fk_idx` (`continentFk`), KEY `continent_id_fk_idx` (`continentFk`),
@ -31971,6 +31980,7 @@ CREATE TABLE `item` (
`value12` varchar(50) DEFAULT NULL, `value12` varchar(50) DEFAULT NULL,
`tag13` varchar(20) DEFAULT NULL, `tag13` varchar(20) DEFAULT NULL,
`value13` varchar(50) 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`), PRIMARY KEY (`id`),
UNIQUE KEY `item_supplyResponseFk_idx` (`supplyResponseFk`), UNIQUE KEY `item_supplyResponseFk_idx` (`supplyResponseFk`),
KEY `Color` (`inkFk`), KEY `Color` (`inkFk`),
@ -68661,10 +68671,11 @@ BEGIN
TRUE, TRUE,
sc.userFk, sc.userFk,
s.id s.id
FROM vn.sectorCollection sc FROM sectorCollection sc
JOIN vn.sectorCollectionSaleGroup scsg ON scsg.sectorCollectionFk = sc.id JOIN sectorCollectionSaleGroup scsg ON scsg.sectorCollectionFk = sc.id
JOIN vn.saleGroupDetail sgd ON sgd.saleGroupFk = scsg.saleGroupFk JOIN saleGroupDetail sgd ON sgd.saleGroupFk = scsg.saleGroupFk
JOIN vn.state s ON s.code = 'OK PREVIOUS' JOIN state s ON s.code = 'OK PREVIOUS'
JOIN itemShelvingSale iss ON iss.saleFk = sgd.saleFk
WHERE sc.id = vSectorCollectionFk; WHERE sc.id = vSectorCollectionFk;
END ;; END ;;
DELIMITER ; DELIMITER ;
@ -90882,4 +90893,4 @@ USE `vn2008`;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
-- Dump completed on 2025-01-07 6:51:38 -- Dump completed on 2025-01-14 6:39:04

View File

@ -11499,4 +11499,4 @@ USE `vn2008`;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
-- Dump completed on 2025-01-07 6:51:57 -- Dump completed on 2025-01-14 6:39:25

View File

@ -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 VALUES
(1, 'EUR', 'Euro', 1), (1, 'EUR', 'Euro', 1, FALSE),
(2, 'USD', 'Dollar USA', 1.4), (2, 'USD', 'Dollar USA', 1.4, TRUE),
(3, 'GBP', 'Libra', 1), (3, 'GBP', 'Libra', 1, TRUE),
(4, 'JPY', 'Yen Japones', 1), (4, 'JPY', 'Yen Japones', 1, FALSE),
(5, 'CNY', 'Yuan Chino', 1.2); (5, 'CNY', 'Yuan Chino', 1.2, TRUE);
INSERT INTO `vn`.`country`(`id`, `name`, `isUeeMember`, `code`, `currencyFk`, `ibanLength`, `continentFk`, `hasDailyInvoice`, `CEE`) INSERT INTO `vn`.`country`(`id`, `name`, `isUeeMember`, `code`, `currencyFk`, `ibanLength`, `continentFk`, `hasDailyInvoice`, `CEE`)
VALUES VALUES
@ -694,22 +694,22 @@ INSERT INTO `vn`.`invoiceOutExpense`(`id`, `invoiceOutFk`, `amount`, `expenseFk`
(6, 4, 8.07, 2000000000, util.VN_CURDATE()), (6, 4, 8.07, 2000000000, util.VN_CURDATE()),
(7, 5, 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`) INSERT INTO `vn`.`zone`
VALUES (`id`, `name`, `hour`, `agencyModeFk`, `travelingDays`, `price`, `bonus`, `itemMaxSize`, `priceOptimum`)
(1, 'Zone pickup A', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 1, 0, 1, 0, 100), VALUES
(2, 'Zone pickup B', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 1, 0, 1, 0, 100), (1, 'Zone pickup A', 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), (2, 'Zone pickup B', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 1, 0, 1, 0, 100, 1),
(4, 'Zone 247 B', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 7, 1, 2, 0, 100), (3, 'Zone 247 A', 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), (4, 'Zone 247 B', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 7, 1, 2, 0, 100, 1),
(6, 'Zone expensive B', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 8, 1, 1000, 0, 100), (5, 'Zone expensive A', 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), (6, 'Zone expensive B', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 8, 1, 1000, 0, 100, 500),
(8, 'Zone others', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 10, 0, 1, 0, 100), (7, 'Zone refund', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 23, 0, 1, 0, 100, 0.5),
(9, 'Zone superMan', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 2, 0, 1, 0, 100), (8, 'Zone others', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 10, 0, 1, 0, 100, 0.5),
(10, 'Zone teleportation', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 3, 0, 1, 0, 100), (9, 'Zone superMan', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 2, 0, 1, 0, 100, 0.5),
(11, 'Zone pickup C', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 1, 0, 1, 0, 100), (10, 'Zone teleportation', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 3, 0, 1, 0, 100, 0.5),
(12, 'Zone entanglement', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 4, 0, 1, 0, 100), (11, 'Zone pickup C', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 1, 0, 1, 0, 100, 0.5),
(13, 'Zone quantum break', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 5, 0, 1, 0, 100); (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`) INSERT INTO `vn`.`zoneWarehouse` (`id`, `zoneFk`, `warehouseFk`)
VALUES VALUES

View File

@ -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 ;

View File

@ -231,7 +231,19 @@ BEGIN
SELECT tcc.warehouseFK, SELECT tcc.warehouseFK,
tcc.itemFk, tcc.itemFk,
c2.id, 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 FROM tmp.ticketComponentCalculate tcc
JOIN item i ON i.id = tcc.itemFk JOIN item i ON i.id = tcc.itemFk
JOIN tmp.zoneOption zo ON zo.zoneFk = vZoneFk JOIN tmp.zoneOption zo ON zo.zoneFk = vZoneFk
@ -239,6 +251,7 @@ BEGIN
JOIN agencyMode am ON am.id = z.agencyModeFk JOIN agencyMode am ON am.id = z.agencyModeFk
JOIN vn.volumeConfig vc JOIN vn.volumeConfig vc
JOIN vn.component c2 ON c2.code = 'delivery' JOIN vn.component c2 ON c2.code = 'delivery'
JOIN `client` c on c.id = vClientFk
LEFT JOIN itemCost ic ON ic.warehouseFk = tcc.warehouseFk LEFT JOIN itemCost ic ON ic.warehouseFk = tcc.warehouseFk
AND ic.itemFk = tcc.itemFk AND ic.itemFk = tcc.itemFk
HAVING cost <> 0; HAVING cost <> 0;

View File

@ -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 ;

View File

@ -16,10 +16,11 @@ BEGIN
TRUE, TRUE,
sc.userFk, sc.userFk,
s.id s.id
FROM vn.sectorCollection sc FROM sectorCollection sc
JOIN vn.sectorCollectionSaleGroup scsg ON scsg.sectorCollectionFk = sc.id JOIN sectorCollectionSaleGroup scsg ON scsg.sectorCollectionFk = sc.id
JOIN vn.saleGroupDetail sgd ON sgd.saleGroupFk = scsg.saleGroupFk JOIN saleGroupDetail sgd ON sgd.saleGroupFk = scsg.saleGroupFk
JOIN vn.state s ON s.code = 'OK PREVIOUS' JOIN state s ON s.code = 'OK PREVIOUS'
JOIN itemShelvingSale iss ON iss.saleFk = sgd.saleFk
WHERE sc.id = vSectorCollectionFk; WHERE sc.id = vSectorCollectionFk;
END$$ END$$
DELIMITER ; DELIMITER ;

View File

@ -9,7 +9,7 @@ BEGIN
* @return tmp.zoneOption(zoneFk, hour, travelingDays, price, bonus, specificity) The computed options * @return tmp.zoneOption(zoneFk, hour, travelingDays, price, bonus, specificity) The computed options
*/ */
DECLARE vHour TIME DEFAULT TIME(util.VN_NOW()); DECLARE vHour TIME DEFAULT TIME(util.VN_NOW());
DROP TEMPORARY TABLE IF EXISTS tLandings; DROP TEMPORARY TABLE IF EXISTS tLandings;
CREATE TEMPORARY TABLE tLandings CREATE TEMPORARY TABLE tLandings
(INDEX (eventFk)) (INDEX (eventFk))
@ -30,6 +30,7 @@ BEGIN
TIME(IFNULL(e.`hour`, z.`hour`)) `hour`, TIME(IFNULL(e.`hour`, z.`hour`)) `hour`,
l.travelingDays, l.travelingDays,
IFNULL(e.price, z.price) price, IFNULL(e.price, z.price) price,
IFNULL(e.priceOptimum, z.priceOptimum) priceOptimum,
IFNULL(e.bonus, z.bonus) bonus, IFNULL(e.bonus, z.bonus) bonus,
l.landed, l.landed,
vShipped shipped vShipped shipped

View File

@ -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)

View File

@ -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)

View File

@ -0,0 +1,2 @@
UPDATE `vn`.`zone`
SET `priceOptimum` = `price`;

View File

@ -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';

View File

@ -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';

View File

@ -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';

View File

@ -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';

View File

@ -0,0 +1,3 @@
UPDATE `vn`.`currency`
SET `hasToDownloadRate` = TRUE
WHERE `code` IN ('USD', 'CNY', 'GBP');

View File

@ -0,0 +1,2 @@
INSERT INTO salix.ACL (model,property,accessType,permission,principalType,principalId)
VALUES ('VnUser','adminUser','WRITE','ALLOW','ROLE','sysadmin');

View File

@ -0,0 +1,2 @@
RENAME TABLE bi.f_tvc TO bi.f_tvc__;
ALTER TABLE bi.f_tvc__ COMMENT='@deprecated 2025-01-15';

View File

@ -211,6 +211,7 @@
"Name should be uppercase": "Name should be uppercase", "Name should be uppercase": "Name should be uppercase",
"You cannot update these fields": "You cannot update these fields", "You cannot update these fields": "You cannot update these fields",
"CountryFK cannot be empty": "Country cannot be empty", "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 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", "You already have the mailAlias": "You already have the mailAlias",
"This machine is already in use.": "This machine is already in use.", "This machine is already in use.": "This machine is already in use.",
@ -251,4 +252,4 @@
"Price cannot be blank": "Price cannot be blank", "Price cannot be blank": "Price cannot be blank",
"There are tickets to be invoiced": "There are tickets to be invoiced", "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"
} }

View File

@ -339,7 +339,7 @@
"Incorrect pin": "Pin incorrecto.", "Incorrect pin": "Pin incorrecto.",
"You already have the mailAlias": "Ya tienes este alias de correo", "You already have the mailAlias": "Ya tienes este alias de correo",
"The alias cant be modified": "Este alias de correo no puede ser modificado", "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 warehouse has not dms": "El Almacén no acepta documentos",
"This ticket already has a cmr saved": "Este ticket ya tiene un cmr guardado", "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", "Name should be uppercase": "El nombre debe ir en mayúscula",

View File

@ -339,7 +339,7 @@
"Incorrect pin": "Pin incorrect.", "Incorrect pin": "Pin incorrect.",
"You already have the mailAlias": "Vous avez déjà cet alias de courrier", "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é", "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 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é", "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", "Name should be uppercase": "Le nom doit être en majuscules",

View File

@ -339,7 +339,7 @@
"Incorrect pin": "PIN incorreto.", "Incorrect pin": "PIN incorreto.",
"You already have the mailAlias": "Você já tem o alias de e-mail", "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", "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 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", "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", "Name should be uppercase": "O nome deve estar em maiúsculas",

View File

@ -52,6 +52,14 @@ module.exports = function(Self) {
arg: 'customsAgentFk', arg: 'customsAgentFk',
type: 'number' type: 'number'
}, },
{
arg: 'longitude',
type: 'number'
},
{
arg: 'latitude',
type: 'number'
},
{ {
arg: 'isActive', arg: 'isActive',
type: 'boolean' type: 'boolean'

View File

@ -119,6 +119,16 @@ module.exports = Self => {
arg: 'invoiceAmount', arg: 'invoiceAmount',
type: 'number', type: 'number',
description: `The invoice amount` description: `The invoice amount`
},
{
arg: 'initialTemperature',
type: 'number',
description: 'Initial temperature value'
},
{
arg: 'finalTemperature',
type: 'number',
description: 'Final temperature value'
} }
], ],
returns: { returns: {
@ -170,6 +180,10 @@ module.exports = Self => {
case 'invoiceInFk': case 'invoiceInFk':
param = `e.${param}`; param = `e.${param}`;
return {[param]: value}; return {[param]: value};
case 'initialTemperature':
return {'e.initialTemperature': {lte: value}};
case 'finalTemperature':
return {'e.finalTemperature': {gte: value}};
} }
}); });
filter = mergeFilters(ctx.args.filter, {where}); filter = mergeFilters(ctx.args.filter, {where});
@ -204,6 +218,8 @@ module.exports = Self => {
e.gestDocFk, e.gestDocFk,
e.invoiceInFk, e.invoiceInFk,
e.invoiceAmount, e.invoiceAmount,
e.initialTemperature,
e.finalTemperature,
t.landed, t.landed,
s.name supplierName, s.name supplierName,
s.nickname supplierAlias, s.nickname supplierAlias,

View File

@ -68,6 +68,12 @@
}, },
"invoiceAmount": { "invoiceAmount": {
"type": "number" "type": "number"
},
"initialTemperature": {
"type": "number"
},
"finalTemperature": {
"type": "number"
} }
}, },
"relations": { "relations": {

View File

@ -13,66 +13,114 @@ module.exports = Self => {
} }
}); });
Self.exchangeRateUpdate = async() => { Self.exchangeRateUpdate = async(options = {}) => {
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 models = Self.app.models; 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)) { for (const rateCube of Array.from(cube.childNodes)) {
if (rateCube.nodeType === doc.ELEMENT_NODE) { if (rateCube.nodeType === doc.ELEMENT_NODE) {
const currencyCode = rateCube.getAttribute('currency'); const currencyCode = rateCube.getAttribute('currency');
const rate = rateCube.getAttribute('rate'); const rate = rateCube.getAttribute('rate');
if (['USD', 'CNY', 'GBP'].includes(currencyCode)) { const currency = currencies.find(c => c.code === currencyCode);
const currency = await models.Currency.findOne({where: {code: currencyCode}}); if (currency) {
if (!currency) throw new UserError(`Currency not found for code: ${currencyCode}`);
const existingRate = await models.ReferenceRate.findOne({ const existingRate = await models.ReferenceRate.findOne({
where: {currencyFk: currency.id, dated: xmlDate} where: {currencyFk: currency.id, dated: xmlDateWithoutTime}
}); }, myOptions);
if (existingRate) { if (existingRate) {
if (existingRate.value !== rate) if (existingRate.value !== rate)
await existingRate.updateAttributes({value: rate}); await existingRate.updateAttributes({value: rate}, myOptions);
} else { } else {
await models.ReferenceRate.create({ await models.ReferenceRate.create({
currencyFk: currency.id, currencyFk: currency.id,
dated: xmlDate, dated: xmlDateWithoutTime,
value: rate value: rate
}); }, myOptions);
}
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}
);
}
} }
} }
} }
} }
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);
}
}
}; };

View File

@ -1,52 +1,190 @@
describe('exchangeRateUpdate functionality', function() { describe('exchangeRateUpdate functionality', function() {
const axios = require('axios'); const axios = require('axios');
const models = require('vn-loopback/server/server').models; const models = require('vn-loopback/server/server').models;
let tx; let options;
beforeEach(function() { function formatYmd(d) {
spyOn(axios, 'get').and.returnValue(Promise.resolve({ const mm = (d.getMonth() + 1).toString().padStart(2, '0');
data: `<Cube> const dd = d.getDate().toString().padStart(2, '0');
<Cube time='2024-04-12'> return `${d.getFullYear()}-${mm}-${dd}`;
<Cube currency='USD' rate='1.1'/> }
<Cube currency='CNY' rate='1.2'/>
</Cube> afterEach(async() => {
</Cube>` 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 = `<Cube>
<Cube time='${formatYmd(d1)}'>
<Cube currency='USD' rate='1.1'/>
<Cube currency='CNY' rate='1.2'/>
</Cube>
<Cube time='${formatYmd(d4)}'>
<Cube currency='USD' rate='1.3'/>
</Cube>
</Cube>`;
axios.get.and.returnValue(Promise.resolve({data: xml}));
spyOn(models.ReferenceRate, 'findOne').and.returnValue(Promise.resolve(null)); spyOn(models.ReferenceRate, 'findOne').and.returnValue(Promise.resolve(null));
spyOn(models.ReferenceRate, 'create').and.returnValue(Promise.resolve()); spyOn(models.ReferenceRate, 'create').and.returnValue(Promise.resolve());
await models.InvoiceIn.exchangeRateUpdate(options);
await models.InvoiceIn.exchangeRateUpdate(); expect(models.ReferenceRate.create).toHaveBeenCalledTimes(3);
expect(models.ReferenceRate.create).toHaveBeenCalledTimes(2);
}); });
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({})); axios.get.and.returnValue(Promise.resolve({}));
spyOn(models.ReferenceRate, 'create'); spyOn(models.ReferenceRate, 'create');
let e;
let thrownError = null;
try { try {
await models.InvoiceIn.exchangeRateUpdate(); await models.InvoiceIn.exchangeRateUpdate(options);
} catch (error) { } catch (err) {
thrownError = error; 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'))); axios.get.and.returnValue(Promise.reject(new Error('Network error')));
let error; let e;
try { try {
await models.InvoiceIn.exchangeRateUpdate(); await models.InvoiceIn.exchangeRateUpdate(options);
} catch (e) { } catch (err) {
error = e; e = err;
} }
expect(error).toBeDefined(); expect(e).toBeDefined();
expect(error.message).toBe('Network error'); 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 = `<Cube>
<Cube time='${formatYmd(existingRate.dated)}'>
<Cube currency='${currency.code}' rate='2.22'/>
</Cube>
</Cube>`;
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 = `<Cube>
<Cube time='${formatYmd(existingRate.dated)}'>
<Cube currency='${currency.code}' rate='${oldValue}'/>
</Cube>
</Cube>`;
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 = `<Cube>
<Cube time='${formatYmd(d1)}'>
<Cube currency='${currency.code}' rate='1.0'/>
</Cube>
<Cube time='${formatYmd(d4)}'>
<Cube currency='${currency.code}' rate='2.0'/>
</Cube>
</Cube>`;
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 = `<Cube>
<Cube time='${formatYmd(day1)}'>
<Cube currency='${currency.code}' rate='1.1'/>
</Cube>
<Cube time='${formatYmd(day2)}'>
<Cube currency='${currency.code}' rate='2.2'/>
</Cube>
</Cube>`;
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');
}); });
}); });

View File

@ -49,12 +49,6 @@ module.exports = Self => {
} }
try { 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; const vIsAllInvoiceable = false;
await Self.rawSql('CALL ticketPackaging_add(?, ?, ?, ?)', [ await Self.rawSql('CALL ticketPackaging_add(?, ?, ?, ?)', [
clientId, clientId,

View File

@ -1,4 +1,5 @@
const models = require('vn-loopback/server/server').models; const models = require('vn-loopback/server/server').models;
const LoopBackContext = require('loopback-context');
describe('InvoiceOut clientsToInvoice()', () => { describe('InvoiceOut clientsToInvoice()', () => {
const userId = 1; const userId = 1;
@ -20,6 +21,21 @@ describe('InvoiceOut clientsToInvoice()', () => {
headers: {origin: 'http://localhost'} headers: {origin: 'http://localhost'}
}; };
const ctx = {req: activeCtx}; 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() => { it('should return a list of clients to invoice', async() => {
spyOn(models.InvoiceOut, 'rawSql').and.callFake(query => { spyOn(models.InvoiceOut, 'rawSql').and.callFake(query => {
@ -37,24 +53,14 @@ describe('InvoiceOut clientsToInvoice()', () => {
} }
}); });
const tx = await models.InvoiceOut.beginTransaction({}); const addresses = await models.InvoiceOut.clientsToInvoice(
const options = {transaction: tx}; ctx, clientId, invoiceDate, maxShipped, companyFk, options);
try { expect(addresses.length).toBeGreaterThan(0);
const addresses = await models.InvoiceOut.clientsToInvoice( expect(addresses[0].clientId).toBe(clientId);
ctx, clientId, invoiceDate, maxShipped, companyFk, options); expect(addresses[0].clientName).toBe('Test Client');
expect(addresses[0].id).toBe(1);
expect(addresses.length).toBeGreaterThan(0); expect(addresses[0].nickname).toBe('Address 1');
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;
}
}); });
it('should handle errors and rollback transaction', async() => { it('should handle errors and rollback transaction', async() => {
@ -62,14 +68,20 @@ describe('InvoiceOut clientsToInvoice()', () => {
return Promise.reject(new Error('Test Error')); return Promise.reject(new Error('Test Error'));
}); });
const tx = await models.InvoiceOut.beginTransaction({});
const options = {transaction: tx};
try { try {
await models.InvoiceOut.clientsToInvoice(ctx, clientId, invoiceDate, maxShipped, companyFk, options); await models.InvoiceOut.clientsToInvoice(ctx, clientId, invoiceDate, maxShipped, companyFk, options);
} catch (e) { } catch (e) {
expect(e.message).toBe('Test Error'); 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();
});
}); });

View File

@ -30,7 +30,7 @@ module.exports = Self => {
Object.assign(myOptions, options); Object.assign(myOptions, options);
const query = const query =
`SELECT DISTINCT u.id, u.nickname `SELECT DISTINCT u.id, u.nickname, w.firstName, w.lastName
FROM itemType it FROM itemType it
JOIN worker w ON w.id = it.workerFk JOIN worker w ON w.id = it.workerFk
JOIN account.user u ON u.id = w.id`; JOIN account.user u ON u.id = w.id`;

View File

@ -41,7 +41,9 @@ module.exports = Self => {
* b.stickers)/1000000) AS DECIMAL(10,2)) m3, * b.stickers)/1000000) AS DECIMAL(10,2)) m3,
TRUNCATE(SUM(b.stickers)/(COUNT( b.id) / COUNT( DISTINCT b.id)),0) hb, 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.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 FROM vn.travel t
LEFT JOIN vn.entry e ON t.id = e.travelFk LEFT JOIN vn.entry e ON t.id = e.travelFk
LEFT JOIN vn.buy b ON b.entryFk = e.id LEFT JOIN vn.buy b ON b.entryFk = e.id

View File

@ -20,6 +20,9 @@
}, },
"ratio": { "ratio": {
"type": "number" "type": "number"
},
"hasToDownloadRate": {
"type": "boolean"
} }
}, },
"acls": [ "acls": [

View File

@ -42,6 +42,9 @@
"price": { "price": {
"type": "number" "type": "number"
}, },
"priceOptimum": {
"type": "number"
},
"bonus": { "bonus": {
"type": "number" "type": "number"
}, },

View File

@ -28,6 +28,9 @@
"price": { "price": {
"type": "number" "type": "number"
}, },
"priceOptimum": {
"type": "number"
},
"bonus": { "bonus": {
"type": "number" "type": "number"
}, },