Compare commits

..

68 Commits

Author SHA1 Message Date
Alex Moreno 9d289fa11e build: init version
gitea/salix/pipeline/head This commit looks good Details
2025-01-21 11:57:35 +01:00
Alex Moreno ded035285b Merge pull request '8448-devToTest' (!3373) from 8448-devToTest into test
gitea/salix/pipeline/head This commit looks good Details
Reviewed-on: #3373
Reviewed-by: Carlos Satorres <carlossa@verdnatura.es>
2025-01-21 10:00:49 +00:00
Alex Moreno 05b383ecb0 test: refs #8448 fix e2e
gitea/salix/pipeline/pr-test This commit looks good Details
2025-01-21 10:57:40 +01:00
Sergio De la torre 6f73758cad Merge pull request '7569-sendEmailOrderTicket' (!3350) from 7569-sendEmailOrderTicket into dev
gitea/salix/pipeline/head This commit looks good Details
gitea/salix/pipeline/pr-test This commit looks good Details
Reviewed-on: #3350
Reviewed-by: Javi Gallego <jgallego@verdnatura.es>
2025-01-21 06:29:28 +00:00
Sergio De la torre c50ff6a43a feat: refs #7569 refs#7569 sendEmailNotification
gitea/salix/pipeline/pr-dev This commit looks good Details
2025-01-21 07:05:42 +01:00
Sergio De la torre eee73f001d Merge branch 'dev' of https: refs #7569//gitea.verdnatura.es/verdnatura/salix into 7569-sendEmailOrderTicket
gitea/salix/pipeline/pr-dev This commit looks good Details
2025-01-21 07:00:02 +01:00
Sergio De la torre 7f17cd59e7 Merge branch 'dev' of https: refs #7569//gitea.verdnatura.es/verdnatura/salix into 7569-sendEmailOrderTicket 2025-01-21 06:58:15 +01:00
Sergio De la torre ef68884fe0 feat: refs #7569 refs#7569 sendEmailNotification
gitea/salix/pipeline/pr-dev There was a failure building this commit Details
2025-01-20 16:27:35 +01:00
Sergio De la torre b5e27707a7 feat: refs #7569 refs#7569 sendEmailNotification
gitea/salix/pipeline/pr-dev There was a failure building this commit Details
2025-01-20 12:36:31 +01:00
Sergio De la torre 0340612645 feat: refs #7569 refs#7569 sendEmailNotification
gitea/salix/pipeline/pr-dev There was a failure building this commit Details
2025-01-20 12:35:55 +01:00
Guillermo Bonet aa62f1d483 Merge branch 'test' into dev
gitea/salix/pipeline/head This commit looks good Details
2025-01-20 08:10:38 +01:00
Guillermo Bonet 86a2b1de1e Merge branch 'master' into test
gitea/salix/pipeline/head This commit looks good Details
2025-01-20 08:10:29 +01:00
Guillermo Bonet 9584ffcf5b feat: refs #7531 Added landed index
gitea/salix/pipeline/head This commit looks good Details
2025-01-20 08:10:12 +01:00
Guillermo Bonet 04180bf8da Merge branch 'test' into dev
gitea/salix/pipeline/head This commit looks good Details
2025-01-20 07:52:04 +01:00
Guillermo Bonet 5998002420 Merge branch 'master' into test
gitea/salix/pipeline/head This commit looks good Details
2025-01-20 07:51:45 +01:00
Guillermo Bonet fff6979921 Merge pull request 'feat: refs #7531 Added address_hasDelivery' (!3361) from 7531-addressHasDelivery into master
gitea/salix/pipeline/head This commit looks good Details
Reviewed-on: #3361
Reviewed-by: Javi Gallego <jgallego@verdnatura.es>
2025-01-20 06:51:18 +00:00
Guillermo Bonet 7a5ed0ff23 Merge branch 'master' into 7531-addressHasDelivery
gitea/salix/pipeline/pr-master This commit looks good Details
2025-01-20 06:49:42 +00:00
Guillermo Bonet 934507569e feat: refs #7531 Added comment
gitea/salix/pipeline/pr-master This commit looks good Details
2025-01-20 07:48:43 +01:00
Guillermo Bonet e6abb1d759 feat: refs #7531 Minor change
gitea/salix/pipeline/pr-master This commit looks good Details
2025-01-20 07:41:41 +01:00
Guillermo Bonet 044a22bc3e feat: refs #7531 Deleted address_hasDelivery
gitea/salix/pipeline/pr-master This commit looks good Details
2025-01-20 07:13:04 +01:00
PAU ROVIRA ROSALENY 5ef1d615a7 Merge pull request 'feat: #8258 added uppercase validation on supplier create' (!3368) from 8258-uppercaseInputs into dev
gitea/salix/pipeline/head This commit looks good Details
Reviewed-on: #3368
Reviewed-by: Javi Gallego <jgallego@verdnatura.es>
2025-01-20 06:01:20 +00:00
PAU ROVIRA ROSALENY 1cdeadb59d feat: refs #8258 added uppercase validation on supplier create
gitea/salix/pipeline/pr-dev This commit looks good Details
2025-01-17 13:20:45 +01:00
Guillermo Bonet e636d43f04 feat: refs #7531 Added address_hasDelivery
gitea/salix/pipeline/pr-master This commit looks good Details
2025-01-17 09:42:15 +01:00
Guillermo Bonet a666cfa4cd feat: refs #7531 Added address_hasDelivery
gitea/salix/pipeline/pr-master This commit looks good Details
2025-01-17 09:40:07 +01:00
Javi Gallego d4b7d54052 Merge pull request '8298-zonePriceOptimum' (!3345) from 8298-zonePriceOptimum into dev
gitea/salix/pipeline/head This commit looks good Details
Reviewed-on: #3345
Reviewed-by: Pako Natek <pako@verdnatura.es>
Reviewed-by: Alex Moreno <alexm@verdnatura.es>
2025-01-17 08:30:44 +00:00
Guillermo Bonet 1aa1fbda6c feat: refs #7531 Added address_hasDelivery
gitea/salix/pipeline/pr-master This commit looks good Details
2025-01-17 08:10:26 +01:00
Guillermo Bonet 69b78b6bf1 feat: refs #7531 Added address_hasDelivery
gitea/salix/pipeline/pr-master There was a failure building this commit Details
2025-01-16 15:04:21 +01:00
Javi Gallego 125b7730e7 feat: refs #8298 update price calculation logic and add packagesDiscountFactor column to client table
gitea/salix/pipeline/pr-dev This commit looks good Details
2025-01-16 12:56:04 +01:00
Guillermo Bonet 4d98c340d2 feat: refs #7882 Added coords to create a address
gitea/salix/pipeline/head This commit looks good Details
2025-01-16 09:34:18 +01:00
Javi Gallego b8dbaec46c Merge pull request 'test: refs #8361 enhance exchangeRateUpdate specs with additional scenarios' (!3340) from 8361-exchangeRateUpdateWithFestiveDays into dev
gitea/salix/pipeline/head This commit looks good Details
Reviewed-on: #3340
Reviewed-by: Alex Moreno <alexm@verdnatura.es>
Reviewed-by: Carlos Andrés <carlosap@verdnatura.es>
2025-01-16 08:10:09 +00:00
Robert Ferrús 03c974db12 Merge pull request 'feat: refs #257275 defaulterFilter' (!3356) from hotFixDefaulterFilter into master
gitea/salix/pipeline/head This commit looks good Details
Reviewed-on: #3356
Reviewed-by: Carlos Andrés <carlosap@verdnatura.es>
2025-01-16 07:00:48 +00:00
Javi Gallego 69f1e76307 Merge pull request 'feat: refs #8381 add initial and final temperature fields to entry model and queries' (!3354) from 8381-entryTemperature into dev
gitea/salix/pipeline/head This commit looks good Details
Reviewed-on: #3354
Reviewed-by: Alex Moreno <alexm@verdnatura.es>
2025-01-16 06:56:42 +00:00
Robert Ferrús 0e8b4d92bf Merge branch 'master' into hotFixDefaulterFilter
gitea/salix/pipeline/pr-master This commit looks good Details
2025-01-16 06:53:00 +00:00
Carlos Andrés c24b008567 Actualizar modules/travel/back/methods/travel/filter.js
gitea/salix/pipeline/head This commit looks good Details
2025-01-15 16:34:44 +00:00
Ivan Mas 8da1d866e3 Merge pull request 'refactor: refs #8378 deprecate bi.f_tvc' (!3365) from 8378-deprecateBi.f_tvc into dev
gitea/salix/pipeline/head This commit looks good Details
Reviewed-on: #3365
Reviewed-by: Javi Gallego <jgallego@verdnatura.es>
2025-01-15 15:12:08 +00:00
Ivan Mas 416e6c81f1 refactor: refs #8378 deprecate bi.f_tvc
gitea/salix/pipeline/pr-dev This commit looks good Details
2025-01-15 15:22:48 +01:00
Guillermo Bonet c2ca9cfbe5 feat: refs #7531 Added address_hasDelivery
gitea/salix/pipeline/pr-master This commit looks good Details
2025-01-15 12:26:16 +01:00
Jon Elias d0df1c1f42 Merge pull request '#8247: Added new acl for VnUser model' (!3358) from 8247-CreateNewAcl into dev
gitea/salix/pipeline/head This commit looks good Details
Reviewed-on: #3358
Reviewed-by: Alex Moreno <alexm@verdnatura.es>
2025-01-15 10:51:25 +00:00
Robert Ferrús 620d14355c Merge branch 'master' into hotFixDefaulterFilter
gitea/salix/pipeline/pr-master This commit looks good Details
2025-01-15 09:12:45 +00:00
Carlos Satorres d95482ea54 Merge pull request 'fix: hotfix 7366 6943' (!3360) from hotfix-7366-6943CreditBillingDataAWB into master
gitea/salix/pipeline/head This commit looks good Details
Reviewed-on: #3360
Reviewed-by: Alex Moreno <alexm@verdnatura.es>
2025-01-15 07:00:40 +00:00
Carlos Satorres d9716154bb Merge branch 'master' into hotfix-7366-6943CreditBillingDataAWB
gitea/salix/pipeline/pr-master This commit looks good Details
2025-01-14 11:54:20 +00:00
Carlos Satorres 01072f7cbc fix: hotfix 7366 6943
gitea/salix/pipeline/pr-master There was a failure building this commit Details
2025-01-14 11:36:54 +01:00
Alex Moreno e273733832 refactor: order by id
gitea/salix/pipeline/head This commit looks good Details
2025-01-14 09:33:26 +01:00
Javi Gallego 44765b5a64 feat: refs #8361 add hasToDownloadRate field to currency model and update exchange rate logic
gitea/salix/pipeline/pr-dev This commit looks good Details
2025-01-14 09:07:00 +01:00
Robert Ferrús 2585cce627 Merge branch 'master' into hotFixDefaulterFilter
gitea/salix/pipeline/pr-master This commit looks good Details
2025-01-14 07:17:17 +00:00
Alex Moreno 48ad72ac98 Merge branch 'test' of https://gitea.verdnatura.es/verdnatura/salix into dev
gitea/salix/pipeline/head This commit looks good Details
2025-01-14 08:00:08 +01:00
Alex Moreno b4686def94 Merge pull request 'build: refs #8389 dump db' (!3359) from 8389-dump into master
gitea/salix/pipeline/head This commit looks good Details
Reviewed-on: #3359
Reviewed-by: Jon Elias <jon@verdnatura.es>
2025-01-14 06:58:52 +00:00
Alex Moreno 6aa898ee59 build: refs #8389 dump db
gitea/salix/pipeline/pr-master This commit looks good Details
2025-01-14 07:39:52 +01:00
Alex Moreno 105a5045cf Merge branch 'test' of https://gitea.verdnatura.es/verdnatura/salix into dev
gitea/salix/pipeline/head This commit looks good Details
2025-01-14 07:37:33 +01:00
Jon Elias 29e6a99983 feat: refs #8247 added new acl for VnUser model
gitea/salix/pipeline/pr-dev This commit looks good Details
2025-01-14 07:36:23 +01:00
Robert Ferrús 0891fc6665 Merge branch 'master' into hotFixDefaulterFilter
gitea/salix/pipeline/pr-master This commit looks good Details
2025-01-14 06:31:23 +00:00
Alex Moreno 43edb1f82e Merge pull request '8389-testToMaster' (!3357) from 8389-testToMaster into master
gitea/salix/pipeline/head This commit looks good Details
Reviewed-on: #3357
Reviewed-by: Guillermo Bonet <guillermo@verdnatura.es>
2025-01-14 06:31:07 +00:00
Alex Moreno 00577056dd build: refs #8389 changelog
gitea/salix/pipeline/pr-master This commit looks good Details
2025-01-13 15:24:12 +01:00
Alex Moreno 6e56bdeeb1 fix: refs #8389 prevent error propagation 2025-01-13 15:24:01 +01:00
Robert Ferrús c4870d52de feat: refs #257275 defaulterFilter
gitea/salix/pipeline/pr-master Build queued... Details
2025-01-13 14:37:27 +01:00
Javi Gallego c15a3bfe50 feat: refs #8381 add initial and final temperature fields to entry model and queries
gitea/salix/pipeline/pr-dev This commit looks good Details
2025-01-13 11:28:30 +01:00
Sergio De la torre a1e1d4fa72 fix: refs #7569 refs·6861 ticketOrderReserve
gitea/salix/pipeline/pr-dev There was a failure building this commit Details
2025-01-10 07:20:24 +01:00
Sergio De la torre 12fa87a93c fix: refs #7569 refs·6861 ticketOrderReserve
gitea/salix/pipeline/pr-dev There was a failure building this commit Details
2025-01-09 16:15:29 +01:00
Javi Gallego 53c604762a Merge branch 'dev' into 8298-zonePriceOptimum
gitea/salix/pipeline/pr-dev This commit looks good Details
2025-01-08 13:43:17 +01:00
Javi Gallego be56313706 feat: refs #8298 add priceOptimum column to zoneEvent and update zone fixture data
gitea/salix/pipeline/pr-dev Build queued... Details
2025-01-08 11:58:50 +01:00
Javi Gallego 0d822d03c9 fix: refs #8298 remove duplicate entry in English locale file
gitea/salix/pipeline/pr-dev There was a failure building this commit Details
2025-01-08 10:30:47 +01:00
Javi Gallego 1816b6de67 feat: refs #8298 add priceOptimum and packagesDiscountFactor to zone and client tables 2025-01-08 10:24:18 +01:00
Javi Gallego dbd8d816c0 fix: refs #8361 streamline transaction handling in exchangeRateUpdate
gitea/salix/pipeline/pr-dev This commit looks good Details
2025-01-07 14:53:26 +01:00
Javi Gallego 786f1fe661 test: refs #8361 enhance exchangeRateUpdate specs to validate day1 and day2 entries without backfilling day3
gitea/salix/pipeline/pr-dev There was a failure building this commit Details
2025-01-07 11:06:09 +01:00
Javi Gallego 73d5d508ce test: refs #8361 enhance exchangeRateUpdate specs with additional scenarios
gitea/salix/pipeline/pr-dev This commit looks good Details
2025-01-07 10:45:51 +01:00
Sergio De la torre 05b8c3451a Merge branch 'dev' of https: refs #7569//gitea.verdnatura.es/verdnatura/salix into 7569-sendEmailOrderTicket 2025-01-02 10:47:11 +01:00
Sergio De la torre 2c672951c6 fix: refs #7569 refs#8188 add IfNotExists 2024-12-12 20:33:00 +01:00
Sergio De la torre 31a6db5da0 feat: refs #7569 refs#7569 sendMail 2024-12-12 20:30:38 +01:00
51 changed files with 738 additions and 190 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

@ -67,7 +67,6 @@ module.exports = Self => {
INSERT INTO util.debug (variable, value) INSERT INTO util.debug (variable, value)
VALUES ('sendCheckingPresence_error', ?) VALUES ('sendCheckingPresence_error', ?)
`, [`User: ${userId}, recipient: ${recipientId}, message: ${message}, error: ${e}`]); `, [`User: ${userId}, recipient: ${recipientId}, message: ${message}, error: ${e}`]);
throw e;
} }
}; };
}; };

View File

@ -12,6 +12,12 @@
"required": true, "required": true,
"id": true "id": true
}, },
"sectorFromCode": {
"type": "string"
},
"sectorToCode": {
"type": "string"
},
"backupPrinterNotificationDelay": { "backupPrinterNotificationDelay": {
"type": "string" "type": "string"
}, },

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

@ -1,26 +1,27 @@
DELIMITER $$ DELIMITER $$
CREATE OR REPLACE DEFINER=`vn`@`localhost` PROCEDURE `vn`.`zone_getAddresses`( CREATE OR REPLACE DEFINER=`vn`@`localhost` PROCEDURE `vn`.`zone_getAddresses`(
vSelf INT, vSelf INT,
vShipped DATE, vLanded DATE,
vDepartmentFk INT vDepartmentFk INT
) )
BEGIN BEGIN
/** /**
* Devuelve un listado de todos los clientes activos * Devuelve un listado de todos los clientes activos
* con consignatarios a los que se les puede * con consignatarios a los que se les puede
* vender producto para esa zona. * entregar producto para esa zona.
* *
* @param vSelf Id de zona * @param vSelf Id de zona
* @param vShipped Fecha de envio * @param vLanded Fecha de entrega
* @param vDepartmentFk Id de departamento * @param vDepartmentFk Id de departamento | NULL para mostrar todos
* @return Un select * @return Un select
*/ */
CALL zone_getPostalCode(vSelf); CALL zone_getPostalCode(vSelf);
WITH clientWithTicket AS ( WITH clientWithTicket AS (
SELECT clientFk SELECT DISTINCT clientFk
FROM vn.ticket 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, SELECT c.id,
c.name, c.name,
@ -30,7 +31,7 @@ BEGIN
u.name username, u.name username,
aai.invoiced, aai.invoiced,
cnb.lastShipped, cnb.lastShipped,
cwt.clientFk IF(cwt.clientFk, TRUE, FALSE) hasTicket
FROM vn.client c FROM vn.client c
JOIN vn.worker w ON w.id = c.salesPersonFk JOIN vn.worker w ON w.id = c.salesPersonFk
JOIN vn.workerDepartment wd ON wd.workerFk = w.id JOIN vn.workerDepartment wd ON wd.workerFk = w.id
@ -50,7 +51,7 @@ BEGIN
AND c.isActive AND c.isActive
AND ct.code = 'normal' AND ct.code = 'normal'
AND bt.code <> 'worker' AND bt.code <> 'worker'
AND (d.id = vDepartmentFk OR NOT vDepartmentFk) AND (d.id = vDepartmentFk OR vDepartmentFk IS NULL)
GROUP BY c.id; GROUP BY c.id;
DROP TEMPORARY TABLE tmp.zoneNodes; DROP TEMPORARY TABLE tmp.zoneNodes;

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

@ -1,16 +0,0 @@
DELETE FROM salix.ACL
WHERE property ='hasItemOlder';
ALTER TABLE vn.productionConfig DROP FOREIGN KEY productionConfig_sector_FK;
ALTER TABLE vn.productionConfig DROP FOREIGN KEY productionConfig_sector_FK_1;
ALTER TABLE vn.productionConfig DROP COLUMN sectorToCode;
ALTER TABLE vn.productionConfig DROP COLUMN sectorFromCode;

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

@ -0,0 +1 @@
CREATE INDEX ticket_landed_IDX USING BTREE ON vn.ticket (landed);

View File

@ -238,25 +238,11 @@ describe('Ticket Edit sale path', () => {
await page.waitToClick(selectors.globalItems.cancelButton); await page.waitToClick(selectors.globalItems.cancelButton);
}); });
it('should select the third sale and create a claim of it', async() => { it('should select the third sale and delete 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();
await page.loginAndModule('salesPerson', 'ticket'); await page.loginAndModule('salesPerson', 'ticket');
await page.accessToSearchResult('16'); await page.accessToSearchResult('16');
await page.accessToSection('ticket.card.sale'); 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.thirdSaleCheckbox);
await page.waitToClick(selectors.ticketSales.deleteSaleButton); await page.waitToClick(selectors.ticketSales.deleteSaleButton);
await page.waitToClick(selectors.globalItems.acceptButton); await page.waitToClick(selectors.globalItems.acceptButton);

View File

@ -75,7 +75,7 @@ describe('Ticket Edit basic data path', () => {
const result = await page const result = await page
.waitToGetProperty(selectors.ticketBasicData.stepTwoTotalPriceDif, 'innerText'); .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() => { it(`should select a new reason for the changes made then click on finalize`, async() => {

View File

@ -211,7 +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", "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.",
@ -247,9 +247,11 @@
"ticketLostExpedition": "The ticket [{{ticketId}}]({{{ticketUrl}}}) has the following lost expedition:{{ expeditionId }}", "ticketLostExpedition": "The ticket [{{ticketId}}]({{{ticketUrl}}}) has the following lost expedition:{{ expeditionId }}",
"The raid information is not correct": "The raid information is not correct", "The raid information is not correct": "The raid information is not correct",
"Payment method is required": "Payment method is required", "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", "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",
} "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."
}

View File

@ -390,13 +390,11 @@
"The web user's email already exists": "El correo del usuario web ya existe", "The web user's email already exists": "El correo del usuario web ya existe",
"Sales already moved": "Ya han sido transferidas", "Sales already moved": "Ya han sido transferidas",
"The raid information is not correct": "La información de la redada no es correcta", "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", "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", "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", "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"
}

View File

@ -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é", "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é", "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", "Cannot send mail": "Impossible d'envoyer le mail",
"Original invoice not found": "Facture originale introuvable", "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", "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é", "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}}", "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."
}

View File

@ -365,5 +365,7 @@
"Cannot send mail": "Não é possível enviar o email", "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", "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}}", "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."
}

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

@ -94,7 +94,7 @@ module.exports = Self => {
AND r1.started = r2.maxStarted AND r1.started = r2.maxStarted
) r ON r.clientFk = c.id ) r ON r.clientFk = c.id
LEFT JOIN workerDepartment wd ON wd.workerFk = u.id LEFT JOIN workerDepartment wd ON wd.workerFk = u.id
JOIN department dp ON dp.id = wd.departmentFk LEFT JOIN department dp ON dp.id = wd.departmentFk
WHERE WHERE
d.created = ? d.created = ?
AND d.amount > 0 AND d.amount > 0

View File

@ -19,6 +19,9 @@
}, },
"created": { "created": {
"type": "date" "type": "date"
},
"workerFk": {
"type": "number"
} }
}, },
"relations": { "relations": {
@ -33,4 +36,4 @@
"foreignKey": "workerFk" "foreignKey": "workerFk"
} }
} }
} }

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

@ -74,7 +74,8 @@ module.exports = Self => {
AND t.companyFk = ? AND t.companyFk = ?
AND NOT t.isDeleted AND NOT t.isDeleted
GROUP BY IF(c.hasToInvoiceByAddress, a.id, c.id) 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, [ const addresses = await Self.rawSql(query, [
minShipped, minShipped,

View File

@ -0,0 +1,70 @@
module.exports = Self => {
Self.remoteMethod('getListItemNewer', {
description:
'Get boolean if any or specific item of the shelving has older created in another shelving or parking',
accessType: 'READ',
accepts: [{
arg: 'shelvingFk',
type: 'string',
required: true,
description: 'Shelving code'
},
{
arg: 'parking',
type: 'string',
required: true,
description: 'Parking code'
},
],
returns: {
type: 'Array',
root: true
},
http: {
path: `/getListItemNewer`,
verb: 'GET'
}
});
Self.getListItemNewer = async(shelvingFk, parking, options) => {
const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
const [isParkingToReview] = await Self.rawSql(`
SELECT COUNT(p.id) parkingToReview
FROM vn.parking p
JOIN vn.sector s ON s.id = p.sectorFk
JOIN vn.productionConfig pc
WHERE p.code = ? AND s.code = pc.sectorToCode;`,
[parking], myOptions);
if (isParkingToReview['parkingToReview'] < 1) return [];
const result = await Self.rawSql(`
WITH tItemShelving AS(
SELECT is2.itemFk, is2.created, p.sectorFK, is2.id
FROM vn.itemShelving is2
JOIN vn.shelving sh ON sh.id = is2.shelvingFk
JOIN vn.parking p ON p.id = sh.parkingFk
JOIN vn.sector s ON s.id = p.sectorFk
JOIN vn.productionConfig pc
WHERE sh.code = ? AND s.code = pc.sectorFromCode
), tItemInSector AS (
SELECT is2.itemFk, is2.created, sh.code
FROM vn.itemShelving is2
JOIN vn.shelving sh ON sh.id = is2.shelvingFk
JOIN vn.parking p ON p.id = sh.parkingFk
JOIN vn.sector s ON s.id = p.sectorFk
JOIN vn.productionConfig pc
WHERE sh.code <> ?
AND s.code = pc.sectorFromCode)
SELECT ti.itemFK, tis.code shelvingFk
FROM tItemShelving ti
JOIN tItemInSector tis ON tis.itemFk = ti.itemFk
JOIN vn.productionConfig pc
WHERE ti.created + INTERVAL pc.itemOlderReviewHours HOUR < tis.created;`,
[shelvingFk, shelvingFk], myOptions);
return result;
};
};

View File

@ -0,0 +1,32 @@
const {models} = require('vn-loopback/server/server');
describe('itemShelving getListItemNewer()', () => {
it('should return true because there is an older item', async() => {
const shelving = 'NBB';
const parking = '700-01';
const sectorCamHighCode = 'FIRST';
const sectorCamCode = 'NS';
const tx = await models.Sector.beginTransaction({});
const myOptions = {transaction: tx};
try {
const config = await models.ProductionConfig.findOne();
await config.updateAttributes({
sectorToCode: sectorCamHighCode,
sectorFromCode: sectorCamCode
});
const result = await models.ItemShelving.getListItemNewer(shelving, parking, myOptions);
expect(result.length).toEqual(3);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
});

View File

@ -4,5 +4,6 @@ module.exports = Self => {
require('../methods/item-shelving/getInventory')(Self); require('../methods/item-shelving/getInventory')(Self);
require('../methods/item-shelving/getAlternative')(Self); require('../methods/item-shelving/getAlternative')(Self);
require('../methods/item-shelving/updateFromSale')(Self); require('../methods/item-shelving/updateFromSale')(Self);
require('../methods/item-shelving/getListItemNewer')(Self);
require('../methods/item-shelving/getItemsByReviewOrder')(Self); require('../methods/item-shelving/getItemsByReviewOrder')(Self);
}; };

View File

@ -28,6 +28,7 @@ module.exports = Self => {
delete args.ctx; delete args.ctx;
if (!args.name) throw new UserError('The social name cannot be empty'); 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 data = {...args, ...{nickname: args.name}};
const supplier = await models.Supplier.create(data, myOptions); const supplier = await models.Supplier.create(data, myOptions);

View File

@ -28,7 +28,6 @@ module.exports = Self => {
verb: 'POST' verb: 'POST'
} }
}); });
Self.saveSign = async(ctx, tickets, location, signedTime, options) => { Self.saveSign = async(ctx, tickets, location, signedTime, options) => {
const models = Self.app.models; const models = Self.app.models;
const myOptions = {userId: ctx.req.accessToken.userId}; const myOptions = {userId: ctx.req.accessToken.userId};
@ -111,6 +110,12 @@ module.exports = Self => {
scope: { scope: {
fields: ['id'] fields: ['id']
} }
},
{
relation: 'zone',
scope: {
fields: ['id', 'zoneFk,', 'name']
}
}] }]
}, myOptions); }, myOptions);
@ -151,6 +156,28 @@ module.exports = Self => {
await Self.rawSql(`CALL vn.ticket_setState(?, ?)`, [ticketId, stateCode], myOptions); 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) { if (ticket?.address()?.province()?.country()?.code != 'ES' && ticket.$cmrFk) {
await models.Ticket.saveCmr(ctx, [ticketId], myOptions); await models.Ticket.saveCmr(ctx, [ticketId], myOptions);
externalTickets.push(ticketId); externalTickets.push(ticketId);
@ -163,4 +190,25 @@ module.exports = Self => {
} }
await models.Ticket.sendCmrEmail(ctx, externalTickets); 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
});
}
}; };

View File

@ -1,12 +1,20 @@
const models = require('vn-loopback/server/server').models; const models = require('vn-loopback/server/server').models;
const LoopBackContext = require('loopback-context');
describe('Ticket saveSign()', () => { describe('Ticket saveSign()', () => {
let ctx = {req: { let ctx = {req: {
getLocale: () => { getLocale: () => {
return 'en'; return 'en';
}, },
__: () => {},
accessToken: {userId: 9} 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() => { it(`should throw error if the ticket's alert level is lower than 2`, async() => {
const tx = await models.TicketDms.beginTransaction({}); const tx = await models.TicketDms.beginTransaction({});
@ -51,4 +59,46 @@ describe('Ticket saveSign()', () => {
expect(ticketTrackingAfter.name).toBe('Entregado en parte'); 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);
});
}); });

View File

@ -1,4 +1,3 @@
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL; const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
const buildFilter = require('vn-loopback/util/filter').buildFilter; const buildFilter = require('vn-loopback/util/filter').buildFilter;
const mergeFilters = require('vn-loopback/util/filter').mergeFilters; const mergeFilters = require('vn-loopback/util/filter').mergeFilters;
@ -91,6 +90,11 @@ module.exports = Self => {
arg: 'landed', arg: 'landed',
type: 'date', type: 'date',
description: 'The landed date' description: 'The landed date'
},
{
arg: 'awbFk',
type: 'number',
description: 'The awbFk id'
} }
], ],
returns: { returns: {
@ -168,14 +172,17 @@ module.exports = Self => {
t.totalEntries, t.totalEntries,
t.isRaid, t.isRaid,
t.daysInForward, t.daysInForward,
t.awbFk,
am.name agencyModeName, am.name agencyModeName,
a.code awbCode,
win.name warehouseInName, win.name warehouseInName,
wout.name warehouseOutName, wout.name warehouseOutName,
cnt.code continent cnt.code continent
FROM vn.travel t FROM travel t
JOIN vn.agencyMode am ON am.id = t.agencyModeFk JOIN agencyMode am ON am.id = t.agencyModeFk
JOIN vn.warehouse win ON win.id = t.warehouseInFk JOIN warehouse win ON win.id = t.warehouseInFk
JOIN vn.warehouse wout ON wout.id = t.warehouseOutFk 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 warehouse wo ON wo.id = t.warehouseOutFk
JOIN country c ON c.id = wo.countryFk JOIN country c ON c.id = wo.countryFk
LEFT JOIN continent cnt ON cnt.id = c.continentFk) AS t` LEFT JOIN continent cnt ON cnt.id = c.continentFk) AS t`

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"
}, },

View File

@ -1,6 +1,6 @@
{ {
"name": "salix-back", "name": "salix-back",
"version": "25.04.0", "version": "25.06.0",
"author": "Verdnatura Levante SL", "author": "Verdnatura Levante SL",
"description": "Salix backend", "description": "Salix backend",
"license": "GPL-3.0", "license": "GPL-3.0",