From 7895decf4eea09243c552d6cd94ad3d9d7ffae78 Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Tue, 19 Jul 2022 15:17:22 +0200
Subject: [PATCH 001/151] feat(notification): create models

---
 back/methods/notification/clean.js        |  0
 back/methods/notification/send.js         | 18 ++++++
 back/models/notifcation.json              | 22 +++++++
 back/models/notifcationAcl.json           | 21 +++++++
 back/models/notifcationConfig.json        | 19 ++++++
 back/models/notifcationQueue.json         | 37 ++++++++++++
 back/models/notification.js               |  4 ++
 back/models/notificationSubscription.json | 21 +++++++
 db/dump/fixtures.sql                      |  5 +-
 db/dump/structure.sql                     | 71 ++++++++++++++++++++++-
 10 files changed, 214 insertions(+), 4 deletions(-)
 create mode 100644 back/methods/notification/clean.js
 create mode 100644 back/methods/notification/send.js
 create mode 100644 back/models/notifcation.json
 create mode 100644 back/models/notifcationAcl.json
 create mode 100644 back/models/notifcationConfig.json
 create mode 100644 back/models/notifcationQueue.json
 create mode 100644 back/models/notification.js
 create mode 100644 back/models/notificationSubscription.json

diff --git a/back/methods/notification/clean.js b/back/methods/notification/clean.js
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/back/methods/notification/send.js b/back/methods/notification/send.js
new file mode 100644
index 0000000000..bb2d79f2a2
--- /dev/null
+++ b/back/methods/notification/send.js
@@ -0,0 +1,18 @@
+module.exports = Self => {
+    Self.remoteMethod('send', {
+        description: 'Send notifications from queue',
+        accessType: 'WRITE',
+        returns: {
+            type: 'object',
+            root: true
+        },
+        http: {
+            path: `/send`,
+            verb: 'POST'
+        }
+    });
+
+    Self.send = async() => {
+
+    };
+};
diff --git a/back/models/notifcation.json b/back/models/notifcation.json
new file mode 100644
index 0000000000..e4f0be17e0
--- /dev/null
+++ b/back/models/notifcation.json
@@ -0,0 +1,22 @@
+{
+	"name": "Notificacion",
+	"base": "VnModel",
+	"options": {
+		"mysql": {
+			"table": "notificacion"
+		}
+	},
+	"properties": {
+        "id": {
+            "type": "number",
+            "id": true,
+            "description": "Identifier"
+        },
+        "name": {
+            "type": "string"
+        },
+        "description": {
+            "type": "string"
+        }
+    }
+}
\ No newline at end of file
diff --git a/back/models/notifcationAcl.json b/back/models/notifcationAcl.json
new file mode 100644
index 0000000000..f5861943f7
--- /dev/null
+++ b/back/models/notifcationAcl.json
@@ -0,0 +1,21 @@
+{
+	"name": "NotificacionAcl",
+	"base": "VnModel",
+	"options": {
+		"mysql": {
+			"table": "notificacionAcl"
+		}
+	},
+	"relations": {
+        "notificacion": {
+            "type": "belongsTo",
+            "model": "Notificacion",
+            "foreignKey": "notificacionFk"
+        },
+        "role": {
+            "type": "belongsTo",
+            "model": "Role",
+            "foreignKey": "roleFk"
+        }
+    }
+}
\ No newline at end of file
diff --git a/back/models/notifcationConfig.json b/back/models/notifcationConfig.json
new file mode 100644
index 0000000000..73882b6b7a
--- /dev/null
+++ b/back/models/notifcationConfig.json
@@ -0,0 +1,19 @@
+{
+	"name": "NotificationConfig",
+	"base": "VnModel",
+	"options": {
+		"mysql": {
+			"table": "notificationConfig"
+		}
+	},
+	"properties": {
+        "id": {
+            "type": "number",
+            "id": true,
+            "description": "Identifier"
+        },
+        "cleanDays": {
+            "type": "number"
+        }
+    }
+}
\ No newline at end of file
diff --git a/back/models/notifcationQueue.json b/back/models/notifcationQueue.json
new file mode 100644
index 0000000000..7a9199bc0f
--- /dev/null
+++ b/back/models/notifcationQueue.json
@@ -0,0 +1,37 @@
+{
+	"name": "NotificacionQueue",
+	"base": "VnModel",
+	"options": {
+		"mysql": {
+			"table": "notificacionQueue"
+		}
+	},
+	"properties": {
+        "id": {
+            "type": "number",
+            "id": true,
+            "description": "Identifier"
+        },
+        "params": {
+            "type": "string"
+        },
+        "status": {
+            "type": "string"
+        },
+        "created": {
+            "type": "date"
+        }
+    },
+    "relations": {
+        "notificacion": {
+            "type": "belongsTo",
+            "model": "Notificacion",
+            "foreignKey": "notificacionFk"
+        },
+        "author": {
+            "type": "belongsTo",
+            "model": "User",
+            "foreignKey": "authorFk"
+        }
+    }
+}
\ No newline at end of file
diff --git a/back/models/notification.js b/back/models/notification.js
new file mode 100644
index 0000000000..da766d4424
--- /dev/null
+++ b/back/models/notification.js
@@ -0,0 +1,4 @@
+module.exports = Self => {
+    require('../methods/notification/send')(Self);
+    require('../methods/notification/clear')(Self);
+};
diff --git a/back/models/notificationSubscription.json b/back/models/notificationSubscription.json
new file mode 100644
index 0000000000..ed8bb1907d
--- /dev/null
+++ b/back/models/notificationSubscription.json
@@ -0,0 +1,21 @@
+{
+	"name": "NotificationSubscription",
+	"base": "VnModel",
+	"options": {
+		"mysql": {
+			"table": "notificationSubscription"
+		}
+	},
+	"relations": {
+        "notificacion": {
+            "type": "belongsTo",
+            "model": "Notificacion",
+            "foreignKey": "notificacionFk"
+        },
+        "user": {
+            "type": "belongsTo",
+            "model": "User",
+            "foreignKey": "userFk"
+        }
+    }
+}
\ No newline at end of file
diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql
index 0609a6a6ab..dabc731394 100644
--- a/db/dump/fixtures.sql
+++ b/db/dump/fixtures.sql
@@ -2610,4 +2610,7 @@ INSERT INTO `vn`.`sectorCollectionSaleGroup` (`sectorCollectionFk`, `saleGroupFk
         
 INSERT INTO `vn`.`workerTimeControlConfig` (`id`, `dayBreak`, `dayBreakDriver`, `shortWeekBreak`, `longWeekBreak`, `weekScope`, `mailPass`, `mailHost`, `mailSuccessFolder`, `mailErrorFolder`, `mailUser`, `minHoursToBreak`, `breakHours`, `hoursCompleteWeek`, `startNightlyHours`, `endNightlyHours`, `maxTimePerDay`, `breakTime`, `timeToBreakTime`, `dayMaxTime`, `shortWeekDays`, `longWeekDays`)
     VALUES
-        (1, 43200, 32400, 129600, 259200, 604800, '', '', 'Leidos.exito', 'Leidos.error', 'timeControl', 5.33, 0.33, 40, '22:00:00', '06:00:00', 57600, 1200, 18000, 57600, 6, 13);
\ No newline at end of file
+        (1, 43200, 32400, 129600, 259200, 604800, '', '', 'Leidos.exito', 'Leidos.error', 'timeControl', 5.33, 0.33, 40, '22:00:00', '06:00:00', 57600, 1200, 18000, 57600, 6, 13);
+
+INSERT INTO `util`.`notificationConfig`
+	SET `cleanDays` = 90;
\ No newline at end of file
diff --git a/db/dump/structure.sql b/db/dump/structure.sql
index 2c0e8231af..9238557620 100644
--- a/db/dump/structure.sql
+++ b/db/dump/structure.sql
@@ -20849,9 +20849,74 @@ CREATE DATABASE /*!32312 IF NOT EXISTS*/ `util` /*!40100 DEFAULT CHARACTER SET u
 
 USE `util`;
 
---
--- Table structure for table `config`
---
+CREATE TABLE notification(
+	id INT PRIMARY KEY,
+	`name` VARCHAR(255) UNIQUE,
+	`description` VARCHAR(255)
+);
+
+CREATE TABLE notificationAcl (
+	notificationFk INT(11),
+	roleFk INT(10) unsigned,
+	PRIMARY KEY(notificationFk, roleFk),
+	CONSTRAINT `notificationAcl_ibfk_1` FOREIGN KEY (`notificationFk`) REFERENCES `notification` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
+	CONSTRAINT `notificationAcl_ibfk_2` FOREIGN KEY (`roleFk`) REFERENCES `account`.`role` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
+);
+
+CREATE TABLE notificationSubscription(
+	notificationFk INT,
+	userFk INT(10) unsigned,
+	PRIMARY KEY(notificationFk, userFk),
+	CONSTRAINT `notificationSubscription_ibfk_1` FOREIGN KEY (`notificationFk`) REFERENCES `notification` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
+	CONSTRAINT `notificationSubscription_ibfk_2` FOREIGN KEY (`userFk`) REFERENCES `account`.`user` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
+);
+
+CREATE TABLE notificationQueue(
+	id INT PRIMARY KEY AUTO_INCREMENT,
+	notificationFk VARCHAR(255),
+	params TEXT,
+	authorFk INT(10) unsigned NULL,
+	`status` ENUM('pending', 'sent', 'error') NOT NULL DEFAULT 'pending',
+	created DATETIME DEFAULT CURRENT_TIMESTAMP,
+	INDEX(notificationFk),
+	INDEX(authorFk),
+	INDEX(status),
+	CONSTRAINT `notificationQueue_ibfk_1` FOREIGN KEY (`notificationFk`) REFERENCES `notification` (`name`) ON DELETE CASCADE ON UPDATE CASCADE,
+	CONSTRAINT `notificationQueue_ibfk_2` FOREIGN KEY (`authorFk`) REFERENCES `account`.`user` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
+);
+
+CREATE TABLE notificationConfig(
+	id INT PRIMARY KEY AUTO_INCREMENT,
+	cleanDays MEDIUMINT
+);
+
+DROP FUNCTION IF EXISTS util.notification_send;
+DELIMITER $$
+CREATE FUNCTION util.notification_send(vNotificationName VARCHAR(255), vParams TEXT, vAuthorFk INT)
+	RETURNS INT
+BEGIN
+/**
+ * Sends a notification.
+ *
+ * @param vNotificationName The notification name
+ * @param vParams The notification parameters formatted as JSON
+ * @param vAuthorFk The notification author or %NULL if there is no author
+ * @return The notification id
+ */
+	DECLARE vNotificationFk INT;
+
+	SELECT id INTO vNotificationFk
+		FROM `notification`
+		WHERE `name` = vNotificationName;
+
+	INSERT INTO notificationQueue
+		SET notificationFk = vNotificationFk,
+			params = vParams,
+			authorFk = vAuthorFk;
+
+	RETURN LAST_INSERT_ID();
+END$$
+DELIMITER ;
 
 DROP TABLE IF EXISTS `config`;
 /*!40101 SET @saved_cs_client     = @@character_set_client */;

From 9b48cbb07866be87502d33cee7d6648243606a0d Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Wed, 20 Jul 2022 14:54:50 +0200
Subject: [PATCH 002/151] feat(notification): send

---
 back/methods/notification/send.js             | 19 ++++++++++++++++++-
 back/model-config.json                        | 15 +++++++++++++++
 back/models/notification.js                   |  1 -
 .../{notifcation.json => notification.json}   |  4 ++--
 ...tifcationAcl.json => notificationAcl.json} | 10 +++++-----
 ...ionConfig.json => notificationConfig.json} |  2 +-
 ...ationQueue.json => notificationQueue.json} | 10 +++++-----
 back/models/notificationSubscription.json     |  8 ++++----
 .../10490-goldenSummer/00-aclNotification.sql |  3 +++
 db/dump/fixtures.sql                          | 18 +++++++++++++++++-
 10 files changed, 70 insertions(+), 20 deletions(-)
 rename back/models/{notifcation.json => notification.json} (84%)
 rename back/models/{notifcationAcl.json => notificationAcl.json} (59%)
 rename back/models/{notifcationConfig.json => notificationConfig.json} (88%)
 rename back/models/{notifcationQueue.json => notificationQueue.json} (76%)
 create mode 100644 db/changes/10490-goldenSummer/00-aclNotification.sql

diff --git a/back/methods/notification/send.js b/back/methods/notification/send.js
index bb2d79f2a2..d5149fc59b 100644
--- a/back/methods/notification/send.js
+++ b/back/methods/notification/send.js
@@ -1,7 +1,7 @@
 module.exports = Self => {
     Self.remoteMethod('send', {
         description: 'Send notifications from queue',
-        accessType: 'WRITE',
+        accessType: 'READ',
         returns: {
             type: 'object',
             root: true
@@ -13,6 +13,23 @@ module.exports = Self => {
     });
 
     Self.send = async() => {
+        const status = 'pending';
 
+        const myOptions = {};
+        let tx;
+
+        if (!myOptions.transaction) {
+            tx = await Self.beginTransaction({});
+            myOptions.transaction = tx;
+        }
+
+        const notificationQueue = await Self.app.models.NotificationQueue.find({
+            where: {code: status},
+            include: [{
+                relation: 'notificationSubscription'
+            }]
+        }, myOptions);
+
+        console.log(notificationQueue);
     };
 };
diff --git a/back/model-config.json b/back/model-config.json
index 3432103832..755f449de7 100644
--- a/back/model-config.json
+++ b/back/model-config.json
@@ -77,6 +77,21 @@
     "Module": {
         "dataSource": "vn"
     },
+    "Notification": {
+        "dataSource": "vn"
+    },
+    "NotificationAcl": {
+        "dataSource": "vn"
+    },
+    "NotificationConfig": {
+        "dataSource": "vn"
+    },
+    "NotificationQueue": {
+        "dataSource": "vn"
+    },
+    "NotificationSubscription": {
+        "dataSource": "vn"
+    },
     "Province": {
         "dataSource": "vn"
     },
diff --git a/back/models/notification.js b/back/models/notification.js
index da766d4424..46378bd027 100644
--- a/back/models/notification.js
+++ b/back/models/notification.js
@@ -1,4 +1,3 @@
 module.exports = Self => {
     require('../methods/notification/send')(Self);
-    require('../methods/notification/clear')(Self);
 };
diff --git a/back/models/notifcation.json b/back/models/notification.json
similarity index 84%
rename from back/models/notifcation.json
rename to back/models/notification.json
index e4f0be17e0..9422d03b37 100644
--- a/back/models/notifcation.json
+++ b/back/models/notification.json
@@ -1,9 +1,9 @@
 {
-	"name": "Notificacion",
+	"name": "Notification",
 	"base": "VnModel",
 	"options": {
 		"mysql": {
-			"table": "notificacion"
+			"table": "util.notification"
 		}
 	},
 	"properties": {
diff --git a/back/models/notifcationAcl.json b/back/models/notificationAcl.json
similarity index 59%
rename from back/models/notifcationAcl.json
rename to back/models/notificationAcl.json
index f5861943f7..e3e97f52de 100644
--- a/back/models/notifcationAcl.json
+++ b/back/models/notificationAcl.json
@@ -1,16 +1,16 @@
 {
-	"name": "NotificacionAcl",
+	"name": "NotificationAcl",
 	"base": "VnModel",
 	"options": {
 		"mysql": {
-			"table": "notificacionAcl"
+			"table": "util.notificationAcl"
 		}
 	},
 	"relations": {
-        "notificacion": {
+        "notification": {
             "type": "belongsTo",
-            "model": "Notificacion",
-            "foreignKey": "notificacionFk"
+            "model": "Notification",
+            "foreignKey": "notificationFk"
         },
         "role": {
             "type": "belongsTo",
diff --git a/back/models/notifcationConfig.json b/back/models/notificationConfig.json
similarity index 88%
rename from back/models/notifcationConfig.json
rename to back/models/notificationConfig.json
index 73882b6b7a..b00ed3675b 100644
--- a/back/models/notifcationConfig.json
+++ b/back/models/notificationConfig.json
@@ -3,7 +3,7 @@
 	"base": "VnModel",
 	"options": {
 		"mysql": {
-			"table": "notificationConfig"
+			"table": "util.notificationConfig"
 		}
 	},
 	"properties": {
diff --git a/back/models/notifcationQueue.json b/back/models/notificationQueue.json
similarity index 76%
rename from back/models/notifcationQueue.json
rename to back/models/notificationQueue.json
index 7a9199bc0f..122d3816d3 100644
--- a/back/models/notifcationQueue.json
+++ b/back/models/notificationQueue.json
@@ -1,9 +1,9 @@
 {
-	"name": "NotificacionQueue",
+	"name": "NotificationQueue",
 	"base": "VnModel",
 	"options": {
 		"mysql": {
-			"table": "notificacionQueue"
+			"table": "util.notificationQueue"
 		}
 	},
 	"properties": {
@@ -23,10 +23,10 @@
         }
     },
     "relations": {
-        "notificacion": {
+        "notification": {
             "type": "belongsTo",
-            "model": "Notificacion",
-            "foreignKey": "notificacionFk"
+            "model": "Notification",
+            "foreignKey": "notificationFk"
         },
         "author": {
             "type": "belongsTo",
diff --git a/back/models/notificationSubscription.json b/back/models/notificationSubscription.json
index ed8bb1907d..14b305ca8c 100644
--- a/back/models/notificationSubscription.json
+++ b/back/models/notificationSubscription.json
@@ -3,14 +3,14 @@
 	"base": "VnModel",
 	"options": {
 		"mysql": {
-			"table": "notificationSubscription"
+			"table": "util.notificationSubscription"
 		}
 	},
 	"relations": {
-        "notificacion": {
+        "notification": {
             "type": "belongsTo",
-            "model": "Notificacion",
-            "foreignKey": "notificacionFk"
+            "model": "Notification",
+            "foreignKey": "notificationFk"
         },
         "user": {
             "type": "belongsTo",
diff --git a/db/changes/10490-goldenSummer/00-aclNotification.sql b/db/changes/10490-goldenSummer/00-aclNotification.sql
new file mode 100644
index 0000000000..aa4e32cee4
--- /dev/null
+++ b/db/changes/10490-goldenSummer/00-aclNotification.sql
@@ -0,0 +1,3 @@
+INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
+    VALUES
+        ('Notification', '*', 'READ', 'ALLOW', 'ROLE', 'developer');
diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql
index dabc731394..f73210a960 100644
--- a/db/dump/fixtures.sql
+++ b/db/dump/fixtures.sql
@@ -2613,4 +2613,20 @@ INSERT INTO `vn`.`workerTimeControlConfig` (`id`, `dayBreak`, `dayBreakDriver`,
         (1, 43200, 32400, 129600, 259200, 604800, '', '', 'Leidos.exito', 'Leidos.error', 'timeControl', 5.33, 0.33, 40, '22:00:00', '06:00:00', 57600, 1200, 18000, 57600, 6, 13);
 
 INSERT INTO `util`.`notificationConfig`
-	SET `cleanDays` = 90;
\ No newline at end of file
+	SET `cleanDays` = 90;
+
+INSERT INTO `util`.`notification` (`id`, `name`, `description`)
+    VALUES
+        (1, 'notification one', 'notification fixture one');
+
+INSERT INTO `util`.`notificationAcl` (`notificationFk`, `roleFk`)
+    VALUES
+        (1, 9);
+
+INSERT INTO `util`.`notificationQueue` (`id`, `notificationFk`, `params`, `authorFk`, `status`, `created`)
+    VALUES
+        (1, 'notification one', 'randomParams', 9, 'pending', util.VN_CURDATE());
+
+INSERT INTO `util`.`notificationSubscription` (`notificationFk`, `userFk`)
+    VALUES
+        (1, 1110);
\ No newline at end of file

From 8048d4ce90d22d08ffa8e24bd8671f5497baee8d Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Mon, 25 Jul 2022 08:25:10 +0200
Subject: [PATCH 003/151] feat(notification): basic functionality and test

---
 back/methods/notification/clean.js            | 46 ++++++++++++++
 back/methods/notification/send.js             | 63 ++++++++++++++++---
 back/methods/notification/specs/clean.spec.js | 42 +++++++++++++
 back/methods/notification/specs/send.spec.js  | 33 ++++++++++
 back/models/notification.js                   |  1 +
 back/models/notification.json                 | 10 ++-
 back/models/notificationQueue.json            |  5 +-
 back/models/notificationSubscription.json     | 14 ++++-
 .../10490-goldenSummer/00-aclNotification.sql |  2 +-
 db/dump/fixtures.sql                          |  4 +-
 10 files changed, 205 insertions(+), 15 deletions(-)
 create mode 100644 back/methods/notification/specs/clean.spec.js
 create mode 100644 back/methods/notification/specs/send.spec.js

diff --git a/back/methods/notification/clean.js b/back/methods/notification/clean.js
index e69de29bb2..e6da58af8b 100644
--- a/back/methods/notification/clean.js
+++ b/back/methods/notification/clean.js
@@ -0,0 +1,46 @@
+module.exports = Self => {
+    Self.remoteMethod('clean', {
+        description: 'clean notifications from queue',
+        accessType: 'WRITE',
+        returns: {
+            type: 'object',
+            root: true
+        },
+        http: {
+            path: `/clean`,
+            verb: 'POST'
+        }
+    });
+
+    Self.clean = async options => {
+        const models = Self.app.models;
+        const status = ['sent', 'error'];
+
+        const myOptions = {};
+        let tx;
+
+        if (typeof options == 'object')
+            Object.assign(myOptions, options);
+
+        if (!myOptions.transaction) {
+            tx = await Self.beginTransaction({});
+            myOptions.transaction = tx;
+        }
+
+        try {
+            const config = await models.NotificationConfig.findOne({}, myOptions);
+            const cleanDate = new Date();
+            cleanDate.setDate(cleanDate.getDate() - config.cleanDays);
+
+            await models.NotificationQueue.destroyAll({
+                where: {status: {inq: status}},
+                created: {lt: cleanDate}
+            }, myOptions);
+
+            if (tx) await tx.commit();
+        } catch (e) {
+            if (tx) await tx.rollback();
+            throw e;
+        }
+    };
+};
diff --git a/back/methods/notification/send.js b/back/methods/notification/send.js
index d5149fc59b..b56d9d6c03 100644
--- a/back/methods/notification/send.js
+++ b/back/methods/notification/send.js
@@ -1,7 +1,9 @@
+const axios = require('axios');
+
 module.exports = Self => {
     Self.remoteMethod('send', {
         description: 'Send notifications from queue',
-        accessType: 'READ',
+        accessType: 'WRITE',
         returns: {
             type: 'object',
             root: true
@@ -12,24 +14,69 @@ module.exports = Self => {
         }
     });
 
-    Self.send = async() => {
+    Self.send = async options => {
+        // const headers = ctx.req.headers;
+        // const origin = headers.origin || 'http://' + headers.host;
+        // const auth = ctx.req.accessToken;
+        // console.log(origin);
+
+        const models = Self.app.models;
         const status = 'pending';
 
         const myOptions = {};
         let tx;
 
+        if (typeof options == 'object')
+            Object.assign(myOptions, options);
+
         if (!myOptions.transaction) {
             tx = await Self.beginTransaction({});
             myOptions.transaction = tx;
         }
 
-        const notificationQueue = await Self.app.models.NotificationQueue.find({
-            where: {code: status},
-            include: [{
-                relation: 'notificationSubscription'
-            }]
+        const notificationQueue = await models.NotificationQueue.find({
+            where: {status: status},
+            include: [
+                {
+                    relation: 'notification',
+                    scope: {
+                        include: {
+                            relation: 'subscription',
+                            scope: {
+                                include: {
+                                    relation: 'user',
+                                    scope: {
+                                        fields: ['name']
+                                    }
+                                }
+                            }
+                        }
+                    }
+
+                }
+            ]
         }, myOptions);
 
-        console.log(notificationQueue);
+        const statusSent = 'sent';
+        const statusError = 'error';
+        for (const queue of notificationQueue) {
+            // console.log(queue);
+            // console.log(origin);
+            // console.log(auth);
+            // console.log(queue.notification().name);
+            // console.log(queue.params);
+
+            // const queueParams = Object.assign({}, JSON.parse(queue.params));
+            // queueParams.authorization = auth.id;
+
+            try {
+                // await print axios.get(`print`, queueParams)
+                await queue.updateAttribute('status', statusSent);
+            } catch (error) {
+                await queue.updateAttribute('status', statusError);
+            }
+        }
+
+        return notificationQueue;
     };
 };
diff --git a/back/methods/notification/specs/clean.spec.js b/back/methods/notification/specs/clean.spec.js
new file mode 100644
index 0000000000..c9441a98be
--- /dev/null
+++ b/back/methods/notification/specs/clean.spec.js
@@ -0,0 +1,42 @@
+const models = require('vn-loopback/server/server').models;
+
+fdescribe('Notification Clean()', () => {
+    it('should delete old rows with error', async() => {
+        const userId = 9;
+        const status = 'error';
+        const tx = await models.NotificationQueue.beginTransaction({});
+        const options = {transaction: tx};
+
+        const notification = await models.Notification.findOne({}, options);
+        const notificationConfig = await models.NotificationConfig.findOne({});
+
+        const cleanDate = new Date();
+        cleanDate.setDate(cleanDate.getDate() - (notificationConfig.cleanDays + 1));
+
+        let before;
+        let after;
+
+        try {
+            const notificationDelete = await models.NotificationQueue.create({
+                notificationFk: notification.name,
+                authorFk: userId,
+                status: status,
+                created: cleanDate
+            }, options);
+
+            before = await models.NotificationQueue.findById(notificationDelete.id, null, options);
+
+            await models.Notification.clean(options);
+
+            after = await models.NotificationQueue.findById(notificationDelete.id, null, options);
+
+            await tx.rollback();
+        } catch (e) {
+            await tx.rollback();
+            throw e;
+        }
+
+        expect(before.notificationFk).toEqual(notification.name);
+        expect(after).toBe(null);
+    });
+});
diff --git a/back/methods/notification/specs/send.spec.js b/back/methods/notification/specs/send.spec.js
new file mode 100644
index 0000000000..ce03b4f3ff
--- /dev/null
+++ b/back/methods/notification/specs/send.spec.js
@@ -0,0 +1,33 @@
+const models = require('vn-loopback/server/server').models;
+
+fdescribe('Notification Send()', () => {
+    it('should send notification', async() => {
+        const statusPending = 'pending';
+        const tx = await models.NotificationQueue.beginTransaction({});
+        const options = {transaction: tx};
+        const filter = {
+            where: {
+                status: statusPending
+            }
+        };
+
+        let before;
+        let after;
+
+        try {
+            before = await models.NotificationQueue.find(filter, options);
+
+            await models.Notification.send(options);
+
+            after = await models.NotificationQueue.find(filter, options);
+
+            await tx.rollback();
+        } catch (e) {
+            await tx.rollback();
+            throw e;
+        }
+
+        expect(before.length).toEqual(1);
+        expect(after.length).toEqual(0);
+    });
+});
diff --git a/back/models/notification.js b/back/models/notification.js
index 46378bd027..65e82e3c7a 100644
--- a/back/models/notification.js
+++ b/back/models/notification.js
@@ -1,3 +1,4 @@
 module.exports = Self => {
     require('../methods/notification/send')(Self);
+    require('../methods/notification/clean')(Self);
 };
diff --git a/back/models/notification.json b/back/models/notification.json
index 9422d03b37..56f66bf1de 100644
--- a/back/models/notification.json
+++ b/back/models/notification.json
@@ -13,10 +13,18 @@
             "description": "Identifier"
         },
         "name": {
-            "type": "string"
+            "type": "string",
+            "required": true
         },
         "description": {
             "type": "string"
         }
+    },
+    "relations": {
+        "subscription": {
+            "type": "hasMany",
+            "model": "NotificationSubscription",
+            "foreignKey": "notificationFk"
+        }
     }
 }
\ No newline at end of file
diff --git a/back/models/notificationQueue.json b/back/models/notificationQueue.json
index 122d3816d3..9790ea595c 100644
--- a/back/models/notificationQueue.json
+++ b/back/models/notificationQueue.json
@@ -26,11 +26,12 @@
         "notification": {
             "type": "belongsTo",
             "model": "Notification",
-            "foreignKey": "notificationFk"
+            "foreignKey": "notificationFk",
+            "primaryKey": "name"
         },
         "author": {
             "type": "belongsTo",
-            "model": "User",
+            "model": "Account",
             "foreignKey": "authorFk"
         }
     }
diff --git a/back/models/notificationSubscription.json b/back/models/notificationSubscription.json
index 14b305ca8c..43fa6db274 100644
--- a/back/models/notificationSubscription.json
+++ b/back/models/notificationSubscription.json
@@ -6,6 +6,18 @@
 			"table": "util.notificationSubscription"
 		}
 	},
+    "properties": {
+        "notificationFk": {
+            "type": "number",
+            "id": true,
+            "description": "Identifier"
+        },
+        "userFk": {
+            "type": "number",
+            "id": true,
+            "description": "Identifier"
+        }
+    },
 	"relations": {
         "notification": {
             "type": "belongsTo",
@@ -14,7 +26,7 @@
         },
         "user": {
             "type": "belongsTo",
-            "model": "User",
+            "model": "Account",
             "foreignKey": "userFk"
         }
     }
diff --git a/db/changes/10490-goldenSummer/00-aclNotification.sql b/db/changes/10490-goldenSummer/00-aclNotification.sql
index aa4e32cee4..51d6b24714 100644
--- a/db/changes/10490-goldenSummer/00-aclNotification.sql
+++ b/db/changes/10490-goldenSummer/00-aclNotification.sql
@@ -1,3 +1,3 @@
 INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
     VALUES
-        ('Notification', '*', 'READ', 'ALLOW', 'ROLE', 'developer');
+        ('Notification', '*', 'WRITE', 'ALLOW', 'ROLE', 'developer');
diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql
index f73210a960..7731755e40 100644
--- a/db/dump/fixtures.sql
+++ b/db/dump/fixtures.sql
@@ -2617,7 +2617,7 @@ INSERT INTO `util`.`notificationConfig`
 
 INSERT INTO `util`.`notification` (`id`, `name`, `description`)
     VALUES
-        (1, 'notification one', 'notification fixture one');
+        (1, 'invoice', 'notification fixture one');
 
 INSERT INTO `util`.`notificationAcl` (`notificationFk`, `roleFk`)
     VALUES
@@ -2625,7 +2625,7 @@ INSERT INTO `util`.`notificationAcl` (`notificationFk`, `roleFk`)
 
 INSERT INTO `util`.`notificationQueue` (`id`, `notificationFk`, `params`, `authorFk`, `status`, `created`)
     VALUES
-        (1, 'notification one', 'randomParams', 9, 'pending', util.VN_CURDATE());
+        (1, 'invoice', '{"invoiceId": 1}', 9, 'pending', util.VN_CURDATE());
 
 INSERT INTO `util`.`notificationSubscription` (`notificationFk`, `userFk`)
     VALUES

From 2b19688ca4a9e0d6bcb9cad1fb2e330a33877755 Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Mon, 25 Jul 2022 08:25:46 +0200
Subject: [PATCH 004/151] quit focus

---
 back/methods/notification/specs/clean.spec.js | 2 +-
 back/methods/notification/specs/send.spec.js  | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/back/methods/notification/specs/clean.spec.js b/back/methods/notification/specs/clean.spec.js
index c9441a98be..4c9dc563d0 100644
--- a/back/methods/notification/specs/clean.spec.js
+++ b/back/methods/notification/specs/clean.spec.js
@@ -1,6 +1,6 @@
 const models = require('vn-loopback/server/server').models;
 
-fdescribe('Notification Clean()', () => {
+describe('Notification Clean()', () => {
     it('should delete old rows with error', async() => {
         const userId = 9;
         const status = 'error';
diff --git a/back/methods/notification/specs/send.spec.js b/back/methods/notification/specs/send.spec.js
index ce03b4f3ff..015d1cb4d0 100644
--- a/back/methods/notification/specs/send.spec.js
+++ b/back/methods/notification/specs/send.spec.js
@@ -1,6 +1,6 @@
 const models = require('vn-loopback/server/server').models;
 
-fdescribe('Notification Send()', () => {
+describe('Notification Send()', () => {
     it('should send notification', async() => {
         const statusPending = 'pending';
         const tx = await models.NotificationQueue.beginTransaction({});

From 3fd34e08618fe9ea1b260f8103bddb9b6d9421fd Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Mon, 25 Jul 2022 14:49:39 +0200
Subject: [PATCH 005/151] feat(claim_pickup_order): modify email

---
 db/dump/fixtures.sql                          | 256 +++++++++---------
 modules/claim/front/basic-data/index.html     |   4 +-
 modules/claim/front/basic-data/locale/es.yml  |   4 +-
 modules/claim/front/descriptor/index.js       |   5 +-
 modules/claim/front/summary/index.html        |  47 ++--
 .../claim-pickup-order.html                   |   9 +-
 .../claim-pickup-order/claim-pickup-order.js  |  12 +
 .../email/claim-pickup-order/locale/es.yml    |  13 +-
 .../claim-pickup-order.html                   |   9 +-
 .../claim-pickup-order/claim-pickup-order.js  |   4 -
 .../reports/claim-pickup-order/locale/es.yml  |   4 -
 .../claim-pickup-order/sql/claimConfig.sql    |   2 -
 12 files changed, 192 insertions(+), 177 deletions(-)
 delete mode 100644 print/templates/reports/claim-pickup-order/sql/claimConfig.sql

diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql
index 0609a6a6ab..746e77ffd7 100644
--- a/db/dump/fixtures.sql
+++ b/db/dump/fixtures.sql
@@ -1,7 +1,7 @@
 CREATE SCHEMA IF NOT EXISTS `vn2008`;
 CREATE SCHEMA IF NOT EXISTS `tmp`;
 
-UPDATE `util`.`config` 
+UPDATE `util`.`config`
     SET `environment`= 'test';
 
 ALTER TABLE `vn`.`itemTaxCountry` AUTO_INCREMENT = 1;
@@ -9,11 +9,11 @@ ALTER TABLE `vn`.`address` AUTO_INCREMENT = 1;
 ALTER TABLE `vn`.`zoneGeo` AUTO_INCREMENT = 1;
 ALTER TABLE `vn`.`ticket` AUTO_INCREMENT = 1;
 
-INSERT INTO `salix`.`AccessToken` (`id`, `ttl`, `created`, `userId`) 
-    VALUES 
+INSERT INTO `salix`.`AccessToken` (`id`, `ttl`, `created`, `userId`)
+    VALUES
         ('DEFAULT_TOKEN', '1209600', util.VN_CURDATE(), 66);
 
-INSERT INTO `vn`.`ticketConfig` (`id`, `scopeDays`) 
+INSERT INTO `vn`.`ticketConfig` (`id`, `scopeDays`)
     VALUES
         ('1', '6');
 
@@ -22,11 +22,11 @@ INSERT INTO `vn`.`bionicConfig` (`generalInflationCoeficient`, `minimumDensityVo
         (1.30, 167.00, 138000, 71);
 
 INSERT INTO `vn`.`chatConfig` (`host`, `api`)
-    VALUES    
+    VALUES
         ('https://chat.verdnatura.es', 'https://chat.verdnatura.es/api/v1');
 
-INSERT IGNORE INTO `vn`.`greugeConfig`(`id`, `freightPickUpPrice`) 
-    VALUES 
+INSERT IGNORE INTO `vn`.`greugeConfig`(`id`, `freightPickUpPrice`)
+    VALUES
         ('1', '11');
 
 INSERT INTO `vn`.`packagingConfig`(`upperGap`)
@@ -52,11 +52,11 @@ INSERT INTO `account`.`account`(`id`)
 INSERT INTO `vn`.`educationLevel` (`id`, `name`)
 	VALUES
 		(1, 'ESTUDIOS PRIMARIOS COMPLETOS'),
-		(2, 'ENSEÑANZAS DE BACHILLERATO');    
+		(2, 'ENSEÑANZAS DE BACHILLERATO');
 
 INSERT INTO `vn`.`worker`(`id`,`code`, `firstName`, `lastName`, `userFk`, `bossFk`)
     SELECT id,UPPER(LPAD(role, 3, '0')), name, name, id, 9
-        FROM `vn`.`user`;      
+        FROM `vn`.`user`;
 
 UPDATE `vn`.`worker` SET bossFk = NULL WHERE id = 20;
 UPDATE `vn`.`worker` SET bossFk = 20 WHERE id = 1 OR id = 9;
@@ -69,7 +69,7 @@ INSERT INTO `hedera`.`tpvConfig`(`id`, `currency`, `terminal`, `transactionType`
         (1,	978, 1, 0, 2000, 9, 0);
 
 INSERT INTO `account`.`user`(`id`,`name`,`nickname`, `password`,`role`,`active`,`email`,`lang`, `image`)
-    VALUES 
+    VALUES
         (1101, 'BruceWayne',         'Bruce Wayne',          'ac754a330530832ba1bf7687f577da91', 2, 1, 'BruceWayne@mydomain.com',         'es', 'e7723f0b24ff05b32ed09d95196f2f29'),
         (1102, 'PetterParker',       'Petter Parker',        'ac754a330530832ba1bf7687f577da91', 2, 1, 'PetterParker@mydomain.com',       'en', 'e7723f0b24ff05b32ed09d95196f2f29'),
         (1103, 'ClarkKent',          'Clark Kent',           'ac754a330530832ba1bf7687f577da91', 2, 1, 'ClarkKent@mydomain.com',          'fr', 'e7723f0b24ff05b32ed09d95196f2f29'),
@@ -113,7 +113,7 @@ INSERT INTO `vn`.`worker`(`id`, `code`, `firstName`, `lastName`, `userFk`,`bossF
         (1107, 'ANT', 'Hank'         , 'Pym'   , 1107, 19, 432978107, NULL, 1),
         (1108, 'DCX', 'Charles'      , 'Xavier', 1108, 19, 432978108, 1,    NULL),
         (1109, 'HLK', 'Bruce'        , 'Banner', 1109, 19, 432978109, 1,    2),
-        (1110, 'JJJ', 'Jessica'      , 'Jones' , 1110, 19, 432978110, 2,    1); 
+        (1110, 'JJJ', 'Jessica'      , 'Jones' , 1110, 19, 432978110, 2,    1);
 
 INSERT INTO `vn`.`currency`(`id`, `code`, `name`, `ratio`)
     VALUES
@@ -123,7 +123,7 @@ INSERT INTO `vn`.`currency`(`id`, `code`, `name`, `ratio`)
         (4, 'JPY', 'Yen Japones',   1);
 
 INSERT INTO `vn`.`country`(`id`, `country`, `isUeeMember`, `code`, `currencyFk`, `politicalCountryFk`, `ibanLength`, `continentFk`, `hasDailyInvoice`, `CEE`)
-    VALUES 
+    VALUES
         (1, 'España',   1, 'ES', 1, 1,  24, 4, 0, 1),
         (2, 'Italia',   1, 'IT', 1, 2,  27, 4, 0, 1),
         (3, 'Alemania', 1, 'DE', 1, 3,  22, 4, 0, 1),
@@ -153,19 +153,19 @@ INSERT INTO `vn`.`sector`(`id`, `description`, `warehouseFk`, `isPreviousPrepare
         (1, 'First sector',     1, 1, 'FIRST'),
         (2, 'Second sector',    2, 0, 'SECOND');
 
-INSERT INTO `vn`.`parking` (`id`, `column`, `row`, `sectorFk`, `code`, `pickingOrder`) 
-    VALUES 
+INSERT INTO `vn`.`parking` (`id`, `column`, `row`, `sectorFk`, `code`, `pickingOrder`)
+    VALUES
         ('1', '700', '01', '1', '700-01', '70001'),
         ('2', '700', '02', '2', '700-02', '70002');
 
-INSERT INTO `vn`.`shelving` (`code`, `parkingFk`, `isPrinted`, `priority`, `parked`, `userFk`) 
-    VALUES 
+INSERT INTO `vn`.`shelving` (`code`, `parkingFk`, `isPrinted`, `priority`, `parked`, `userFk`)
+    VALUES
         ('GVC', 1, 0, 1, 0, 1106),
         ('HEJ', 2, 0, 1, 0, 1106),
         ('UXN', 1, 0, 1, 0, 1106);
 
 INSERT INTO `vn`.`accountingType`(`id`, `description`, `receiptDescription`,`code`, `maxAmount`, `daysInFuture`)
-    VALUES 
+    VALUES
         (1,     'CC and credit policies',   'Transfers',        'wireTransfer', NULL, 1),
         (2,     'Cash',                     'Cash',             'cash',         1000, 0),
         (3,     'Credit card',              'Credit Card',      'creditCard',   NULL, 0),
@@ -180,8 +180,8 @@ INSERT INTO `vn`.`bankEntity`(`id`, `countryFk`, `name`, `bic`)
         (128,  1, 'The Best Bank', 'BBKKESMMMMMM'),
         (2100, 1, 'Caixa Bank',    'CAIXESBB');
 
-INSERT INTO `vn`.`bank`(`id`, `bank`, `account`, `cash`, `entityFk`, `isActive`, `currencyFk`) 
-    VALUES 
+INSERT INTO `vn`.`bank`(`id`, `bank`, `account`, `cash`, `entityFk`, `isActive`, `currencyFk`)
+    VALUES
         (1,     'Pay on receipt',           '5720000001', 3, 128,     1, 1),
         (2,     'Cash',                     '5700000001', 2, 128,     1, 1),
         (3,     'Compensation',             '4000000000', 8, 128,     1, 1),
@@ -235,7 +235,7 @@ UPDATE `vn`.`agencyMode` SET `web` = 1, `reportMail` = 'no-reply@gothamcity.com'
 UPDATE `vn`.`agencyMode` SET `code` = 'refund' WHERE  `id` = 23;
 
 INSERT INTO `vn`.`payMethod`(`id`,`code`,  `name`, `graceDays`, `outstandingDebt`, `isIbanRequiredForClients`, `isIbanRequiredForSuppliers`, `hasVerified`)
-    VALUES 
+    VALUES
         (1, NULL,           'PayMethod one',            0,  001,    0, 0, 0),
         (2, NULL,           'PayMethod two',            10, 001,    0, 0, 1),
         (3, 'compensation', 'PayMethod three',          0,  001,    0, 0, 0),
@@ -244,7 +244,7 @@ INSERT INTO `vn`.`payMethod`(`id`,`code`,  `name`, `graceDays`, `outstandingDebt
         (8,'wireTransfer',  'WireTransfer',             5,  001,    1, 1, 0);
 
 INSERT INTO `vn`.`payDem`(`id`, `payDem`)
-    VALUES 
+    VALUES
         (1, 10),
         (2, 20);
 
@@ -273,7 +273,7 @@ INSERT INTO `vn`.`town`(`id`, `name`, `provinceFk`)
         (5, 'Quito',        5);
 
 INSERT INTO `vn`.`postCode`(`code`, `townFk`, `geoFk`)
-    VALUES 
+    VALUES
         ('46000', 1, 6),
         ('46460', 2, 6),
         ('46680', 3, 6),
@@ -481,7 +481,7 @@ INSERT INTO `vn`.`supplierActivity`(`code`, `name`)
         ('complements',  'Other complements'),
         ('flowerPlants',  'Wholesale of flowers and plants'),
         ('vegetablesFruits', 'Fruit and vegetable trade');
-        
+
 INSERT INTO `vn`.`supplier`(`id`, `name`, `nickname`,`account`,`countryFk`,`nif`, `commission`, `created`, `isActive`, `street`, `city`, `provinceFk`, `postCode`, `payMethodFk`, `payDemFk`, `payDay`, `taxTypeSageFk`, `withholdingSageFk`, `transactionTypeSageFk`, `workerFk`, `supplierActivityFk`, `isPayMethodChecked`, `healthRegister`)
     VALUES
         (1,   'Plants SL',             'Plants nick',   4100000001, 1, '06089160W', 0, util.VN_CURDATE(), 1, 'supplier address 1', 'PONTEVEDRA', 1, 15214, 1, 1, 15, 4,  1, 1, 18, 'flowerPlants',  1, '400664487V'),
@@ -498,7 +498,7 @@ INSERT INTO `vn`.`company`(`id`, `code`, `supplierAccountFk`, `workerManagerFk`,
         (442 , 'VNL', 241,  30,  2   , 1, NULL,         2, 'VNL Company - Plant passport'),
         (567 , 'VNH', NULL, 30,  NULL, 4, NULL,         1, 'VNH Company - Plant passport'),
         (791 , 'FTH', NULL, 30,  NULL, 3, '2015-11-30', 1, NULL),
-        (1381, 'ORN', NULL, 30,  NULL, 7, NULL,         1, 'ORN Company - Plant passport');  
+        (1381, 'ORN', NULL, 30,  NULL, 7, NULL,         1, 'ORN Company - Plant passport');
 
 INSERT INTO `vn`.`taxArea` (`code`, `claveOperacionFactura`, `CodigoTransaccion`)
     VALUES
@@ -519,7 +519,7 @@ INSERT INTO `vn`.`invoiceOutSerial` (`code`, `description`, `isTaxed`, `taxAreaF
 INSERT INTO `vn`.`invoiceOut`(`id`, `serial`, `amount`, `issued`,`clientFk`, `created`, `companyFk`, `dued`, `booked`, `bankFk`, `hasPdf`)
     VALUES
         (1, 'T', 1014.24,   util.VN_CURDATE(),                              1101, util.VN_CURDATE(),                              442, util.VN_CURDATE(),                              util.VN_CURDATE(), 1, 0),
-        (2, 'T', 121.36,    util.VN_CURDATE(),                              1102, util.VN_CURDATE(),                              442, util.VN_CURDATE(),                              util.VN_CURDATE(), 1, 0), 
+        (2, 'T', 121.36,    util.VN_CURDATE(),                              1102, util.VN_CURDATE(),                              442, util.VN_CURDATE(),                              util.VN_CURDATE(), 1, 0),
         (3, 'T', 8.88,      util.VN_CURDATE(),                              1103, util.VN_CURDATE(),                              442, util.VN_CURDATE(),                              util.VN_CURDATE(), 1, 0),
         (4, 'T', 8.88,      util.VN_CURDATE(),                              1103, util.VN_CURDATE(),                              442, util.VN_CURDATE(),                              util.VN_CURDATE(), 1, 0),
         (5, 'A', 8.88,      DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 1103, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 442, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 1, 0);
@@ -531,7 +531,7 @@ UPDATE `vn`.`invoiceOut` SET ref = 'T4444444' WHERE id = 4;
 UPDATE `vn`.`invoiceOut` SET ref = 'A1111111' WHERE id = 5;
 
 INSERT INTO `vn`.`invoiceOutTax` (`invoiceOutFk`, `taxableBase`, `vat`, `pgcFk`)
-    VALUES 
+    VALUES
         (1, 895.76, 89.58,  4722000010),
         (1, 33.80,  7.10,   4722000021),
         (2, 110.33, 11.03,  4770000010),
@@ -552,7 +552,7 @@ INSERT INTO `vn`.`expence`(`id`, `taxTypeFk`, `name`, `isWithheld`)
         (7001000000, 1, 'Mercaderia',                       0),
         (7050000000, 1, 'Prestacion de servicios',          1);
 
-        
+
 INSERT INTO `vn`.`invoiceOutExpence`(`id`, `invoiceOutFk`, `amount`, `expenceFk`, `created`)
     VALUES
         (1, 1, 813.06,  2000000000, util.VN_CURDATE()),
@@ -564,7 +564,7 @@ INSERT INTO `vn`.`invoiceOutExpence`(`id`, `invoiceOutFk`, `amount`, `expenceFk`
         (7, 5, 8.07,    2000000000, util.VN_CURDATE());
 
 INSERT INTO `vn`.`zone` (`id`, `name`, `hour`, `agencyModeFk`, `travelingDays`, `price`, `bonus`, `itemMaxSize`)
-    VALUES 
+    VALUES
         (1,  'Zone pickup A',       CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 1,  0, 0,    0, 100),
         (2,  'Zone pickup B',       CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 1,  0, 0,    0, 100),
         (3,  'Zone 247 A',          CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 7,  1, 2,    0, 100),
@@ -580,7 +580,7 @@ INSERT INTO `vn`.`zone` (`id`, `name`, `hour`, `agencyModeFk`, `travelingDays`,
         (13, 'Zone quantum break',  CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 5,  0, 0,    0, 100);
 
 INSERT INTO `vn`.`zoneWarehouse` (`id`, `zoneFk`, `warehouseFk`)
-    VALUES 
+    VALUES
         (1, 1, 1),
         (2, 2, 2),
         (3, 3, 1),
@@ -596,7 +596,7 @@ INSERT INTO `vn`.`zoneWarehouse` (`id`, `zoneFk`, `warehouseFk`)
         (13, 13, 5);
 
 INSERT INTO `vn`.`zoneClosure` (`zoneFk`, `dated`, `hour`)
-    VALUES 
+    VALUES
         (1,     util.VN_CURDATE(), '23:59'),
         (2,     util.VN_CURDATE(), '23:59'),
         (3,     util.VN_CURDATE(), '23:59'),
@@ -668,7 +668,7 @@ INSERT INTO `vn`.`ticketObservation`(`id`, `ticketFk`, `observationTypeFk`, `des
         (11, 24, 4, 'Reclama ticket: 7'),
         (12, 11, 3, 'Delivery after 10am');
 
--- FIX for state hours on local, inter_afterInsert 
+-- FIX for state hours on local, inter_afterInsert
 UPDATE vncontrol.inter SET odbc_date = DATE_ADD(util.VN_CURDATE(), INTERVAL -10 SECOND);
 
 INSERT INTO `vn`.`ticketTracking`(`ticketFk`, `stateFk`, `workerFk`, `created`)
@@ -764,7 +764,7 @@ INSERT INTO `vn`.`itemCategory`(`id`, `name`, `display`, `color`, `icon`, `code`
 INSERT INTO `vn`.`temperature`(`code`, `name`, `description`)
     VALUES
         ('warm', 'Warm', 'Warm'),
-        ('cool', 'Cool', 'Cool');        
+        ('cool', 'Cool', 'Cool');
 
 INSERT INTO `vn`.`itemType`(`id`, `code`, `name`, `categoryFk`, `warehouseFk`, `life`,`workerFk`, `isPackaging`, `temperatureFk`)
     VALUES
@@ -818,7 +818,7 @@ INSERT INTO `vn`.`taxClassCode`(`taxClassFk`, `effectived`, `taxCodeFk`)
         (1, util.VN_CURDATE(), 1),
         (1, util.VN_CURDATE(), 21),
         (2, util.VN_CURDATE(), 2);
-      
+
 INSERT INTO `vn`.`intrastat`(`id`, `description`, `taxClassFk`, `taxCodeFk`)
     VALUES
         (05080000, 'Coral y materiales similares',        2, 2),
@@ -830,7 +830,7 @@ INSERT INTO `vn`.`itemFamily`(`code`, `description`)
         ('SER', 'Services'),
         ('VT',  'Sales');
 
-INSERT INTO `vn`.`item`(`id`, `typeFk`, `size`, `inkFk`, `stems`, `originFk`, `description`, `producerFk`, `intrastatFk`, `expenceFk`, 
+INSERT INTO `vn`.`item`(`id`, `typeFk`, `size`, `inkFk`, `stems`, `originFk`, `description`, `producerFk`, `intrastatFk`, `expenceFk`,
     `comment`, `relevancy`, `image`, `subName`, `minPrice`, `stars`, `family`, `isFloramondo`, `genericFk`, `itemPackingTypeFk`, `hasMinPrice`, `packingShelve`)
     VALUES
         (1,  2, 70,   'YEL', 1,    1, NULL,              1,    06021010, 2000000000, NULL, 0, '1',  NULL, 0, 1, 'VT',   0,  NULL,   'V',  0, 15),
@@ -966,7 +966,7 @@ INSERT INTO `vn`.`saleComponent`(`saleFk`, `componentFk`, `value`)
         (3,     39, 0.994),
         (4,     28, 1.25),
         (4,     29, 0.42),
-        (4,     39, 0.017),     
+        (4,     39, 0.017),
         (5,     17, 9.94),
         (5,     28, 50),
         (5,     29, 49.4),
@@ -988,8 +988,8 @@ INSERT INTO `vn`.`saleComponent`(`saleFk`, `componentFk`, `value`)
         (9,     15, 3.0949),
         (9,     21, 0.001),
         (9,     28, 53),
-        (9,     29, 46.4), 
-        (9,     39, 0.994), 
+        (9,     29, 46.4),
+        (9,     39, 0.994),
         (10,    15, 0.0199),
         (10,    28, 7),
         (10,    29, 0),
@@ -1088,14 +1088,14 @@ INSERT INTO `vn`.`saleComponent`(`saleFk`, `componentFk`, `value`)
         (32,    36, -92.324),
         (32,    39, 0.994);
 
-INSERT INTO `vn`.`itemShelving` (`itemFk`, `shelvingFk`, `shelve`, `visible`, `grouping`, `packing`, `userFk`) 
-    VALUES 
+INSERT INTO `vn`.`itemShelving` (`itemFk`, `shelvingFk`, `shelve`, `visible`, `grouping`, `packing`, `userFk`)
+    VALUES
         (2, 'GVC', 'A', 1, 1, 1, 1106),
         (4, 'HEJ', 'A', 1, 1, 1, 1106),
         (1, 'UXN', 'A', 2, 12, 12, 1106);
 
-INSERT INTO `vn`.`itemShelvingSale` (`itemShelvingFk`, `saleFk`, `quantity`, `created`, `userFk`) 
-    VALUES 
+INSERT INTO `vn`.`itemShelvingSale` (`itemShelvingFk`, `saleFk`, `quantity`, `created`, `userFk`)
+    VALUES
         ('1', '1', '1', '', '1106'),
         ('2', '2', '5', '', '1106'),
         ('1', '7', '1', '', '1106'),
@@ -1137,8 +1137,8 @@ INSERT INTO `vn`.`ticketCollection`(`ticketFk`, `collectionFk`, `level`)
         (3, 2, NULL),
         (23, 1, NULL);
 
-INSERT INTO `vn`.`parking` (`column`, `row`, `sectorFk`, `code`, `pickingOrder`) 
-    VALUES 
+INSERT INTO `vn`.`parking` (`column`, `row`, `sectorFk`, `code`, `pickingOrder`)
+    VALUES
         ('100', '01', 1, '100-01', 1);
 
 INSERT INTO `vn`.`genus`(`id`, `name`)
@@ -1292,7 +1292,7 @@ INSERT INTO `vn`.`itemTypeTag`(`id`, `itemTypeFk`, `tagFk`, `priority`)
 CALL `vn`.`itemRefreshTags`(NULL);
 
 INSERT INTO `vn`.`itemLog` (`id`, `originFk`, `userFk`, `action`, `description`)
-    VALUES 
+    VALUES
         ('1', '1', '1', 'insert', 'We made a change!');
 
 INSERT INTO `vn`.`recovery`(`id`, `clientFk`, `started`, `finished`, `amount`, `period`)
@@ -1484,8 +1484,8 @@ INSERT INTO `hedera`.`orderRowComponent`(`rowFk`, `componentFk`, `price`)
         (4,     21, -0.001),
         (4,     28, 20.72),
         (4,     29, -19.72),
-        (4,     37, 2),  
-        (4,     39, 0.01),  
+        (4,     37, 2),
+        (4,     39, 0.01),
         (5,     15, 0.58),
         (5,     23, 6.5),
         (5,     28, 20.72),
@@ -1704,7 +1704,7 @@ INSERT INTO `vn`.`workerManaExcluded`(`workerFk`)
  La otra manera es poner el calculo con los 2 trabajadores que utilizamos ahora mismo para los tickets
 */
 
-call vn.manaSpellersRequery(19);  
+call vn.manaSpellersRequery(19);
 call vn.manaSpellersRequery(18);
 
 INSERT INTO `vn`.`clientSample`(`id`, `clientFk`, `typeFk`, `created`, `workerFk`, `userFk`, `companyFk`)
@@ -1772,8 +1772,8 @@ INSERT INTO `hedera`.`tpvMerchant`(`id`, `description`, `companyFk`, `bankFk`, `
         (1, 'Arkham Bank',  442, 1, 'h12387193H10238'),
         (2, 'NewYork Bank', 442, 1, '7981ugsgd1hsdad');
 
-INSERT INTO `hedera`.`tpvTransaction`(`id`,`merchantFk`, `clientFk`,`receiptFk`, `amount`, `response`, `errorCode`, `status`, `created`) 
-    VALUES 
+INSERT INTO `hedera`.`tpvTransaction`(`id`,`merchantFk`, `clientFk`,`receiptFk`, `amount`, `response`, `errorCode`, `status`, `created`)
+    VALUES
         (1, 1, 1101, NULL, 2000, NULL, 'SIS0042',    'ok',       util.VN_CURDATE()),
         (2, 1, 1101, NULL, 1000, NULL, 'SIS0051',    'started',  util.VN_CURDATE()),
         (3, 2, 1101, NULL, 7268, NULL, NULL,         'ok',       util.VN_CURDATE()),
@@ -1787,32 +1787,32 @@ INSERT INTO `vn`.`orderTicket`(`orderFk`, `ticketFk`)
         (2,  2),
         (3,  3),
         (4,  4),
-        (5,  5), 
-        (6,  6), 
-        (7,  7), 
-        (8,  8), 
-        (9,  9), 
-        (10, 10), 
-        (11, 11), 
-        (12, 12), 
-        (13, 13), 
-        (14, 14), 
+        (5,  5),
+        (6,  6),
+        (7,  7),
+        (8,  8),
+        (9,  9),
+        (10, 10),
+        (11, 11),
+        (12, 12),
+        (13, 13),
+        (14, 14),
         (15, 15),
         (16, 16),
         (17, 17),
         (18, 18),
         (19, 19),
-        (20, 20), 
-        (21, 21), 
+        (20, 20),
+        (21, 21),
         (22, 22);
 
-INSERT INTO `vn`.`userConfig` (`userFk`, `warehouseFk`, `companyFk`) 
+INSERT INTO `vn`.`userConfig` (`userFk`, `warehouseFk`, `companyFk`)
     VALUES
         (1,  1, 69),
-        (5,  1, 442), 
+        (5,  1, 442),
         (9,  1, 442),
         (18, 3, 567);
- 
+
 INSERT INTO `vn`.`receipt`(`id`, `invoiceFk`, `amountPaid`, `payed`, `workerFk`, `bankFk`, `clientFk`, `created`, `companyFk`, `isConciliate`)
     VALUES
         (1, 'Cobro web',            100.50, util.VN_CURDATE(),                             9, 1, 1101, util.VN_CURDATE(),                             442, 1),
@@ -1895,14 +1895,14 @@ INSERT INTO `postgresql`.`business_labour` (`business_id`, `notes`, `department_
     VALUES
         (1111, NULL, 23, 1, 0.0, 1, 1, 1, 1);
 
-UPDATE `postgresql`.`business_labour` bl 
+UPDATE `postgresql`.`business_labour` bl
     JOIN `postgresql`.`business` b ON b.business_id = bl.business_id
     JOIN `postgresql`.`profile` pr ON pr.profile_id = b.client_id
     JOIN `postgresql`.`person` p ON p.person_id = pr.person_id
     SET bl.`professional_category_id` = 31
     WHERE p.`Id_trabajador` = 1110;
 
-UPDATE `postgresql`.`business_labour` bl 
+UPDATE `postgresql`.`business_labour` bl
     SET bl.`department_id` = 43
 WHERE business_id IN(18, 19);
 
@@ -1917,18 +1917,18 @@ INSERT INTO `postgresql`.`profile_media`(`profile_media_id`, `profile_id`, `medi
         (2, 1107, 2);
 
 INSERT INTO `vn`.`workCenterHoliday` (`workCenterFk`, `days`, `year`)
-    VALUES 
+    VALUES
         ('1', '27.5', YEAR(util.VN_CURDATE())),
         ('5', '22', YEAR(util.VN_CURDATE())),
-        ('1', '24.5', YEAR(DATE_ADD(util.VN_CURDATE(), INTERVAL -1 YEAR))), 
+        ('1', '24.5', YEAR(DATE_ADD(util.VN_CURDATE(), INTERVAL -1 YEAR))),
         ('5', '23', YEAR(DATE_ADD(util.VN_CURDATE(), INTERVAL -1 YEAR)));
 
-INSERT INTO `vn`.`absenceType` (`id`, `name`, `rgb`, `code`, `holidayEntitlementRate`, `discountRate`) 
-    VALUES 
+INSERT INTO `vn`.`absenceType` (`id`, `name`, `rgb`, `code`, `holidayEntitlementRate`, `discountRate`)
+    VALUES
         (1,  'Holidays',            '#FF4444', 'holiday',       0,      0),
         (2,  'Leave of absence',    '#C71585', 'absence',       0,      1),
         (6,  'Half holiday',        '#E65F00', 'halfHoliday',   0,      0.5),
-        (15, 'Half Paid Leave',     '#5151c0', 'halfPaidLeave', 0,      1),        
+        (15, 'Half Paid Leave',     '#5151c0', 'halfPaidLeave', 0,      1),
         (20, 'Furlough',            '#97B92F', 'furlough',      1,      1),
         (21, 'Furlough half day',   '#778899', 'halfFurlough',  0.5,    1);
 
@@ -1945,10 +1945,10 @@ INSERT INTO `postgresql`.`business_labour_payroll` (`business_id`, `cod_tarifa`,
         (1, 7, 12, 100, 900.50),
         (1106, 7, 12, 100, 1263.03),
         (1107, 7, 12, 100, 2000),
-        (1108, 7, 12, 100, 1500);       
+        (1108, 7, 12, 100, 1500);
 
-INSERT INTO `postgresql`.`calendar_employee` (`business_id`, `calendar_state_id`, `date`) 
-    VALUES 
+INSERT INTO `postgresql`.`calendar_employee` (`business_id`, `calendar_state_id`, `date`)
+    VALUES
         (1,    6, IF(MONTH(util.VN_CURDATE()) = 12 AND DAY(util.VN_CURDATE()) > 10, DATE_ADD(util.VN_CURDATE(), INTERVAL -10 DAY), DATE_ADD(util.VN_CURDATE(), INTERVAL 10 DAY))),
         (1106, 1, IF(MONTH(util.VN_CURDATE()) = 12 AND DAY(util.VN_CURDATE()) > 10, DATE_ADD(util.VN_CURDATE(), INTERVAL -10 DAY), DATE_ADD(util.VN_CURDATE(), INTERVAL 10 DAY))),
         (1106, 1, IF(MONTH(util.VN_CURDATE()) = 12 AND DAY(util.VN_CURDATE()) > 10, DATE_ADD(util.VN_CURDATE(), INTERVAL -11 DAY), DATE_ADD(util.VN_CURDATE(), INTERVAL 11 DAY))),
@@ -1966,8 +1966,8 @@ INSERT INTO `postgresql`.`calendar_employee` (`business_id`, `calendar_state_id`
         (1107, 2, IF(MONTH(util.VN_CURDATE()) >= 1 AND DAY(util.VN_CURDATE()) > 20, DATE_ADD(util.VN_CURDATE(), INTERVAL -15 DAY), DATE_ADD(util.VN_CURDATE(), INTERVAL 7  DAY))),
         (1107, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL - 16 DAY));
 
-INSERT INTO `vn`.`smsConfig` (`id`, `uri`, `title`, `apiKey`) 
-    VALUES 
+INSERT INTO `vn`.`smsConfig` (`id`, `uri`, `title`, `apiKey`)
+    VALUES
         ('1', 'https://api.gateway360.com/api/3.0/sms/send', 'Verdnatura', '5715476da95b46d686a5a255e6459523');
 
 INSERT INTO `vn`.`sharingClient`(`id`, `workerFk`, `started`, `ended`, `clientFk`)
@@ -1983,37 +1983,37 @@ CALL `vn`.zoneGeo_calcTree(); -- this is an auto calculate for table vn.zoneGeo,
 
 INSERT INTO `vn`.`zoneIncluded` (`zoneFk`, `geoFk`, `isIncluded`)
     VALUES
-        (1, 3,   0), 
-        (1, 4,   0), 
-        (1, 5,   0), 
+        (1, 3,   0),
+        (1, 4,   0),
+        (1, 5,   0),
         (1, 1,   1),
-        (2, 3,   0), 
-        (2, 4,   0), 
-        (2, 5,   0), 
+        (2, 3,   0),
+        (2, 4,   0),
+        (2, 5,   0),
         (2, 1,   1),
-        (3, 3,   0), 
-        (3, 4,   0), 
-        (3, 5,   0),  
+        (3, 3,   0),
+        (3, 4,   0),
+        (3, 5,   0),
         (3, 1,   1),
-        (4, 3,   0), 
-        (4, 4,   0), 
-        (4, 5,   0),  
+        (4, 3,   0),
+        (4, 4,   0),
+        (4, 5,   0),
         (4, 1,   1),
-        (5, 3,   1), 
-        (5, 4,   0), 
-        (5, 5,   1), 
+        (5, 3,   1),
+        (5, 4,   0),
+        (5, 5,   1),
         (5, 1,   1),
-        (6, 3,   1), 
-        (6, 4,   0), 
-        (6, 5,   1), 
+        (6, 3,   1),
+        (6, 4,   0),
+        (6, 5,   1),
         (6, 1,   1),
-        (7, 3,   0), 
-        (7, 4,   0), 
-        (7, 5,   0), 
+        (7, 3,   0),
+        (7, 4,   0),
+        (7, 5,   0),
         (7, 1,   1),
-        (8, 3,   0), 
-        (8, 4,   0), 
-        (8, 5,   0), 
+        (8, 3,   0),
+        (8, 4,   0),
+        (8, 5,   0),
         (8, 1,   1),
         (10, 14, 1);
 
@@ -2226,12 +2226,12 @@ INSERT INTO `vn`.`zoneEvent`(`zoneFk`, `type`, `dated`)
         (7, 'day', DATE_ADD(util.VN_CURDATE(), INTERVAL +6 DAY));
 
 INSERT INTO `vn`.`zoneEvent`(`zoneFk`, `type`, `weekDays`)
-    VALUES 
+    VALUES
         (8, 'indefinitely', 'mon,tue,wed,thu,fri,sat,sun'),
         (10, 'indefinitely', 'mon,tue,wed,thu,fri,sat,sun');
 
 INSERT INTO `vn`.`zoneEvent`(`zoneFk`, `type`, `started`, `ended`)
-    VALUES 
+    VALUES
         (9, 'range', DATE_ADD(util.VN_CURDATE(), INTERVAL -1 YEAR), DATE_ADD(util.VN_CURDATE(), INTERVAL +1 YEAR));
 
 INSERT INTO `vn`.`workerTimeControl`(`userFk`, `timed`, `manual`, `direction`)
@@ -2294,8 +2294,8 @@ INSERT INTO `vn`.`workerDocument`(`id`, `worker`, `document`,`isReadableByWorker
         (1, 1106, 4, TRUE),
         (2, 1107, 3, FALSE);
 
-INSERT INTO `vn`.`device` (`sn`, `model`, `userFk`) 
-    VALUES 
+INSERT INTO `vn`.`device` (`sn`, `model`, `userFk`)
+    VALUES
         ('aaa', 'android', '9');
 
 INSERT INTO `vn`.`queuePriority`(`id`, `priority`)
@@ -2309,7 +2309,7 @@ INSERT INTO `vn`.`workerTimeControlParams` (`id`, `dayBreak`, `weekBreak`, `week
         (1, 43200, 129600, 734400, 43200, 50400, 259200, 1296000, 36000);
 
 INSERT IGNORE INTO `vn`.`greugeConfig` (`id`, `freightPickUpPrice`) VALUES ('1', '11');
-        
+
 INSERT INTO `vn`.`thermograph`(`id`, `model`)
     VALUES
         ('TMM190901395',    'TEMPMATE'),
@@ -2327,21 +2327,21 @@ INSERT INTO `vn`.`travelThermograph`(`thermographFk`, `created`, `warehouseFk`,
         ('138350-0',        DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 1, 1,       'WARM', NULL,                           5),
         ('138350-0',        util.VN_CURDATE(),                              1, NULL,    'COOL', NULL,                           NULL);
 
-REPLACE INTO `vn`.`incoterms`(`code`, `name`) 
-    VALUES 
+REPLACE INTO `vn`.`incoterms`(`code`, `name`)
+    VALUES
         ('FAS', 'Free Alongside Ship');
 
-REPLACE INTO `vn`.`customsAgent`(`id`, `fiscalName`, `street`, `nif`, `phone`, `email`) 
-    VALUES 
+REPLACE INTO `vn`.`customsAgent`(`id`, `fiscalName`, `street`, `nif`, `phone`, `email`)
+    VALUES
         (1, 'Agent one', '1007 Mountain Drive, Gotham', 'N1111111111', '111111111', 'agentone@gotham.com'),
         (2, 'Agent two', '1007 Mountain Drive, Gotham', 'N2222222222', '222222222', 'agenttwo@gotham.com');
 
-INSERT INTO `vn`.`tablet`(`uuid`, `name`, `place`, `macwifi`) 
-    VALUES 
+INSERT INTO `vn`.`tablet`(`uuid`, `name`, `place`, `macwifi`)
+    VALUES
         ('1', 'TEST', 'ON THE FIXTURES', '0'),
         ('2', 'DEV', 'OTHER TABLET', '0');
 
-INSERT INTO `vn`.`tabletDepartment`(`tabletFk`, `departmentFk`) 
+INSERT INTO `vn`.`tabletDepartment`(`tabletFk`, `departmentFk`)
     VALUES
         (1, 23),
         (2, 1);
@@ -2374,8 +2374,8 @@ INSERT INTO `vn`.`rate`(`dated`, `warehouseFk`, `rate0`, `rate1`, `rate2`, `rate
         (DATE_ADD(util.VN_CURDATE(), INTERVAL -1 YEAR), 1, 10, 15, 20, 25),
         (util.VN_CURDATE(), 1, 12, 17, 22, 27);
 
-INSERT INTO `vn`.`awb` (id, code, package, weight, created, amount, transitoryFk, taxFk) 
-    VALUES 
+INSERT INTO `vn`.`awb` (id, code, package, weight, created, amount, transitoryFk, taxFk)
+    VALUES
         (1,     '07546501420', 67,  671,    util.VN_CURDATE(),  1761, 1, 1),
         (2,     '07546491421', 252, 2769,   util.VN_CURDATE(),  5231, 1, 1),
         (3,     '07546500823', 102, 1495,   util.VN_CURDATE(),  3221, 1, 1),
@@ -2387,8 +2387,8 @@ INSERT INTO `vn`.`awb` (id, code, package, weight, created, amount, transitoryFk
         (9,     '99610289193', 302, 2972,   util.VN_CURDATE(),  3871, 442, 1),
         (10,    '07546500856', 185, 2364,   util.VN_CURDATE(),  5321, 442, 1);
 
-INSERT INTO `vn`.`dua` (id, code, awbFk, issued, operated, booked, bookEntried, gestdocFk, customsValue, companyFk) 
-    VALUES 
+INSERT INTO `vn`.`dua` (id, code, awbFk, issued, operated, booked, bookEntried, gestdocFk, customsValue, companyFk)
+    VALUES
         (1,  '19ES0028013A481523', 1,  util.VN_CURDATE(), util.VN_CURDATE(), util.VN_CURDATE(), util.VN_CURDATE(), 1, 11276.95,   442),
         (2,  '21ES00280136115760', 2,  util.VN_CURDATE(), util.VN_CURDATE(), util.VN_CURDATE(), util.VN_CURDATE(), 2, 1376.20,    442),
         (3,  '19ES00280131956004', 3,  util.VN_CURDATE(), util.VN_CURDATE(), util.VN_CURDATE(), util.VN_CURDATE(), 3, 14268.50,   442),
@@ -2435,8 +2435,8 @@ INSERT INTO `vn`.`duaInvoiceIn`(`id`, `duaFk`, `invoiceInFk`)
         (4,  4,  4),
         (5,  5,  5),
         (6,  6,  6),
-        (7,  7,  7),	
-        (8,  8,  8),	
+        (7,  7,  7),
+        (8,  8,  8),
         (9,  9,  9),
         (10, 10, 10);
 
@@ -2446,7 +2446,7 @@ INSERT INTO `vn`.`invoiceInTax` (`invoiceInFk`, `taxableBase`, `expenceFk`, `for
         (2, 999.99, '2000000000', null, null, null),
         (3, 1000.50, '2000000000', null, null, null),
         (4, 0.50, '2000000000', null, null, null),
-        (5, 150.50, '2000000000', null, null, null),    
+        (5, 150.50, '2000000000', null, null, null),
         (1, 252.25, '4751000000', NULL, 7, 61),
         (2, 223.17, '6210000567', NULL, 8, 20),
         (3, 95.60,  '7001000000', NULL, 8, 35),
@@ -2461,9 +2461,9 @@ INSERT INTO `vn`.`invoiceInIntrastat` (`invoiceInFk`, `net`, `intrastatFk`, `amo
         (1, 10,    6021010, 20.00, 205, 5),
         (2, 13.20, 5080000, 15.00, 580, 5),
         (2, 16.10, 6021010, 25.00, 80,  5);
-   
+
 INSERT INTO `vn`.`ticketRecalc`(`ticketFk`)
-    SELECT `id` 
+    SELECT `id`
         FROM `vn`.`ticket` t
             LEFT JOIN vn.ticketRecalc tr ON tr.ticketFk = t.id
         WHERE tr.ticketFk IS NULL;
@@ -2478,7 +2478,7 @@ INSERT INTO `vn`.`zoneAgencyMode`(`id`, `agencyModeFk`, `zoneFk`)
         (4,  7,  1);
 
 INSERT INTO `vn`.`expeditionTruck` (`id`, `ETD`, `description`)
-    VALUES 
+    VALUES
         (1, CONCAT(YEAR(DATE_ADD(util.VN_CURDATE(), INTERVAL +3 YEAR))), 'Best truck in fleet');
 
 INSERT INTO `vn`.`expeditionPallet` (`id`, `truckFk`, `built`, `position`, `isPrint`)
@@ -2486,7 +2486,7 @@ INSERT INTO `vn`.`expeditionPallet` (`id`, `truckFk`, `built`, `position`, `isPr
         (1, 1, util.VN_CURDATE(), 1, 1);
 
 INSERT INTO `vn`.`expeditionScan` (`id`, `expeditionFk`, `scanned`, `palletFk`)
-    VALUES 
+    VALUES
         (1,     1,  util.VN_CURDATE(), 1),
         (2,     2,  util.VN_CURDATE(), 1),
         (3,     3,  util.VN_CURDATE(), 1),
@@ -2521,7 +2521,7 @@ UPDATE `vn`.`route`
 INSERT INTO `bs`.`salesPerson` (`workerFk`, `year`, `month`, `portfolioWeight`)
     VALUES
         (18,     YEAR(util.VN_CURDATE()),    MONTH(util.VN_CURDATE()),  807.23),
-        (19,     YEAR(util.VN_CURDATE()),    MONTH(util.VN_CURDATE()),  34.40);      
+        (19,     YEAR(util.VN_CURDATE()),    MONTH(util.VN_CURDATE()),  34.40);
 
 INSERT INTO `bs`.`sale` (`saleFk`, `amount`, `dated`,  `typeFk`, `clientFk`)
     VALUES
@@ -2550,14 +2550,14 @@ INSERT INTO `vn`.`calendarHolidaysType` (`id`, `name`, `hexColour`)
 INSERT INTO `vn`.`calendarHolidays` (`id`, `calendarHolidaysTypeFk`, `dated`, `calendarHolidaysNameFk`, `workCenterFk`)
     VALUES
         (1,     1,  CONCAT(YEAR(util.VN_CURDATE()), '-12-09'),      1,      1);
-        
+
 INSERT INTO `vn`.`supplierAgencyTerm` (`agencyFk`, `supplierFk`, `minimumPackages`, `kmPrice`, `packagePrice`, `routePrice`, `minimumKm`, `minimumM3`, `m3Price`)
     VALUES
         (1, 1,   0,  0.00,  0.00,   NULL, 0,  0.00, 23),
         (2, 1,   60, 0.00,  0.00,   NULL, 0,  5.00, 33),
         (3, 2,   0,  15.00, 0.00,   NULL, 0,  0.00, 0),
         (4, 2,   0,  20.00, 0.00,   NULL, 0,  0.00, 0),
-        (5, 442, 0,  0.00, 3.05,    NULL, 0,  0.00, 0);    
+        (5, 442, 0,  0.00, 3.05,    NULL, 0,  0.00, 0);
 
 INSERT INTO `vn`.`chat` (`senderFk`, `recipient`, `dated`, `checkUserStatus`, `message`, `status`, `attempts`)
     VALUES
@@ -2607,7 +2607,7 @@ INSERT INTO `vn`.`sectorCollection` (`userFk`, `sectorFk`)
 INSERT INTO `vn`.`sectorCollectionSaleGroup` (`sectorCollectionFk`, `saleGroupFk`)
     VALUES
         (1, 1);
-        
+
 INSERT INTO `vn`.`workerTimeControlConfig` (`id`, `dayBreak`, `dayBreakDriver`, `shortWeekBreak`, `longWeekBreak`, `weekScope`, `mailPass`, `mailHost`, `mailSuccessFolder`, `mailErrorFolder`, `mailUser`, `minHoursToBreak`, `breakHours`, `hoursCompleteWeek`, `startNightlyHours`, `endNightlyHours`, `maxTimePerDay`, `breakTime`, `timeToBreakTime`, `dayMaxTime`, `shortWeekDays`, `longWeekDays`)
     VALUES
-        (1, 43200, 32400, 129600, 259200, 604800, '', '', 'Leidos.exito', 'Leidos.error', 'timeControl', 5.33, 0.33, 40, '22:00:00', '06:00:00', 57600, 1200, 18000, 57600, 6, 13);
\ No newline at end of file
+        (1, 43200, 32400, 129600, 259200, 604800, '', '', 'Leidos.exito', 'Leidos.error', 'timeControl', 5.33, 0.33, 40, '22:00:00', '06:00:00', 57600, 1200, 18000, 57600, 6, 13);
diff --git a/modules/claim/front/basic-data/index.html b/modules/claim/front/basic-data/index.html
index 7a91e180a4..16e134c60a 100644
--- a/modules/claim/front/basic-data/index.html
+++ b/modules/claim/front/basic-data/index.html
@@ -19,7 +19,7 @@
                 readonly="true">
             </vn-textfield>
             <vn-textfield
-                label="Created" 
+                label="Created"
                 field="::$ctrl.claim.created | date:'yyyy-MM-dd HH:mm'"
                 readonly="true">
             </vn-textfield>
@@ -56,7 +56,7 @@
                 label="Pick up"
                 ng-model="$ctrl.claim.hasToPickUp"
                 vn-acl="claimManager"
-                info="When checked will notify to the salesPerson">
+                title="{{'When checked will notify to the salesPerson' | translate}}">
             </vn-check>
         </vn-horizontal>
     </vn-card>
diff --git a/modules/claim/front/basic-data/locale/es.yml b/modules/claim/front/basic-data/locale/es.yml
index c51afee3fb..5250d266c6 100644
--- a/modules/claim/front/basic-data/locale/es.yml
+++ b/modules/claim/front/basic-data/locale/es.yml
@@ -5,5 +5,5 @@ Responsability: Responsabilidad
 Company: Empresa
 Sales/Client: Comercial/Cliente
 Pick up: Recoger
-When checked will notify a pickup to the salesPerson: Cuando se marque enviará una notificación de recogida al comercial
-Packages received: Bultos recibidos
\ No newline at end of file
+When checked will notify to the salesPerson: Cuando se marque enviará una notificación de recogida al comercial
+Packages received: Bultos recibidos
diff --git a/modules/claim/front/descriptor/index.js b/modules/claim/front/descriptor/index.js
index 674ac91e19..bb406ff795 100644
--- a/modules/claim/front/descriptor/index.js
+++ b/modules/claim/front/descriptor/index.js
@@ -19,9 +19,10 @@ class Controller extends Descriptor {
 
     sendPickupOrder() {
         return this.vnEmail.send('claim-pickup-order', {
-            recipient: this.claim.client.email,
+            recipient: 'alexm@verdnatura.es',
             recipientId: this.claim.clientFk,
-            claimId: this.claim.id
+            claimId: this.claim.id,
+            ticketId: this.claim.ticketFk
         });
     }
 
diff --git a/modules/claim/front/summary/index.html b/modules/claim/front/summary/index.html
index 0c12aa2e64..fc1813467a 100644
--- a/modules/claim/front/summary/index.html
+++ b/modules/claim/front/summary/index.html
@@ -34,6 +34,15 @@
                 label="State"
                 value="{{$ctrl.summary.claim.claimState.description}}">
             </vn-label-value>
+            <vn-check
+                class="vn-mr-md"
+                label="Pick up"
+                ng-model="$ctrl.summary.claim.hasToPickUp"
+                title="{{'When checked will notify to the salesPerson' | translate}}"
+                disabled="true">
+            </vn-check>
+        </vn-one>
+        <vn-one>
             <vn-label-value
                 label="Salesperson"
                 value="{{$ctrl.summary.claim.client.salesPersonUser.name}}">
@@ -45,13 +54,13 @@
         </vn-one>
         <vn-auto>
             <h4 ng-show="$ctrl.isSalesPerson && $ctrl.summary.observations.length">
-                <a 
+                <a
                     ui-sref="claim.card.note.index({id:$ctrl.claim.id})"
                     target="_self">
                     <span translate vn-tooltip="Go to">Observations</span>
                 </a>
             </h4>
-            <h4 
+            <h4
                 ng-show="!$ctrl.isSalesPerson && $ctrl.summary.observations.length"
                 translate>
                 Observations
@@ -70,13 +79,13 @@
         </vn-auto>
         <vn-auto>
             <h4 ng-show="$ctrl.isSalesPerson">
-                <a 
+                <a
                     ui-sref="claim.card.detail({id:$ctrl.claim.id})"
                     target="_self">
                     <span translate vn-tooltip="Go to">Detail</span>
                 </a>
             </h4>
-            <h4 
+            <h4
                 ng-show="!$ctrl.isSalesPerson"
                 translate>
                 Detail
@@ -98,7 +107,7 @@
                     <vn-tbody>
                         <vn-tr ng-repeat="saleClaimed in $ctrl.summary.salesClaimed">
                             <vn-td number>
-                                <span 
+                                <span
                                     ng-click="itemDescriptor.show($event, saleClaimed.sale.itemFk, saleClaimed.sale.id)"
                                     class="link">
                                     {{::saleClaimed.sale.itemFk | zeroFill:6}}
@@ -111,7 +120,7 @@
                             <vn-td number>{{::saleClaimed.sale.price | currency: 'EUR':2}}</vn-td>
                             <vn-td number>{{::saleClaimed.sale.discount}} %</vn-td>
                             <vn-td number>
-                                {{saleClaimed.sale.quantity * saleClaimed.sale.price * 
+                                {{saleClaimed.sale.quantity * saleClaimed.sale.price *
                                     ((100 - saleClaimed.sale.discount) / 100) | currency: 'EUR':2}}
                             </vn-td>
                         </vn-tr>
@@ -123,7 +132,7 @@
             <h4 translate>Photos</h4>
             <vn-horizontal class="photo-list">
                 <section class="photo" ng-repeat="photo in photos">
-                    <section class="image" on-error-src 
+                    <section class="image" on-error-src
                         ng-style="{'background': 'url(' + $ctrl.getImagePath(photo.dmsFk) + ')'}"
                         zoom-image="{{$ctrl.getImagePath(photo.dmsFk)}}"
                         ng-if="photo.dms.contentType != 'video/mp4'">
@@ -137,13 +146,13 @@
         </vn-auto>
         <vn-auto>
             <h4 ng-show="$ctrl.isClaimManager">
-                <a 
+                <a
                     ui-sref="claim.card.development({id:$ctrl.claim.id})"
                     target="_self">
                     <span translate vn-tooltip="Go to">Development</span>
                 </a>
             </h4>
-            <h4 
+            <h4
                 translate
                 ng-show="!$ctrl.isClaimManager">
                 Development
@@ -165,8 +174,8 @@
                             <vn-td>{{::development.claimResult.description}}</vn-td>
                             <vn-td>{{::development.claimResponsible.description}}</vn-td>
                             <vn-td expand>
-                                <span 
-                                    class="link" 
+                                <span
+                                    class="link"
                                     ng-click="workerDescriptor.show($event, development.workerFk)">
                                     {{::development.worker.user.nickname}}
                                 </span>
@@ -179,21 +188,21 @@
         </vn-auto>
         <vn-auto>
             <h4 ng-show="$ctrl.isClaimManager">
-                <a 
+                <a
                     ui-sref="claim.card.action({id:$ctrl.claim.id})"
                     target="_self">
                     <span translate vn-tooltip="Go to">Action</span>
                 </a>
             </h4>
             <h4
-                translate 
+                translate
                 ng-show="!$ctrl.isClaimManager">
                 Action
             </h4>
             <vn-horizontal>
                 <vn-one>
                     <vn-range
-                        vn-one 
+                        vn-one
                         disabled="true"
                         label="Responsability"
                         min-label="Company"
@@ -224,14 +233,14 @@
                     <vn-tbody>
                         <vn-tr ng-repeat="action in $ctrl.summary.actions">
                             <vn-td number>
-                                <span 
+                                <span
                                     ng-click="itemDescriptor.show($event, action.sale.itemFk, action.sale.id)"
                                     class="link">
                                     {{::action.sale.itemFk | zeroFill:6}}
                                 </span>
                             </vn-td>
                             <vn-td number>
-                                <span 
+                                <span
                                     ng-click="ticketDescriptor.show($event, action.sale.ticket.id)"
                                     class="link">
                                     {{::action.sale.ticket.id}}
@@ -258,9 +267,9 @@
     vn-id="item-descriptor"
     warehouse-fk="$ctrl.vnConfig.warehouseFk">
 </vn-item-descriptor-popover>
-<vn-worker-descriptor-popover 
+<vn-worker-descriptor-popover
     vn-id="worker-descriptor">
 </vn-worker-descriptor-popover>
-<vn-ticket-descriptor-popover 
+<vn-ticket-descriptor-popover
     vn-id="ticket-descriptor">
-</vn-ticket-descriptor-popover>
\ No newline at end of file
+</vn-ticket-descriptor-popover>
diff --git a/print/templates/email/claim-pickup-order/claim-pickup-order.html b/print/templates/email/claim-pickup-order/claim-pickup-order.html
index f674dcee8b..e6e74ed939 100644
--- a/print/templates/email/claim-pickup-order/claim-pickup-order.html
+++ b/print/templates/email/claim-pickup-order/claim-pickup-order.html
@@ -23,9 +23,10 @@
                         <!-- Block -->
                         <div class="grid-row">
                             <div class="grid-block vn-pa-ml">
-                                <h1>{{ $t('title') }}</h1>
-                                <p>{{$t('description.dear')}},</p>
-                                <p>{{$t('description.instructions')}}</p>
+                                <h1>{{ $t('title', [claimId]) }}</h1>
+                                <p>{{ $t('description.dear') }},</p>
+                                <p v-html="instructions"></p>
+                                <p>{{ $t('description.conclusion') }}</p>
                             </div>
                         </div>
                         <!-- Footer block -->
@@ -43,4 +44,4 @@
             </tbody>
         </table>
     </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/print/templates/email/claim-pickup-order/claim-pickup-order.js b/print/templates/email/claim-pickup-order/claim-pickup-order.js
index cf4ba7d123..220a72dc33 100755
--- a/print/templates/email/claim-pickup-order/claim-pickup-order.js
+++ b/print/templates/email/claim-pickup-order/claim-pickup-order.js
@@ -8,10 +8,22 @@ module.exports = {
         'email-header': emailHeader.build(),
         'email-footer': emailFooter.build()
     },
+    created() {
+        this.instructions = this.$t('description.instructions', [this.claimId, this.ticketId]);
+    },
+    data() {
+        return {
+            instructions: String
+        };
+    },
     props: {
         claimId: {
             type: [Number, String],
             required: true
+        },
+        ticketId: {
+            type: [Number, String],
+            required: true
         }
     }
 };
diff --git a/print/templates/email/claim-pickup-order/locale/es.yml b/print/templates/email/claim-pickup-order/locale/es.yml
index fe08fb0a8a..9ff30158e2 100644
--- a/print/templates/email/claim-pickup-order/locale/es.yml
+++ b/print/templates/email/claim-pickup-order/locale/es.yml
@@ -1,5 +1,10 @@
-subject: Orden de recogida
-title: Orden de recogida
+subject: Reclamación Verdnatura
+title: Reclamación Verdnatura {0}
 description:
-  dear: Estimado cliente
-  instructions: Aqui tienes tu orden de recogida.
\ No newline at end of file
+    dear: Estimado cliente
+    instructions: 'Le informamos que se ha aceptado su solicitud de reclamación <strong>nº {0}</strong> correspondiente al pedido <strong>{1}</strong>.
+        Para tramitar la recogida, rellene el <a href="https://form.jotform.com/verdnatura/recogida-verdnatura"
+        title="Formulario Recogida" target="_blank" style="color: #8dba25">SIGUIENTE FORMULARIO</a> en un <strong>plazo máximo de 24h.</strong>
+        <br/><br/>Cuando recibamos el género en nuestras instalaciones emitiremos el abono correspondiente.
+        Debe imprimir el archivo adjunto e incluirlo en la caja. En el caso de no poder imprimirlo, <strong>identifique la caja con el número de reclamación CLARAMENTE LEGIBLE.</strong>'
+    conclusion: Un saludo
diff --git a/print/templates/reports/claim-pickup-order/claim-pickup-order.html b/print/templates/reports/claim-pickup-order/claim-pickup-order.html
index 1f6db49666..49ec00cfd4 100644
--- a/print/templates/reports/claim-pickup-order/claim-pickup-order.html
+++ b/print/templates/reports/claim-pickup-order/claim-pickup-order.html
@@ -52,7 +52,7 @@
                                         </div>
                                     </div>
                                 </div>
-                                        
+
                                 <table class="column-oriented vn-mt-ml">
                                     <thead>
                                         <tr>
@@ -71,16 +71,13 @@
                                         </tr>
                                     </tbody>
                                 </table>
-                
+
                                 <div class="panel sign">
                                     <div class="header">{{$t('clientSignature')}}</div>
                                     <div class="body centered">
                                         <h3>{{client.name}}</h3>
                                     </div>
                                 </div>
-                                
-                                <p v-html="$t('sections.agency.description')"></p>
-                                <p>{{claimConfig.pickupContact}}</p>
                             </div>
                         </div>
                         <!-- Footer block -->
@@ -94,4 +91,4 @@
             </tbody>
         </table>
     </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/print/templates/reports/claim-pickup-order/claim-pickup-order.js b/print/templates/reports/claim-pickup-order/claim-pickup-order.js
index bf975e9f2c..fa21240573 100755
--- a/print/templates/reports/claim-pickup-order/claim-pickup-order.js
+++ b/print/templates/reports/claim-pickup-order/claim-pickup-order.js
@@ -7,7 +7,6 @@ module.exports = {
     async serverPrefetch() {
         this.client = await this.fetchClient(this.claimId);
         this.sales = await this.fetchSales(this.claimId);
-        this.claimConfig = await this.fetchClaimConfig();
 
         if (!this.client)
             throw new Error('Something went wrong');
@@ -26,9 +25,6 @@ module.exports = {
         fetchSales(claimId) {
             return this.rawSqlFromDef('sales', [claimId]);
         },
-        fetchClaimConfig() {
-            return this.findOneFromDef('claimConfig');
-        },
     },
     components: {
         'report-header': reportHeader.build(),
diff --git a/print/templates/reports/claim-pickup-order/locale/es.yml b/print/templates/reports/claim-pickup-order/locale/es.yml
index 388c1f1a69..5ee5ecda76 100644
--- a/print/templates/reports/claim-pickup-order/locale/es.yml
+++ b/print/templates/reports/claim-pickup-order/locale/es.yml
@@ -11,7 +11,3 @@ concept: Concepto
 clientSignature: Firma del cliente
 claim: Reclamación {0}
 phone: Teléfono
-sections:
-  agency:
-    description: 'Para agilizar su recogida, por favor, póngase en contacto con la oficina 
-    de Logista Parcel.'
diff --git a/print/templates/reports/claim-pickup-order/sql/claimConfig.sql b/print/templates/reports/claim-pickup-order/sql/claimConfig.sql
deleted file mode 100644
index 9d744ca6d6..0000000000
--- a/print/templates/reports/claim-pickup-order/sql/claimConfig.sql
+++ /dev/null
@@ -1,2 +0,0 @@
-SELECT pickupContact
-    FROM claimConfig;
\ No newline at end of file

From d040ecb743b0c80ca38ccaf98814f4cca39343d8 Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Mon, 1 Aug 2022 07:59:04 +0200
Subject: [PATCH 006/151] feat(ticket): getVideo from shinobi

---
 .../10480-june/00-packingSiteConfig.sql       | 16 +++++
 front/core/lib/lilium.js                      | 12 ++++
 .../ticket/back/methods/boxing/getVideo.js    | 65 +++++++++++++++++
 .../back/methods/boxing/specs/getVideo.js     | 69 +++++++++++++++++++
 modules/ticket/back/model-config.json         |  6 ++
 modules/ticket/back/models/boxing.js          |  3 +
 modules/ticket/back/models/boxing.json        | 12 ++++
 .../ticket/back/models/packingSiteConfig.json | 25 +++++++
 modules/ticket/front/boxing/index.html        |  2 +
 modules/ticket/front/boxing/index.js          | 32 +++++++++
 modules/ticket/front/index.js                 |  1 +
 modules/ticket/front/routes.json              | 16 ++++-
 12 files changed, 256 insertions(+), 3 deletions(-)
 create mode 100644 db/changes/10480-june/00-packingSiteConfig.sql
 create mode 100644 front/core/lib/lilium.js
 create mode 100644 modules/ticket/back/methods/boxing/getVideo.js
 create mode 100644 modules/ticket/back/methods/boxing/specs/getVideo.js
 create mode 100644 modules/ticket/back/models/boxing.js
 create mode 100644 modules/ticket/back/models/boxing.json
 create mode 100644 modules/ticket/back/models/packingSiteConfig.json
 create mode 100644 modules/ticket/front/boxing/index.html
 create mode 100644 modules/ticket/front/boxing/index.js

diff --git a/db/changes/10480-june/00-packingSiteConfig.sql b/db/changes/10480-june/00-packingSiteConfig.sql
new file mode 100644
index 0000000000..b32bc115e2
--- /dev/null
+++ b/db/changes/10480-june/00-packingSiteConfig.sql
@@ -0,0 +1,16 @@
+CREATE TABLE `vn`.`packingSiteConfig` (
+  `id` INT(11) NOT NULL AUTO_INCREMENT,
+  `shinobiUrl` varchar(255) NOT NULL,
+  `shinobiGroupKey` varchar(255) NOT NULL,
+  `avgBoxingTime` INT(3) NULL,
+  PRIMARY KEY (`id`)
+ );
+
+INSERT INTO `vn`.`packingSiteConfig` SET
+    shinobiUrl = 'https://shinobi.verdnatura.es/',
+    shinobiGroupKey = 'xVqft9LFXg',
+    avgBoxingTime = 30;
+
+INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
+    VALUES
+        ('Boxing', '*', '*', 'ALLOW', 'ROLE', 'employee');
diff --git a/front/core/lib/lilium.js b/front/core/lib/lilium.js
new file mode 100644
index 0000000000..ca10d3511b
--- /dev/null
+++ b/front/core/lib/lilium.js
@@ -0,0 +1,12 @@
+
+export default function lilium(route) {
+    const env = process.env.NODE_ENV;
+    let newRoute = 'https://localhost:8080/#/' + route;
+
+    if (env == 'test')
+        newRoute = 'https://test-lilium.verdnatura.es/#/' + route;
+    if (env == 'producction')
+        newRoute = 'https://lilium.verdnatura.es/#/' + route;
+
+    return newRoute;
+}
diff --git a/modules/ticket/back/methods/boxing/getVideo.js b/modules/ticket/back/methods/boxing/getVideo.js
new file mode 100644
index 0000000000..851e4cfaca
--- /dev/null
+++ b/modules/ticket/back/methods/boxing/getVideo.js
@@ -0,0 +1,65 @@
+const axios = require('axios');
+
+module.exports = Self => {
+    Self.remoteMethod('getVideo', {
+        description: 'Get packing video of ticketId',
+        accessType: 'READ',
+        accepts: [
+            {
+                arg: 'id',
+                type: 'number',
+                required: true,
+                description: 'Ticket id'
+            },
+            {
+                arg: 'time',
+                type: 'number',
+                required: true,
+                description: 'Time to add'
+            }
+        ],
+        returns: {
+            type: ['object'],
+            root: true,
+        },
+        http: {
+            path: `/getVideo`,
+            verb: 'GET',
+        },
+    });
+
+    Self.getVideo = async(id, time, options) => {
+        const models = Self.app.models;
+        const myOptions = {};
+
+        if (typeof options == 'object')
+            Object.assign(myOptions, options);
+
+        const expedition = await models.Expedition.findById(id, null, myOptions);
+        const packingSiteConfig = await models.PackingSiteConfig.findOne({}, myOptions);
+        const token = await Self.getToken(packingSiteConfig);
+        const monitorId = 'xVqft9LFXg';
+
+        const start = new Date(expedition.created);
+        const end = start.setTime(start.getTime() + (time ? time : packingSiteConfig.avgBoxingTime));
+
+        const videoUrl = `${token}/videos/${packingSiteConfig}/${monitorId}?start=${start}&end=${end}`;
+        const videos = await axios.post(`${packingSiteConfig.shinobiUrl}${videoUrl}`, {
+            mail: packingSiteConfig.mail,
+            pass: packingSiteConfig.pass
+        });
+
+        console.log(videos);
+        return videos.data;
+    };
+
+    Self.getToken = async function getToken(packingSiteConfig) {
+        const response = await axios.post(`${packingSiteConfig.shinobiUrl}?json=true`, {
+            machineID: 1,
+            ke: 'hola',
+        });
+
+        console.log(response);
+        return response.data;
+    };
+};
diff --git a/modules/ticket/back/methods/boxing/specs/getVideo.js b/modules/ticket/back/methods/boxing/specs/getVideo.js
new file mode 100644
index 0000000000..ad5295f0c9
--- /dev/null
+++ b/modules/ticket/back/methods/boxing/specs/getVideo.js
@@ -0,0 +1,69 @@
+const models = require('vn-loopback/server/server').models;
+
+xdescribe('sale canEdit()', () => {
+    it('should return true if the role is production regardless of the saleTrackings', async() => {
+        const tx = await models.Sale.beginTransaction({});
+
+        try {
+            const options = {transaction: tx};
+
+            const productionUserID = 49;
+            const ctx = {req: {accessToken: {userId: productionUserID}}};
+
+            const sales = [{id: 3}];
+
+            const result = await models.Sale.canEdit(ctx, sales, options);
+
+            expect(result).toEqual(true);
+
+            await tx.rollback();
+        } catch (e) {
+            await tx.rollback();
+            throw e;
+        }
+    });
+
+    it('should return true if the role is not production and none of the sales has saleTracking', async() => {
+        const tx = await models.Sale.beginTransaction({});
+
+        try {
+            const options = {transaction: tx};
+
+            const salesPersonUserID = 18;
+            const ctx = {req: {accessToken: {userId: salesPersonUserID}}};
+
+            const sales = [{id: 10}];
+
+            const result = await models.Sale.canEdit(ctx, sales, options);
+
+            expect(result).toEqual(true);
+
+            await tx.rollback();
+        } catch (e) {
+            await tx.rollback();
+            throw e;
+        }
+    });
+
+    it('should return false if any of the sales has a saleTracking record', async() => {
+        const tx = await models.Sale.beginTransaction({});
+
+        try {
+            const options = {transaction: tx};
+
+            const salesPersonUserID = 18;
+            const ctx = {req: {accessToken: {userId: salesPersonUserID}}};
+
+            const sales = [{id: 3}];
+
+            const result = await models.Sale.canEdit(ctx, sales, options);
+
+            expect(result).toEqual(false);
+
+            await tx.rollback();
+        } catch (e) {
+            await tx.rollback();
+            throw e;
+        }
+    });
+});
diff --git a/modules/ticket/back/model-config.json b/modules/ticket/back/model-config.json
index 8a6ac0c004..21e800b361 100644
--- a/modules/ticket/back/model-config.json
+++ b/modules/ticket/back/model-config.json
@@ -5,6 +5,9 @@
     "AnnualAverageInvoiced": {
         "dataSource": "vn"
     },
+    "Boxing": {
+        "dataSource": "vn"
+    },
     "Component": {
         "dataSource": "vn"
     },
@@ -20,6 +23,9 @@
     "Packaging": {
         "dataSource": "vn"
     },
+    "PackingSiteConfig": {
+        "dataSource": "vn"
+    },
     "PrintServerQueue": {
         "dataSource": "vn"
     },
diff --git a/modules/ticket/back/models/boxing.js b/modules/ticket/back/models/boxing.js
new file mode 100644
index 0000000000..81732d17ac
--- /dev/null
+++ b/modules/ticket/back/models/boxing.js
@@ -0,0 +1,3 @@
+module.exports = Self => {
+    require('../methods/boxing/getVideo')(Self);
+};
diff --git a/modules/ticket/back/models/boxing.json b/modules/ticket/back/models/boxing.json
new file mode 100644
index 0000000000..5aecbcabe1
--- /dev/null
+++ b/modules/ticket/back/models/boxing.json
@@ -0,0 +1,12 @@
+{
+  "name": "Boxing",
+  "base": "PersistedModel",
+  "acls": [
+    {
+        "accessType": "READ",
+        "principalType": "ROLE",
+        "principalId": "$everyone",
+        "permission": "ALLOW"
+	}
+  ]
+}
diff --git a/modules/ticket/back/models/packingSiteConfig.json b/modules/ticket/back/models/packingSiteConfig.json
new file mode 100644
index 0000000000..7e4699c71a
--- /dev/null
+++ b/modules/ticket/back/models/packingSiteConfig.json
@@ -0,0 +1,25 @@
+{
+    "name": "PackingSiteConfig",
+    "base": "VnModel",
+    "options": {
+        "mysql": {
+            "table": "packingSiteConfig"
+        }
+    },
+    "properties": {
+        "id": {
+            "id": true,
+            "type": "number",
+            "description": "Identifier"
+        },
+        "shinobiUrl": {
+            "type": "string"
+        },
+        "shinobiGroupKey":{
+            "type":"string"
+        },
+        "avgBoxingTime":{
+            "type":"number"
+        }
+    }
+}
diff --git a/modules/ticket/front/boxing/index.html b/modules/ticket/front/boxing/index.html
new file mode 100644
index 0000000000..7fb3b870e0
--- /dev/null
+++ b/modules/ticket/front/boxing/index.html
@@ -0,0 +1,2 @@
+<vn-card>
+</vn-card>
diff --git a/modules/ticket/front/boxing/index.js b/modules/ticket/front/boxing/index.js
new file mode 100644
index 0000000000..6a1d4b4d31
--- /dev/null
+++ b/modules/ticket/front/boxing/index.js
@@ -0,0 +1,32 @@
+import ngModule from '../module';
+import Section from 'salix/components/section';
+
+class Controller extends Section {
+    constructor($element, $) {
+        super($element, $);
+    }
+
+    $onInit() {
+        window.location.href = this.lilium('dashboard');
+    }
+
+    lilium(route) {
+        const env = process.env.NODE_ENV;
+        let newRoute = 'http://localhost:8080/#/' + route;
+
+        if (env == 'test')
+            newRoute = 'https://test-lilium.verdnatura.es/#/' + route;
+        if (env == 'producction')
+            newRoute = 'https://lilium.verdnatura.es/#/' + route;
+
+        return newRoute;
+    }
+}
+
+ngModule.vnComponent('vnTicketBoxing', {
+    template: require('./index.html'),
+    controller: Controller,
+    bindings: {
+        ticket: '<'
+    }
+});
diff --git a/modules/ticket/front/index.js b/modules/ticket/front/index.js
index 85a03ffb63..0558d251d1 100644
--- a/modules/ticket/front/index.js
+++ b/modules/ticket/front/index.js
@@ -33,3 +33,4 @@ import './dms/index';
 import './dms/create';
 import './dms/edit';
 import './sms';
+import './boxing';
diff --git a/modules/ticket/front/routes.json b/modules/ticket/front/routes.json
index ba7cfa8875..4be8e2183e 100644
--- a/modules/ticket/front/routes.json
+++ b/modules/ticket/front/routes.json
@@ -24,7 +24,8 @@
             {"state": "ticket.card.saleChecked", "icon": "assignment"},
             {"state": "ticket.card.components", "icon": "icon-components"},
             {"state": "ticket.card.saleTracking", "icon": "assignment"},
-            {"state": "ticket.card.dms.index", "icon": "cloud_download"}
+            {"state": "ticket.card.dms.index", "icon": "cloud_download"},
+            {"state": "ticket.card.boxing", "icon": "science"}
         ]
     },
     "keybindings": [
@@ -66,7 +67,7 @@
             "abstract": true,
             "params": {
                 "ticket": "$ctrl.ticket"
-            }            
+            }
         },
         {
             "url" : "/step-one",
@@ -273,6 +274,15 @@
             "params": {
                 "ticket": "$ctrl.ticket"
             }
+        },
+        {
+            "url": "/boxing",
+            "state": "ticket.card.boxing",
+            "component": "vn-ticket-boxing",
+            "description": "Boxing",
+            "params": {
+                "ticket": "$ctrl.ticket"
+            }
         }
     ]
-}
\ No newline at end of file
+}

From 7d4dd7bb52751dc442f489e2d057b25f047288c4 Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Mon, 1 Aug 2022 15:03:17 +0200
Subject: [PATCH 007/151] feat(boxing): return stream video

---
 .../10480-june/00-packingSiteConfig.sql       |  2 +-
 .../ticket/back/methods/boxing/getVideo.js    | 48 ++++++++++---------
 modules/ticket/front/boxing/index.html        |  3 ++
 modules/ticket/front/boxing/index.js          |  2 +-
 4 files changed, 30 insertions(+), 25 deletions(-)

diff --git a/db/changes/10480-june/00-packingSiteConfig.sql b/db/changes/10480-june/00-packingSiteConfig.sql
index b32bc115e2..879896f418 100644
--- a/db/changes/10480-june/00-packingSiteConfig.sql
+++ b/db/changes/10480-june/00-packingSiteConfig.sql
@@ -7,7 +7,7 @@ CREATE TABLE `vn`.`packingSiteConfig` (
  );
 
 INSERT INTO `vn`.`packingSiteConfig` SET
-    shinobiUrl = 'https://shinobi.verdnatura.es/',
+    shinobiUrl = 'http://shinobi.verdnatura.es',
     shinobiGroupKey = 'xVqft9LFXg',
     avgBoxingTime = 30;
 
diff --git a/modules/ticket/back/methods/boxing/getVideo.js b/modules/ticket/back/methods/boxing/getVideo.js
index 851e4cfaca..4e2a4b12c9 100644
--- a/modules/ticket/back/methods/boxing/getVideo.js
+++ b/modules/ticket/back/methods/boxing/getVideo.js
@@ -8,13 +8,13 @@ module.exports = Self => {
             {
                 arg: 'id',
                 type: 'number',
-                required: true,
+                required: false,
                 description: 'Ticket id'
             },
             {
                 arg: 'time',
                 type: 'number',
-                required: true,
+                required: false,
                 description: 'Time to add'
             }
         ],
@@ -31,35 +31,37 @@ module.exports = Self => {
     Self.getVideo = async(id, time, options) => {
         const models = Self.app.models;
         const myOptions = {};
-
+        console.log('ENTRY');
         if (typeof options == 'object')
             Object.assign(myOptions, options);
 
         const expedition = await models.Expedition.findById(id, null, myOptions);
         const packingSiteConfig = await models.PackingSiteConfig.findOne({}, myOptions);
-        const token = await Self.getToken(packingSiteConfig);
-        const monitorId = 'xVqft9LFXg';
+        const token = 'BW4o7FZyJ85she1hlRDe6QnwW3jwEP';
+        const groupKey = 'xVqft9LFXg';
+        const monitorId = 'VbiUcajdaT';// 'xVqft9LFXg';
 
-        const start = new Date(expedition.created);
-        const end = start.setTime(start.getTime() + (time ? time : packingSiteConfig.avgBoxingTime));
+        const start = '2022-07-27T09:00:00';// new Date('2022-07-27'); // new Date(expedition.created);
+        const end = '2022-07-27T09:15:00';// start.setTime(start.getTime() + (time ? time : packingSiteConfig.avgBoxingTime));
 
-        const videoUrl = `${token}/videos/${packingSiteConfig}/${monitorId}?start=${start}&end=${end}`;
-        const videos = await axios.post(`${packingSiteConfig.shinobiUrl}${videoUrl}`, {
-            mail: packingSiteConfig.mail,
-            pass: packingSiteConfig.pass
-        });
+        const videoUrl = `/${token}/videos/${groupKey}/${monitorId}?start=${start}&end=${end}`;
+        const url = `${packingSiteConfig.shinobiUrl}${videoUrl}`;
+        const data = await axios.post(url);
 
-        console.log(videos);
-        return videos.data;
-    };
+        console.log(data.data.videos);
+        console.log('-----------------------');
+        console.log('-----------------------');
+        console.log('-----------------------');
+        console.log('-----------------------');
 
-    Self.getToken = async function getToken(packingSiteConfig) {
-        const response = await axios.post(`${packingSiteConfig.shinobiUrl}?json=true`, {
-            machineID: 1,
-            ke: 'hola',
-        });
-
-        console.log(response);
-        return response.data;
+        axios({
+            method: 'get',
+            url: `${packingSiteConfig.shinobiUrl}${data.data.videos[0].href}`,
+            responseType: 'stream'
+        })
+            .then(response => {
+                console.log(response);
+                return response;
+            });
     };
 };
diff --git a/modules/ticket/front/boxing/index.html b/modules/ticket/front/boxing/index.html
index 7fb3b870e0..e47976cd79 100644
--- a/modules/ticket/front/boxing/index.html
+++ b/modules/ticket/front/boxing/index.html
@@ -1,2 +1,5 @@
 <vn-card>
+    <video id="videobcg" muted="muted" controls class="video">
+        <source src="http://localhost:5000/api/Boxings/getVideo?id=1" type="video/mp4" autoplay="autoplay" >
+    </video>
 </vn-card>
diff --git a/modules/ticket/front/boxing/index.js b/modules/ticket/front/boxing/index.js
index 6a1d4b4d31..722301963d 100644
--- a/modules/ticket/front/boxing/index.js
+++ b/modules/ticket/front/boxing/index.js
@@ -7,7 +7,7 @@ class Controller extends Section {
     }
 
     $onInit() {
-        window.location.href = this.lilium('dashboard');
+        // window.location.href = this.lilium('dashboard');
     }
 
     lilium(route) {

From 8a08b6f3996e388a624ec7acf001a2c9affc7283 Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Tue, 2 Aug 2022 15:15:05 +0200
Subject: [PATCH 008/151] feat(ticket_boxing): return video stream

---
 .../10480-june/00-packingSiteConfig.sql       |   9 +
 .../10480-june/00-packingSiteUpdate.sql       |  56 ++++
 db/dump/fixtures.sql                          | 287 +++++++++---------
 .../ticket/back/methods/boxing/getVideo.js    |  65 ++--
 .../ticket/back/models/packingSiteConfig.json |   3 +
 modules/ticket/front/boxing/index.html        |   4 +-
 6 files changed, 258 insertions(+), 166 deletions(-)
 create mode 100644 db/changes/10480-june/00-packingSiteUpdate.sql

diff --git a/db/changes/10480-june/00-packingSiteConfig.sql b/db/changes/10480-june/00-packingSiteConfig.sql
index 879896f418..28e685eb69 100644
--- a/db/changes/10480-june/00-packingSiteConfig.sql
+++ b/db/changes/10480-june/00-packingSiteConfig.sql
@@ -1,16 +1,25 @@
 CREATE TABLE `vn`.`packingSiteConfig` (
   `id` INT(11) NOT NULL AUTO_INCREMENT,
   `shinobiUrl` varchar(255) NOT NULL,
+  `shinobiToken` varchar(255) NOT NULL,
   `shinobiGroupKey` varchar(255) NOT NULL,
   `avgBoxingTime` INT(3) NULL,
   PRIMARY KEY (`id`)
  );
 
+
 INSERT INTO `vn`.`packingSiteConfig` SET
     shinobiUrl = 'http://shinobi.verdnatura.es',
+    shinobiToken = 'BW4o7FZyJ85she1hlRDe6QnwW3jwEP',
     shinobiGroupKey = 'xVqft9LFXg',
     avgBoxingTime = 30;
 
 INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
     VALUES
         ('Boxing', '*', '*', 'ALLOW', 'ROLE', 'employee');
+
+SELECT e.id expeditionFk, e.ticketFk, ps.code, ps.monitorId
+	FROM expedition e
+		JOIN host h ON Convert(h.code USING utf8mb3) COLLATE utf8mb3_unicode_ci = e.hostFk
+		JOIN packingSite ps ON  ps.hostFk = h.id
+	WHERE e.ticketFk = 1;
diff --git a/db/changes/10480-june/00-packingSiteUpdate.sql b/db/changes/10480-june/00-packingSiteUpdate.sql
new file mode 100644
index 0000000000..14313fd529
--- /dev/null
+++ b/db/changes/10480-june/00-packingSiteUpdate.sql
@@ -0,0 +1,56 @@
+ALTER TABLE `vn`.`packingSite` ADD monitorId varchar(255) NULL;
+
+UPDATE `vn`.`packingSite`
+    SET monitorId = 'VbiUcajdaT'
+        WHERE code = 'h1';
+UPDATE `vn`.`packingSite`
+    SET monitorId = 'qKMPn9aaVe'
+        WHERE code = 'h2';
+UPDATE `vn`.`packingSite`
+    SET monitorId = '3CtdIAGPAv'
+        WHERE code = 'h3';
+UPDATE `vn`.`packingSite`
+    SET monitorId = 'Xme2hiqz1f'
+        WHERE code = 'h4';
+UPDATE `vn`.`packingSite`
+    SET monitorId = 'aulxefgfJU'
+        WHERE code = 'h5';
+UPDATE `vn`.`packingSite`
+    SET monitorId = '6Ou0D1bhBw'
+        WHERE code = 'h6';
+UPDATE `vn`.`packingSite`
+    SET monitorId = 'eVUvnE6pNw'
+        WHERE code = 'h7';
+UPDATE `vn`.`packingSite`
+    SET monitorId = '0wsmSvqmrs'
+        WHERE code = 'h8';
+UPDATE `vn`.`packingSite`
+    SET monitorId = 'r2l2RyyF4I'
+        WHERE code = 'h9';
+UPDATE `vn`.`packingSite`
+    SET monitorId = 'EdjHLIiDVD'
+        WHERE code = 'h10';
+UPDATE `vn`.`packingSite`
+    SET monitorId = 'czC45kmwqI'
+        WHERE code = 'h11';
+UPDATE `vn`.`packingSite`
+    SET monitorId = 'PNsmxPaCwQ'
+        WHERE code = 'h12';
+UPDATE `vn`.`packingSite`
+    SET monitorId = 'agVssO0FDC'
+        WHERE code = 'h13';
+UPDATE `vn`.`packingSite`
+    SET monitorId = 'f2SPNENHPo'
+        WHERE code = 'h14';
+UPDATE `vn`.`packingSite`
+    SET monitorId = '6UR7gUZxks'
+        WHERE code = 'h15';
+UPDATE `vn`.`packingSite`
+    SET monitorId = 'bOB0f8WZ2V'
+        WHERE code = 'h16';
+UPDATE `vn`.`packingSite`
+    SET monitorId = 'MIR1nXaL0n'
+        WHERE code = 'h17';
+UPDATE `vn`.`packingSite`
+    SET monitorId = '0Oj9SgGTXR'
+        WHERE code = 'h18';
diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql
index f6583f1bb7..f67db0b200 100644
--- a/db/dump/fixtures.sql
+++ b/db/dump/fixtures.sql
@@ -1,7 +1,7 @@
 CREATE SCHEMA IF NOT EXISTS `vn2008`;
 CREATE SCHEMA IF NOT EXISTS `tmp`;
 
-UPDATE `util`.`config` 
+UPDATE `util`.`config`
     SET `environment`= 'test';
 
 ALTER TABLE `vn`.`itemTaxCountry` AUTO_INCREMENT = 1;
@@ -9,11 +9,11 @@ ALTER TABLE `vn`.`address` AUTO_INCREMENT = 1;
 ALTER TABLE `vn`.`zoneGeo` AUTO_INCREMENT = 1;
 ALTER TABLE `vn`.`ticket` AUTO_INCREMENT = 1;
 
-INSERT INTO `salix`.`AccessToken` (`id`, `ttl`, `created`, `userId`) 
-    VALUES 
+INSERT INTO `salix`.`AccessToken` (`id`, `ttl`, `created`, `userId`)
+    VALUES
         ('DEFAULT_TOKEN', '1209600', util.VN_CURDATE(), 66);
 
-INSERT INTO `vn`.`ticketConfig` (`id`, `scopeDays`) 
+INSERT INTO `vn`.`ticketConfig` (`id`, `scopeDays`)
     VALUES
         ('1', '6');
 
@@ -22,11 +22,11 @@ INSERT INTO `vn`.`bionicConfig` (`generalInflationCoeficient`, `minimumDensityVo
         (1.30, 167.00, 138000, 71);
 
 INSERT INTO `vn`.`chatConfig` (`host`, `api`)
-    VALUES    
+    VALUES
         ('https://chat.verdnatura.es', 'https://chat.verdnatura.es/api/v1');
 
-INSERT IGNORE INTO `vn`.`greugeConfig`(`id`, `freightPickUpPrice`) 
-    VALUES 
+INSERT IGNORE INTO `vn`.`greugeConfig`(`id`, `freightPickUpPrice`)
+    VALUES
         ('1', '11');
 
 INSERT INTO `vn`.`packagingConfig`(`upperGap`)
@@ -52,11 +52,11 @@ INSERT INTO `account`.`account`(`id`)
 INSERT INTO `vn`.`educationLevel` (`id`, `name`)
 	VALUES
 		(1, 'ESTUDIOS PRIMARIOS COMPLETOS'),
-		(2, 'ENSEÑANZAS DE BACHILLERATO');    
+		(2, 'ENSEÑANZAS DE BACHILLERATO');
 
 INSERT INTO `vn`.`worker`(`id`,`code`, `firstName`, `lastName`, `userFk`, `bossFk`)
     SELECT id,UPPER(LPAD(role, 3, '0')), name, name, id, 9
-        FROM `vn`.`user`;      
+        FROM `vn`.`user`;
 
 UPDATE `vn`.`worker` SET bossFk = NULL WHERE id = 20;
 UPDATE `vn`.`worker` SET bossFk = 20 WHERE id = 1 OR id = 9;
@@ -69,7 +69,7 @@ INSERT INTO `hedera`.`tpvConfig`(`id`, `currency`, `terminal`, `transactionType`
         (1,	978, 1, 0, 2000, 9, 0);
 
 INSERT INTO `account`.`user`(`id`,`name`,`nickname`, `password`,`role`,`active`,`email`,`lang`, `image`)
-    VALUES 
+    VALUES
         (1101, 'BruceWayne',         'Bruce Wayne',          'ac754a330530832ba1bf7687f577da91', 2, 1, 'BruceWayne@mydomain.com',         'es', 'e7723f0b24ff05b32ed09d95196f2f29'),
         (1102, 'PetterParker',       'Petter Parker',        'ac754a330530832ba1bf7687f577da91', 2, 1, 'PetterParker@mydomain.com',       'en', 'e7723f0b24ff05b32ed09d95196f2f29'),
         (1103, 'ClarkKent',          'Clark Kent',           'ac754a330530832ba1bf7687f577da91', 2, 1, 'ClarkKent@mydomain.com',          'fr', 'e7723f0b24ff05b32ed09d95196f2f29'),
@@ -113,7 +113,7 @@ INSERT INTO `vn`.`worker`(`id`, `code`, `firstName`, `lastName`, `userFk`,`bossF
         (1107, 'ANT', 'Hank'         , 'Pym'   , 1107, 19, 432978107, NULL, 1),
         (1108, 'DCX', 'Charles'      , 'Xavier', 1108, 19, 432978108, 1,    NULL),
         (1109, 'HLK', 'Bruce'        , 'Banner', 1109, 19, 432978109, 1,    2),
-        (1110, 'JJJ', 'Jessica'      , 'Jones' , 1110, 19, 432978110, 2,    1); 
+        (1110, 'JJJ', 'Jessica'      , 'Jones' , 1110, 19, 432978110, 2,    1);
 
 INSERT INTO `vn`.`currency`(`id`, `code`, `name`, `ratio`)
     VALUES
@@ -123,7 +123,7 @@ INSERT INTO `vn`.`currency`(`id`, `code`, `name`, `ratio`)
         (4, 'JPY', 'Yen Japones',   1);
 
 INSERT INTO `vn`.`country`(`id`, `country`, `isUeeMember`, `code`, `currencyFk`, `politicalCountryFk`, `ibanLength`, `continentFk`, `hasDailyInvoice`, `CEE`)
-    VALUES 
+    VALUES
         (1, 'España',   1, 'ES', 1, 1,  24, 4, 0, 1),
         (2, 'Italia',   1, 'IT', 1, 2,  27, 4, 0, 1),
         (3, 'Alemania', 1, 'DE', 1, 3,  22, 4, 0, 1),
@@ -153,19 +153,19 @@ INSERT INTO `vn`.`sector`(`id`, `description`, `warehouseFk`, `isPreviousPrepare
         (1, 'First sector',     1, 1, 'FIRST'),
         (2, 'Second sector',    2, 0, 'SECOND');
 
-INSERT INTO `vn`.`parking` (`id`, `column`, `row`, `sectorFk`, `code`, `pickingOrder`) 
-    VALUES 
+INSERT INTO `vn`.`parking` (`id`, `column`, `row`, `sectorFk`, `code`, `pickingOrder`)
+    VALUES
         ('1', '700', '01', '1', '700-01', '70001'),
         ('2', '700', '02', '2', '700-02', '70002');
 
-INSERT INTO `vn`.`shelving` (`code`, `parkingFk`, `isPrinted`, `priority`, `parked`, `userFk`) 
-    VALUES 
+INSERT INTO `vn`.`shelving` (`code`, `parkingFk`, `isPrinted`, `priority`, `parked`, `userFk`)
+    VALUES
         ('GVC', 1, 0, 1, 0, 1106),
         ('HEJ', 2, 0, 1, 0, 1106),
         ('UXN', 1, 0, 1, 0, 1106);
 
 INSERT INTO `vn`.`accountingType`(`id`, `description`, `receiptDescription`,`code`, `maxAmount`, `daysInFuture`)
-    VALUES 
+    VALUES
         (1,     'CC and credit policies',   'Transfers',        'wireTransfer', NULL, 1),
         (2,     'Cash',                     'Cash',             'cash',         1000, 0),
         (3,     'Credit card',              'Credit Card',      'creditCard',   NULL, 0),
@@ -180,8 +180,8 @@ INSERT INTO `vn`.`bankEntity`(`id`, `countryFk`, `name`, `bic`)
         (128,  1, 'The Best Bank', 'BBKKESMMMMMM'),
         (2100, 1, 'Caixa Bank',    'CAIXESBB');
 
-INSERT INTO `vn`.`bank`(`id`, `bank`, `account`, `cash`, `entityFk`, `isActive`, `currencyFk`) 
-    VALUES 
+INSERT INTO `vn`.`bank`(`id`, `bank`, `account`, `cash`, `entityFk`, `isActive`, `currencyFk`)
+    VALUES
         (1,     'Pay on receipt',           '5720000001', 3, 128,     1, 1),
         (2,     'Cash',                     '5700000001', 2, 128,     1, 1),
         (3,     'Compensation',             '4000000000', 8, 128,     1, 1),
@@ -235,7 +235,7 @@ UPDATE `vn`.`agencyMode` SET `web` = 1, `reportMail` = 'no-reply@gothamcity.com'
 UPDATE `vn`.`agencyMode` SET `code` = 'refund' WHERE  `id` = 23;
 
 INSERT INTO `vn`.`payMethod`(`id`,`code`,  `name`, `graceDays`, `outstandingDebt`, `isIbanRequiredForClients`, `isIbanRequiredForSuppliers`, `hasVerified`)
-    VALUES 
+    VALUES
         (1, NULL,           'PayMethod one',            0,  001,    0, 0, 0),
         (2, NULL,           'PayMethod two',            10, 001,    0, 0, 1),
         (3, 'compensation', 'PayMethod three',          0,  001,    0, 0, 0),
@@ -244,7 +244,7 @@ INSERT INTO `vn`.`payMethod`(`id`,`code`,  `name`, `graceDays`, `outstandingDebt
         (8,'wireTransfer',  'WireTransfer',             5,  001,    1, 1, 0);
 
 INSERT INTO `vn`.`payDem`(`id`, `payDem`)
-    VALUES 
+    VALUES
         (1, 10),
         (2, 20);
 
@@ -273,7 +273,7 @@ INSERT INTO `vn`.`town`(`id`, `name`, `provinceFk`)
         (5, 'Quito',        5);
 
 INSERT INTO `vn`.`postCode`(`code`, `townFk`, `geoFk`)
-    VALUES 
+    VALUES
         ('46000', 1, 6),
         ('46460', 2, 6),
         ('46680', 3, 6),
@@ -481,7 +481,7 @@ INSERT INTO `vn`.`supplierActivity`(`code`, `name`)
         ('complements',  'Other complements'),
         ('flowerPlants',  'Wholesale of flowers and plants'),
         ('vegetablesFruits', 'Fruit and vegetable trade');
-        
+
 INSERT INTO `vn`.`supplier`(`id`, `name`, `nickname`,`account`,`countryFk`,`nif`, `commission`, `created`, `isActive`, `street`, `city`, `provinceFk`, `postCode`, `payMethodFk`, `payDemFk`, `payDay`, `taxTypeSageFk`, `withholdingSageFk`, `transactionTypeSageFk`, `workerFk`, `supplierActivityFk`, `isPayMethodChecked`, `healthRegister`)
     VALUES
         (1,   'Plants SL',             'Plants nick',   4100000001, 1, '06089160W', 0, util.VN_CURDATE(), 1, 'supplier address 1', 'PONTEVEDRA', 1, 15214, 1, 1, 15, 4,  1, 1, 18, 'flowerPlants',  1, '400664487V'),
@@ -498,7 +498,7 @@ INSERT INTO `vn`.`company`(`id`, `code`, `supplierAccountFk`, `workerManagerFk`,
         (442 , 'VNL', 241,  30,  2   , 1, NULL,         2, 'VNL Company - Plant passport'),
         (567 , 'VNH', NULL, 30,  NULL, 4, NULL,         1, 'VNH Company - Plant passport'),
         (791 , 'FTH', NULL, 30,  NULL, 3, '2015-11-30', 1, NULL),
-        (1381, 'ORN', NULL, 30,  NULL, 7, NULL,         1, 'ORN Company - Plant passport');  
+        (1381, 'ORN', NULL, 30,  NULL, 7, NULL,         1, 'ORN Company - Plant passport');
 
 INSERT INTO `vn`.`taxArea` (`code`, `claveOperacionFactura`, `CodigoTransaccion`)
     VALUES
@@ -519,7 +519,7 @@ INSERT INTO `vn`.`invoiceOutSerial` (`code`, `description`, `isTaxed`, `taxAreaF
 INSERT INTO `vn`.`invoiceOut`(`id`, `serial`, `amount`, `issued`,`clientFk`, `created`, `companyFk`, `dued`, `booked`, `bankFk`, `hasPdf`)
     VALUES
         (1, 'T', 1014.24,   util.VN_CURDATE(),                              1101, util.VN_CURDATE(),                              442, util.VN_CURDATE(),                              util.VN_CURDATE(), 1, 0),
-        (2, 'T', 121.36,    util.VN_CURDATE(),                              1102, util.VN_CURDATE(),                              442, util.VN_CURDATE(),                              util.VN_CURDATE(), 1, 0), 
+        (2, 'T', 121.36,    util.VN_CURDATE(),                              1102, util.VN_CURDATE(),                              442, util.VN_CURDATE(),                              util.VN_CURDATE(), 1, 0),
         (3, 'T', 8.88,      util.VN_CURDATE(),                              1103, util.VN_CURDATE(),                              442, util.VN_CURDATE(),                              util.VN_CURDATE(), 1, 0),
         (4, 'T', 8.88,      util.VN_CURDATE(),                              1103, util.VN_CURDATE(),                              442, util.VN_CURDATE(),                              util.VN_CURDATE(), 1, 0),
         (5, 'A', 8.88,      DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 1103, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 442, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 1, 0);
@@ -531,7 +531,7 @@ UPDATE `vn`.`invoiceOut` SET ref = 'T4444444' WHERE id = 4;
 UPDATE `vn`.`invoiceOut` SET ref = 'A1111111' WHERE id = 5;
 
 INSERT INTO `vn`.`invoiceOutTax` (`invoiceOutFk`, `taxableBase`, `vat`, `pgcFk`)
-    VALUES 
+    VALUES
         (1, 895.76, 89.58,  4722000010),
         (1, 33.80,  7.10,   4722000021),
         (2, 110.33, 11.03,  4770000010),
@@ -552,7 +552,7 @@ INSERT INTO `vn`.`expence`(`id`, `taxTypeFk`, `name`, `isWithheld`)
         (7001000000, 1, 'Mercaderia',                       0),
         (7050000000, 1, 'Prestacion de servicios',          1);
 
-        
+
 INSERT INTO `vn`.`invoiceOutExpence`(`id`, `invoiceOutFk`, `amount`, `expenceFk`, `created`)
     VALUES
         (1, 1, 813.06,  2000000000, util.VN_CURDATE()),
@@ -564,7 +564,7 @@ INSERT INTO `vn`.`invoiceOutExpence`(`id`, `invoiceOutFk`, `amount`, `expenceFk`
         (7, 5, 8.07,    2000000000, util.VN_CURDATE());
 
 INSERT INTO `vn`.`zone` (`id`, `name`, `hour`, `agencyModeFk`, `travelingDays`, `price`, `bonus`, `itemMaxSize`)
-    VALUES 
+    VALUES
         (1,  'Zone pickup A',       CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 1,  0, 0,    0, 100),
         (2,  'Zone pickup B',       CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 1,  0, 0,    0, 100),
         (3,  'Zone 247 A',          CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 7,  1, 2,    0, 100),
@@ -580,7 +580,7 @@ INSERT INTO `vn`.`zone` (`id`, `name`, `hour`, `agencyModeFk`, `travelingDays`,
         (13, 'Zone quantum break',  CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 5,  0, 0,    0, 100);
 
 INSERT INTO `vn`.`zoneWarehouse` (`id`, `zoneFk`, `warehouseFk`)
-    VALUES 
+    VALUES
         (1, 1, 1),
         (2, 2, 2),
         (3, 3, 1),
@@ -596,7 +596,7 @@ INSERT INTO `vn`.`zoneWarehouse` (`id`, `zoneFk`, `warehouseFk`)
         (13, 13, 5);
 
 INSERT INTO `vn`.`zoneClosure` (`zoneFk`, `dated`, `hour`)
-    VALUES 
+    VALUES
         (1,     util.VN_CURDATE(), '23:59'),
         (2,     util.VN_CURDATE(), '23:59'),
         (3,     util.VN_CURDATE(), '23:59'),
@@ -668,7 +668,7 @@ INSERT INTO `vn`.`ticketObservation`(`id`, `ticketFk`, `observationTypeFk`, `des
         (11, 24, 4, 'Reclama ticket: 7'),
         (12, 11, 3, 'Delivery after 10am');
 
--- FIX for state hours on local, inter_afterInsert 
+-- FIX for state hours on local, inter_afterInsert
 UPDATE vncontrol.inter SET odbc_date = DATE_ADD(util.VN_CURDATE(), INTERVAL -10 SECOND);
 
 INSERT INTO `vn`.`ticketTracking`(`ticketFk`, `stateFk`, `workerFk`, `created`)
@@ -764,7 +764,7 @@ INSERT INTO `vn`.`itemCategory`(`id`, `name`, `display`, `color`, `icon`, `code`
 INSERT INTO `vn`.`temperature`(`code`, `name`, `description`)
     VALUES
         ('warm', 'Warm', 'Warm'),
-        ('cool', 'Cool', 'Cool');        
+        ('cool', 'Cool', 'Cool');
 
 INSERT INTO `vn`.`itemType`(`id`, `code`, `name`, `categoryFk`, `warehouseFk`, `life`,`workerFk`, `isPackaging`, `temperatureFk`)
     VALUES
@@ -818,7 +818,7 @@ INSERT INTO `vn`.`taxClassCode`(`taxClassFk`, `effectived`, `taxCodeFk`)
         (1, util.VN_CURDATE(), 1),
         (1, util.VN_CURDATE(), 21),
         (2, util.VN_CURDATE(), 2);
-      
+
 INSERT INTO `vn`.`intrastat`(`id`, `description`, `taxClassFk`, `taxCodeFk`)
     VALUES
         (05080000, 'Coral y materiales similares',        2, 2),
@@ -830,7 +830,7 @@ INSERT INTO `vn`.`itemFamily`(`code`, `description`)
         ('SER', 'Services'),
         ('VT',  'Sales');
 
-INSERT INTO `vn`.`item`(`id`, `typeFk`, `size`, `inkFk`, `stems`, `originFk`, `description`, `producerFk`, `intrastatFk`, `expenceFk`, 
+INSERT INTO `vn`.`item`(`id`, `typeFk`, `size`, `inkFk`, `stems`, `originFk`, `description`, `producerFk`, `intrastatFk`, `expenceFk`,
     `comment`, `relevancy`, `image`, `subName`, `minPrice`, `stars`, `family`, `isFloramondo`, `genericFk`, `itemPackingTypeFk`, `hasMinPrice`, `packingShelve`)
     VALUES
         (1,  2, 70,   'YEL', 1,    1, NULL,              1,    06021010, 2000000000, NULL, 0, '1',  NULL, 0, 1, 'VT',   0,  NULL,   'V',  0, 15),
@@ -883,18 +883,18 @@ INSERT INTO `vn`.`expeditionStateType`(`id`, `description`, `code`)
         (3, 'Perdida', 'LOST');
 
 
-INSERT INTO `vn`.`expedition`(`id`, `agencyModeFk`, `ticketFk`, `isBox`, `created`, `itemFk`, `counter`, `workerFk`, `externalId`, `packagingFk`, `stateTypeFk`)
+INSERT INTO `vn`.`expedition`(`id`, `agencyModeFk`, `ticketFk`, `isBox`, `created`, `itemFk`, `counter`, `workerFk`, `externalId`, `packagingFk`, `stateTypeFk`, `hostFk`)
     VALUES
-        (1,  1, 1, 71, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH),  15,      1,  18, 'UR9000006041',   94, 1),
-        (2,  1, 1, 71, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH),  16,      2,  18, 'UR9000006041',   94, 1),
-        (3,  1, 1, 71, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH),  NULL,    3,  18, 'UR9000006041',   94, 2),
-        (4,  1, 1, 71, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH),  NULL,    4,  18, 'UR9000006041',   94, 2),
-        (5,  1, 2, 71, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH),  NULL,    1,  18, NULL,             94, 3),
-        (6,  7, 3, 71, DATE_ADD(util.VN_CURDATE(), INTERVAL -2 MONTH),  NULL,    1,  18, NULL,             94, 3),
-        (7,  2, 4, 71, DATE_ADD(util.VN_CURDATE(), INTERVAL -3 MONTH),  NULL,    1,  18, NULL,             94, NULL),
-        (8,  3, 5, 71, DATE_ADD(util.VN_CURDATE(), INTERVAL -4 MONTH),  NULL,    1,  18, NULL,             94, 1),
-        (9,  3, 6, 71, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH),  NULL,    1,  18, NULL,             94, 2),
-        (10, 7, 7, 71, NOW(),                                           NULL,    1,  18, NULL,             94, 3);
+        (1,  1, 1, 71, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH),  15,      1,  18, 'UR9000006041',   94, 1,   'pc1'),
+        (2,  1, 1, 71, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH),  16,      2,  18, 'UR9000006041',   94, 1,   NULL),
+        (3,  1, 1, 71, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH),  NULL,    3,  18, 'UR9000006041',   94, 2,   NULL),
+        (4,  1, 1, 71, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH),  NULL,    4,  18, 'UR9000006041',   94, 2,   NULL),
+        (5,  1, 2, 71, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH),  NULL,    1,  18, NULL,             94, 3,   NULL),
+        (6,  7, 3, 71, DATE_ADD(util.VN_CURDATE(), INTERVAL -2 MONTH),  NULL,    1,  18, NULL,             94, 3,   NULL),
+        (7,  2, 4, 71, DATE_ADD(util.VN_CURDATE(), INTERVAL -3 MONTH),  NULL,    1,  18, NULL,             94, NULL,NULL),
+        (8,  3, 5, 71, DATE_ADD(util.VN_CURDATE(), INTERVAL -4 MONTH),  NULL,    1,  18, NULL,             94, 1,   NULL),
+        (9,  3, 6, 71, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH),  NULL,    1,  18, NULL,             94, 2,   NULL),
+        (10, 7, 7, 71, NOW(),                                           NULL,    1,  18, NULL,             94, 3,   NULL);
 
 
 INSERT INTO `vn`.`expeditionState`(`id`, `created`, `expeditionFk`, `typeFk`, `userFk`)
@@ -966,7 +966,7 @@ INSERT INTO `vn`.`saleComponent`(`saleFk`, `componentFk`, `value`)
         (3,     39, 0.994),
         (4,     28, 1.25),
         (4,     29, 0.42),
-        (4,     39, 0.017),     
+        (4,     39, 0.017),
         (5,     17, 9.94),
         (5,     28, 50),
         (5,     29, 49.4),
@@ -988,8 +988,8 @@ INSERT INTO `vn`.`saleComponent`(`saleFk`, `componentFk`, `value`)
         (9,     15, 3.0949),
         (9,     21, 0.001),
         (9,     28, 53),
-        (9,     29, 46.4), 
-        (9,     39, 0.994), 
+        (9,     29, 46.4),
+        (9,     39, 0.994),
         (10,    15, 0.0199),
         (10,    28, 7),
         (10,    29, 0),
@@ -1088,14 +1088,14 @@ INSERT INTO `vn`.`saleComponent`(`saleFk`, `componentFk`, `value`)
         (32,    36, -92.324),
         (32,    39, 0.994);
 
-INSERT INTO `vn`.`itemShelving` (`itemFk`, `shelvingFk`, `shelve`, `visible`, `grouping`, `packing`, `userFk`) 
-    VALUES 
+INSERT INTO `vn`.`itemShelving` (`itemFk`, `shelvingFk`, `shelve`, `visible`, `grouping`, `packing`, `userFk`)
+    VALUES
         (2, 'GVC', 'A', 1, 1, 1, 1106),
         (4, 'HEJ', 'A', 1, 1, 1, 1106),
         (1, 'UXN', 'A', 2, 12, 12, 1106);
 
-INSERT INTO `vn`.`itemShelvingSale` (`itemShelvingFk`, `saleFk`, `quantity`, `created`, `userFk`) 
-    VALUES 
+INSERT INTO `vn`.`itemShelvingSale` (`itemShelvingFk`, `saleFk`, `quantity`, `created`, `userFk`)
+    VALUES
         ('1', '1', '1', '', '1106'),
         ('2', '2', '5', '', '1106'),
         ('1', '7', '1', '', '1106'),
@@ -1137,8 +1137,8 @@ INSERT INTO `vn`.`ticketCollection`(`ticketFk`, `collectionFk`, `level`)
         (3, 2, NULL),
         (23, 1, NULL);
 
-INSERT INTO `vn`.`parking` (`column`, `row`, `sectorFk`, `code`, `pickingOrder`) 
-    VALUES 
+INSERT INTO `vn`.`parking` (`column`, `row`, `sectorFk`, `code`, `pickingOrder`)
+    VALUES
         ('100', '01', 1, '100-01', 1);
 
 INSERT INTO `vn`.`genus`(`id`, `name`)
@@ -1292,7 +1292,7 @@ INSERT INTO `vn`.`itemTypeTag`(`id`, `itemTypeFk`, `tagFk`, `priority`)
 CALL `vn`.`itemRefreshTags`(NULL);
 
 INSERT INTO `vn`.`itemLog` (`id`, `originFk`, `userFk`, `action`, `description`)
-    VALUES 
+    VALUES
         ('1', '1', '1', 'insert', 'We made a change!');
 
 INSERT INTO `vn`.`recovery`(`id`, `clientFk`, `started`, `finished`, `amount`, `period`)
@@ -1484,8 +1484,8 @@ INSERT INTO `hedera`.`orderRowComponent`(`rowFk`, `componentFk`, `price`)
         (4,     21, -0.001),
         (4,     28, 20.72),
         (4,     29, -19.72),
-        (4,     37, 2),  
-        (4,     39, 0.01),  
+        (4,     37, 2),
+        (4,     39, 0.01),
         (5,     15, 0.58),
         (5,     23, 6.5),
         (5,     28, 20.72),
@@ -1704,7 +1704,7 @@ INSERT INTO `vn`.`workerManaExcluded`(`workerFk`)
  La otra manera es poner el calculo con los 2 trabajadores que utilizamos ahora mismo para los tickets
 */
 
-call vn.manaSpellersRequery(19);  
+call vn.manaSpellersRequery(19);
 call vn.manaSpellersRequery(18);
 
 INSERT INTO `vn`.`clientSample`(`id`, `clientFk`, `typeFk`, `created`, `workerFk`, `userFk`, `companyFk`)
@@ -1772,8 +1772,8 @@ INSERT INTO `hedera`.`tpvMerchant`(`id`, `description`, `companyFk`, `bankFk`, `
         (1, 'Arkham Bank',  442, 1, 'h12387193H10238'),
         (2, 'NewYork Bank', 442, 1, '7981ugsgd1hsdad');
 
-INSERT INTO `hedera`.`tpvTransaction`(`id`,`merchantFk`, `clientFk`,`receiptFk`, `amount`, `response`, `errorCode`, `status`, `created`) 
-    VALUES 
+INSERT INTO `hedera`.`tpvTransaction`(`id`,`merchantFk`, `clientFk`,`receiptFk`, `amount`, `response`, `errorCode`, `status`, `created`)
+    VALUES
         (1, 1, 1101, NULL, 2000, NULL, 'SIS0042',    'ok',       util.VN_CURDATE()),
         (2, 1, 1101, NULL, 1000, NULL, 'SIS0051',    'started',  util.VN_CURDATE()),
         (3, 2, 1101, NULL, 7268, NULL, NULL,         'ok',       util.VN_CURDATE()),
@@ -1787,32 +1787,32 @@ INSERT INTO `vn`.`orderTicket`(`orderFk`, `ticketFk`)
         (2,  2),
         (3,  3),
         (4,  4),
-        (5,  5), 
-        (6,  6), 
-        (7,  7), 
-        (8,  8), 
-        (9,  9), 
-        (10, 10), 
-        (11, 11), 
-        (12, 12), 
-        (13, 13), 
-        (14, 14), 
+        (5,  5),
+        (6,  6),
+        (7,  7),
+        (8,  8),
+        (9,  9),
+        (10, 10),
+        (11, 11),
+        (12, 12),
+        (13, 13),
+        (14, 14),
         (15, 15),
         (16, 16),
         (17, 17),
         (18, 18),
         (19, 19),
-        (20, 20), 
-        (21, 21), 
+        (20, 20),
+        (21, 21),
         (22, 22);
 
-INSERT INTO `vn`.`userConfig` (`userFk`, `warehouseFk`, `companyFk`) 
+INSERT INTO `vn`.`userConfig` (`userFk`, `warehouseFk`, `companyFk`)
     VALUES
         (1,  1, 69),
-        (5,  1, 442), 
+        (5,  1, 442),
         (9,  1, 442),
         (18, 3, 567);
- 
+
 INSERT INTO `vn`.`receipt`(`id`, `invoiceFk`, `amountPaid`, `payed`, `workerFk`, `bankFk`, `clientFk`, `created`, `companyFk`, `isConciliate`)
     VALUES
         (1, 'Cobro web',            100.50, util.VN_CURDATE(),                             9, 1, 1101, util.VN_CURDATE(),                             442, 1),
@@ -1895,14 +1895,14 @@ INSERT INTO `postgresql`.`business_labour` (`business_id`, `notes`, `department_
     VALUES
         (1111, NULL, 23, 1, 0.0, 1, 1, 1, 1);
 
-UPDATE `postgresql`.`business_labour` bl 
+UPDATE `postgresql`.`business_labour` bl
     JOIN `postgresql`.`business` b ON b.business_id = bl.business_id
     JOIN `postgresql`.`profile` pr ON pr.profile_id = b.client_id
     JOIN `postgresql`.`person` p ON p.person_id = pr.person_id
     SET bl.`professional_category_id` = 31
     WHERE p.`Id_trabajador` = 1110;
 
-UPDATE `postgresql`.`business_labour` bl 
+UPDATE `postgresql`.`business_labour` bl
     SET bl.`department_id` = 43
 WHERE business_id IN(18, 19);
 
@@ -1917,18 +1917,18 @@ INSERT INTO `postgresql`.`profile_media`(`profile_media_id`, `profile_id`, `medi
         (2, 1107, 2);
 
 INSERT INTO `vn`.`workCenterHoliday` (`workCenterFk`, `days`, `year`)
-    VALUES 
+    VALUES
         ('1', '27.5', YEAR(util.VN_CURDATE())),
         ('5', '22', YEAR(util.VN_CURDATE())),
-        ('1', '24.5', YEAR(DATE_ADD(util.VN_CURDATE(), INTERVAL -1 YEAR))), 
+        ('1', '24.5', YEAR(DATE_ADD(util.VN_CURDATE(), INTERVAL -1 YEAR))),
         ('5', '23', YEAR(DATE_ADD(util.VN_CURDATE(), INTERVAL -1 YEAR)));
 
-INSERT INTO `vn`.`absenceType` (`id`, `name`, `rgb`, `code`, `holidayEntitlementRate`, `discountRate`) 
-    VALUES 
+INSERT INTO `vn`.`absenceType` (`id`, `name`, `rgb`, `code`, `holidayEntitlementRate`, `discountRate`)
+    VALUES
         (1,  'Holidays',            '#FF4444', 'holiday',       0,      0),
         (2,  'Leave of absence',    '#C71585', 'absence',       0,      1),
         (6,  'Half holiday',        '#E65F00', 'halfHoliday',   0,      0.5),
-        (15, 'Half Paid Leave',     '#5151c0', 'halfPaidLeave', 0,      1),        
+        (15, 'Half Paid Leave',     '#5151c0', 'halfPaidLeave', 0,      1),
         (20, 'Furlough',            '#97B92F', 'furlough',      1,      1),
         (21, 'Furlough half day',   '#778899', 'halfFurlough',  0.5,    1);
 
@@ -1945,10 +1945,10 @@ INSERT INTO `postgresql`.`business_labour_payroll` (`business_id`, `cod_tarifa`,
         (1, 7, 12, 100, 900.50),
         (1106, 7, 12, 100, 1263.03),
         (1107, 7, 12, 100, 2000),
-        (1108, 7, 12, 100, 1500);       
+        (1108, 7, 12, 100, 1500);
 
-INSERT INTO `postgresql`.`calendar_employee` (`business_id`, `calendar_state_id`, `date`) 
-    VALUES 
+INSERT INTO `postgresql`.`calendar_employee` (`business_id`, `calendar_state_id`, `date`)
+    VALUES
         (1,    6, IF(MONTH(util.VN_CURDATE()) = 12 AND DAY(util.VN_CURDATE()) > 10, DATE_ADD(util.VN_CURDATE(), INTERVAL -10 DAY), DATE_ADD(util.VN_CURDATE(), INTERVAL 10 DAY))),
         (1106, 1, IF(MONTH(util.VN_CURDATE()) = 12 AND DAY(util.VN_CURDATE()) > 10, DATE_ADD(util.VN_CURDATE(), INTERVAL -10 DAY), DATE_ADD(util.VN_CURDATE(), INTERVAL 10 DAY))),
         (1106, 1, IF(MONTH(util.VN_CURDATE()) = 12 AND DAY(util.VN_CURDATE()) > 10, DATE_ADD(util.VN_CURDATE(), INTERVAL -11 DAY), DATE_ADD(util.VN_CURDATE(), INTERVAL 11 DAY))),
@@ -1966,8 +1966,8 @@ INSERT INTO `postgresql`.`calendar_employee` (`business_id`, `calendar_state_id`
         (1107, 2, IF(MONTH(util.VN_CURDATE()) >= 1 AND DAY(util.VN_CURDATE()) > 20, DATE_ADD(util.VN_CURDATE(), INTERVAL -15 DAY), DATE_ADD(util.VN_CURDATE(), INTERVAL 7  DAY))),
         (1107, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL - 16 DAY));
 
-INSERT INTO `vn`.`smsConfig` (`id`, `uri`, `title`, `apiKey`) 
-    VALUES 
+INSERT INTO `vn`.`smsConfig` (`id`, `uri`, `title`, `apiKey`)
+    VALUES
         ('1', 'https://api.gateway360.com/api/3.0/sms/send', 'Verdnatura', '5715476da95b46d686a5a255e6459523');
 
 INSERT INTO `vn`.`sharingClient`(`id`, `workerFk`, `started`, `ended`, `clientFk`)
@@ -1983,37 +1983,37 @@ CALL `vn`.zoneGeo_calcTree(); -- this is an auto calculate for table vn.zoneGeo,
 
 INSERT INTO `vn`.`zoneIncluded` (`zoneFk`, `geoFk`, `isIncluded`)
     VALUES
-        (1, 3,   0), 
-        (1, 4,   0), 
-        (1, 5,   0), 
+        (1, 3,   0),
+        (1, 4,   0),
+        (1, 5,   0),
         (1, 1,   1),
-        (2, 3,   0), 
-        (2, 4,   0), 
-        (2, 5,   0), 
+        (2, 3,   0),
+        (2, 4,   0),
+        (2, 5,   0),
         (2, 1,   1),
-        (3, 3,   0), 
-        (3, 4,   0), 
-        (3, 5,   0),  
+        (3, 3,   0),
+        (3, 4,   0),
+        (3, 5,   0),
         (3, 1,   1),
-        (4, 3,   0), 
-        (4, 4,   0), 
-        (4, 5,   0),  
+        (4, 3,   0),
+        (4, 4,   0),
+        (4, 5,   0),
         (4, 1,   1),
-        (5, 3,   1), 
-        (5, 4,   0), 
-        (5, 5,   1), 
+        (5, 3,   1),
+        (5, 4,   0),
+        (5, 5,   1),
         (5, 1,   1),
-        (6, 3,   1), 
-        (6, 4,   0), 
-        (6, 5,   1), 
+        (6, 3,   1),
+        (6, 4,   0),
+        (6, 5,   1),
         (6, 1,   1),
-        (7, 3,   0), 
-        (7, 4,   0), 
-        (7, 5,   0), 
+        (7, 3,   0),
+        (7, 4,   0),
+        (7, 5,   0),
         (7, 1,   1),
-        (8, 3,   0), 
-        (8, 4,   0), 
-        (8, 5,   0), 
+        (8, 3,   0),
+        (8, 4,   0),
+        (8, 5,   0),
         (8, 1,   1),
         (10, 14, 1);
 
@@ -2226,12 +2226,12 @@ INSERT INTO `vn`.`zoneEvent`(`zoneFk`, `type`, `dated`)
         (7, 'day', DATE_ADD(util.VN_CURDATE(), INTERVAL +6 DAY));
 
 INSERT INTO `vn`.`zoneEvent`(`zoneFk`, `type`, `weekDays`)
-    VALUES 
+    VALUES
         (8, 'indefinitely', 'mon,tue,wed,thu,fri,sat,sun'),
         (10, 'indefinitely', 'mon,tue,wed,thu,fri,sat,sun');
 
 INSERT INTO `vn`.`zoneEvent`(`zoneFk`, `type`, `started`, `ended`)
-    VALUES 
+    VALUES
         (9, 'range', DATE_ADD(util.VN_CURDATE(), INTERVAL -1 YEAR), DATE_ADD(util.VN_CURDATE(), INTERVAL +1 YEAR));
 
 INSERT INTO `vn`.`workerTimeControl`(`userFk`, `timed`, `manual`, `direction`)
@@ -2294,8 +2294,8 @@ INSERT INTO `vn`.`workerDocument`(`id`, `worker`, `document`,`isReadableByWorker
         (1, 1106, 4, TRUE),
         (2, 1107, 3, FALSE);
 
-INSERT INTO `vn`.`device` (`sn`, `model`, `userFk`) 
-    VALUES 
+INSERT INTO `vn`.`device` (`sn`, `model`, `userFk`)
+    VALUES
         ('aaa', 'android', '9');
 
 INSERT INTO `vn`.`queuePriority`(`id`, `priority`)
@@ -2309,7 +2309,7 @@ INSERT INTO `vn`.`workerTimeControlParams` (`id`, `dayBreak`, `weekBreak`, `week
         (1, 43200, 129600, 734400, 43200, 50400, 259200, 1296000, 36000);
 
 INSERT IGNORE INTO `vn`.`greugeConfig` (`id`, `freightPickUpPrice`) VALUES ('1', '11');
-        
+
 INSERT INTO `vn`.`thermograph`(`id`, `model`)
     VALUES
         ('TMM190901395',    'TEMPMATE'),
@@ -2327,21 +2327,21 @@ INSERT INTO `vn`.`travelThermograph`(`thermographFk`, `created`, `warehouseFk`,
         ('138350-0',        DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 1, 1,       'WARM', NULL,                           5),
         ('138350-0',        util.VN_CURDATE(),                              1, NULL,    'COOL', NULL,                           NULL);
 
-REPLACE INTO `vn`.`incoterms`(`code`, `name`) 
-    VALUES 
+REPLACE INTO `vn`.`incoterms`(`code`, `name`)
+    VALUES
         ('FAS', 'Free Alongside Ship');
 
-REPLACE INTO `vn`.`customsAgent`(`id`, `fiscalName`, `street`, `nif`, `phone`, `email`) 
-    VALUES 
+REPLACE INTO `vn`.`customsAgent`(`id`, `fiscalName`, `street`, `nif`, `phone`, `email`)
+    VALUES
         (1, 'Agent one', '1007 Mountain Drive, Gotham', 'N1111111111', '111111111', 'agentone@gotham.com'),
         (2, 'Agent two', '1007 Mountain Drive, Gotham', 'N2222222222', '222222222', 'agenttwo@gotham.com');
 
-INSERT INTO `vn`.`tablet`(`uuid`, `name`, `place`, `macwifi`) 
-    VALUES 
+INSERT INTO `vn`.`tablet`(`uuid`, `name`, `place`, `macwifi`)
+    VALUES
         ('1', 'TEST', 'ON THE FIXTURES', '0'),
         ('2', 'DEV', 'OTHER TABLET', '0');
 
-INSERT INTO `vn`.`tabletDepartment`(`tabletFk`, `departmentFk`) 
+INSERT INTO `vn`.`tabletDepartment`(`tabletFk`, `departmentFk`)
     VALUES
         (1, 23),
         (2, 1);
@@ -2374,8 +2374,8 @@ INSERT INTO `vn`.`rate`(`dated`, `warehouseFk`, `rate0`, `rate1`, `rate2`, `rate
         (DATE_ADD(util.VN_CURDATE(), INTERVAL -1 YEAR), 1, 10, 15, 20, 25),
         (util.VN_CURDATE(), 1, 12, 17, 22, 27);
 
-INSERT INTO `vn`.`awb` (id, code, package, weight, created, amount, transitoryFk, taxFk) 
-    VALUES 
+INSERT INTO `vn`.`awb` (id, code, package, weight, created, amount, transitoryFk, taxFk)
+    VALUES
         (1,     '07546501420', 67,  671,    util.VN_CURDATE(),  1761, 1, 1),
         (2,     '07546491421', 252, 2769,   util.VN_CURDATE(),  5231, 1, 1),
         (3,     '07546500823', 102, 1495,   util.VN_CURDATE(),  3221, 1, 1),
@@ -2387,8 +2387,8 @@ INSERT INTO `vn`.`awb` (id, code, package, weight, created, amount, transitoryFk
         (9,     '99610289193', 302, 2972,   util.VN_CURDATE(),  3871, 442, 1),
         (10,    '07546500856', 185, 2364,   util.VN_CURDATE(),  5321, 442, 1);
 
-INSERT INTO `vn`.`dua` (id, code, awbFk, issued, operated, booked, bookEntried, gestdocFk, customsValue, companyFk) 
-    VALUES 
+INSERT INTO `vn`.`dua` (id, code, awbFk, issued, operated, booked, bookEntried, gestdocFk, customsValue, companyFk)
+    VALUES
         (1,  '19ES0028013A481523', 1,  util.VN_CURDATE(), util.VN_CURDATE(), util.VN_CURDATE(), util.VN_CURDATE(), 1, 11276.95,   442),
         (2,  '21ES00280136115760', 2,  util.VN_CURDATE(), util.VN_CURDATE(), util.VN_CURDATE(), util.VN_CURDATE(), 2, 1376.20,    442),
         (3,  '19ES00280131956004', 3,  util.VN_CURDATE(), util.VN_CURDATE(), util.VN_CURDATE(), util.VN_CURDATE(), 3, 14268.50,   442),
@@ -2435,8 +2435,8 @@ INSERT INTO `vn`.`duaInvoiceIn`(`id`, `duaFk`, `invoiceInFk`)
         (4,  4,  4),
         (5,  5,  5),
         (6,  6,  6),
-        (7,  7,  7),	
-        (8,  8,  8),	
+        (7,  7,  7),
+        (8,  8,  8),
         (9,  9,  9),
         (10, 10, 10);
 
@@ -2446,7 +2446,7 @@ INSERT INTO `vn`.`invoiceInTax` (`invoiceInFk`, `taxableBase`, `expenceFk`, `for
         (2, 999.99, '2000000000', null, null, null),
         (3, 1000.50, '2000000000', null, null, null),
         (4, 0.50, '2000000000', null, null, null),
-        (5, 150.50, '2000000000', null, null, null),    
+        (5, 150.50, '2000000000', null, null, null),
         (1, 252.25, '4751000000', NULL, 7, 61),
         (2, 223.17, '6210000567', NULL, 8, 20),
         (3, 95.60,  '7001000000', NULL, 8, 35),
@@ -2461,9 +2461,9 @@ INSERT INTO `vn`.`invoiceInIntrastat` (`invoiceInFk`, `net`, `intrastatFk`, `amo
         (1, 10,    6021010, 20.00, 205, 5),
         (2, 13.20, 5080000, 15.00, 580, 5),
         (2, 16.10, 6021010, 25.00, 80,  5);
-   
+
 INSERT INTO `vn`.`ticketRecalc`(`ticketFk`)
-    SELECT `id` 
+    SELECT `id`
         FROM `vn`.`ticket` t
             LEFT JOIN vn.ticketRecalc tr ON tr.ticketFk = t.id
         WHERE tr.ticketFk IS NULL;
@@ -2478,7 +2478,7 @@ INSERT INTO `vn`.`zoneAgencyMode`(`id`, `agencyModeFk`, `zoneFk`)
         (4,  7,  1);
 
 INSERT INTO `vn`.`expeditionTruck` (`id`, `ETD`, `description`)
-    VALUES 
+    VALUES
         (1, CONCAT(YEAR(DATE_ADD(util.VN_CURDATE(), INTERVAL +3 YEAR))), 'Best truck in fleet');
 
 INSERT INTO `vn`.`expeditionPallet` (`id`, `truckFk`, `built`, `position`, `isPrint`)
@@ -2486,7 +2486,7 @@ INSERT INTO `vn`.`expeditionPallet` (`id`, `truckFk`, `built`, `position`, `isPr
         (1, 1, util.VN_CURDATE(), 1, 1);
 
 INSERT INTO `vn`.`expeditionScan` (`id`, `expeditionFk`, `scanned`, `palletFk`)
-    VALUES 
+    VALUES
         (1,     1,  util.VN_CURDATE(), 1),
         (2,     2,  util.VN_CURDATE(), 1),
         (3,     3,  util.VN_CURDATE(), 1),
@@ -2521,7 +2521,7 @@ UPDATE `vn`.`route`
 INSERT INTO `bs`.`salesPerson` (`workerFk`, `year`, `month`, `portfolioWeight`)
     VALUES
         (18,     YEAR(util.VN_CURDATE()),    MONTH(util.VN_CURDATE()),  807.23),
-        (19,     YEAR(util.VN_CURDATE()),    MONTH(util.VN_CURDATE()),  34.40);      
+        (19,     YEAR(util.VN_CURDATE()),    MONTH(util.VN_CURDATE()),  34.40);
 
 INSERT INTO `bs`.`sale` (`saleFk`, `amount`, `dated`,  `typeFk`, `clientFk`)
     VALUES
@@ -2550,14 +2550,14 @@ INSERT INTO `vn`.`calendarHolidaysType` (`id`, `name`, `hexColour`)
 INSERT INTO `vn`.`calendarHolidays` (`id`, `calendarHolidaysTypeFk`, `dated`, `calendarHolidaysNameFk`, `workCenterFk`)
     VALUES
         (1,     1,  CONCAT(YEAR(util.VN_CURDATE()), '-12-09'),      1,      1);
-        
+
 INSERT INTO `vn`.`supplierAgencyTerm` (`agencyFk`, `supplierFk`, `minimumPackages`, `kmPrice`, `packagePrice`, `routePrice`, `minimumKm`, `minimumM3`, `m3Price`)
     VALUES
         (1, 1,   0,  0.00,  0.00,   NULL, 0,  0.00, 23),
         (2, 1,   60, 0.00,  0.00,   NULL, 0,  5.00, 33),
         (3, 2,   0,  15.00, 0.00,   NULL, 0,  0.00, 0),
         (4, 2,   0,  20.00, 0.00,   NULL, 0,  0.00, 0),
-        (5, 442, 0,  0.00, 3.05,    NULL, 0,  0.00, 0);    
+        (5, 442, 0,  0.00, 3.05,    NULL, 0,  0.00, 0);
 
 INSERT INTO `vn`.`chat` (`senderFk`, `recipient`, `dated`, `checkUserStatus`, `message`, `status`, `attempts`)
     VALUES
@@ -2607,7 +2607,16 @@ INSERT INTO `vn`.`sectorCollection` (`userFk`, `sectorFk`)
 INSERT INTO `vn`.`sectorCollectionSaleGroup` (`sectorCollectionFk`, `saleGroupFk`)
     VALUES
         (1, 1);
-        
+
 INSERT INTO `vn`.`workerTimeControlConfig` (`id`, `dayBreak`, `dayBreakDriver`, `shortWeekBreak`, `longWeekBreak`, `weekScope`, `mailPass`, `mailHost`, `mailSuccessFolder`, `mailErrorFolder`, `mailUser`, `minHoursToBreak`, `breakHours`, `hoursCompleteWeek`, `startNightlyHours`, `endNightlyHours`, `maxTimePerDay`, `breakTime`, `timeToBreakTime`, `dayMaxTime`, `shortWeekDays`, `longWeekDays`)
     VALUES
-        (1, 43200, 32400, 129600, 259200, 604800, '', '', 'Leidos.exito', 'Leidos.error', 'timeControl', 5.33, 0.33, 40, '22:00:00', '06:00:00', 57600, 1200, 18000, 57600, 6, 13);
\ No newline at end of file
+        (1, 43200, 32400, 129600, 259200, 604800, '', '', 'Leidos.exito', 'Leidos.error', 'timeControl', 5.33, 0.33, 40, '22:00:00', '06:00:00', 57600, 1200, 18000, 57600, 6, 13);
+
+INSERT INTO `vn`.`host` (`id`, `code`, `description`, `warehouseFk`, `bankFk`)
+    VALUES
+        (1, 'pc1', 'pc host', 1, 1);
+
+INSERT INTO `vn`.`packingSite` (`id`, `code`, `hostFk`, `monitorId`)
+    VALUES
+        (1, 'h1', 1, 'VbiUcajdaT');
+
diff --git a/modules/ticket/back/methods/boxing/getVideo.js b/modules/ticket/back/methods/boxing/getVideo.js
index 4e2a4b12c9..bdd0107f3c 100644
--- a/modules/ticket/back/methods/boxing/getVideo.js
+++ b/modules/ticket/back/methods/boxing/getVideo.js
@@ -18,10 +18,23 @@ module.exports = Self => {
                 description: 'Time to add'
             }
         ],
-        returns: {
-            type: ['object'],
-            root: true,
-        },
+        returns: [
+            {
+                arg: 'body',
+                type: 'file',
+                root: true
+            },
+            {
+                arg: 'Content-Type',
+                type: 'String',
+                http: {target: 'header'}
+            },
+            {
+                arg: 'Content-Disposition',
+                type: 'String',
+                http: {target: 'header'}
+            }
+        ],
         http: {
             path: `/getVideo`,
             verb: 'GET',
@@ -37,31 +50,33 @@ module.exports = Self => {
 
         const expedition = await models.Expedition.findById(id, null, myOptions);
         const packingSiteConfig = await models.PackingSiteConfig.findOne({}, myOptions);
-        const token = 'BW4o7FZyJ85she1hlRDe6QnwW3jwEP';
-        const groupKey = 'xVqft9LFXg';
-        const monitorId = 'VbiUcajdaT';// 'xVqft9LFXg';
+        const monitorId = 'VbiUcajdaT';
+        console.log(packingSiteConfig);
 
-        const start = '2022-07-27T09:00:00';// new Date('2022-07-27'); // new Date(expedition.created);
-        const end = '2022-07-27T09:15:00';// start.setTime(start.getTime() + (time ? time : packingSiteConfig.avgBoxingTime));
+        const addTime = (time ? time : packingSiteConfig.avgBoxingTime) * 1000;
+        const start = new Date(expedition.created);// '2022-07-27T09:00:00';// new Date('2022-07-27'); //
+        const end = new Date(start.getTime() + addTime);
+        console.log(addTime);
+        console.log(start.toISOString().split('.')[0]);
+        console.log(end.toISOString().split('.')[0]);
 
-        const videoUrl = `/${token}/videos/${groupKey}/${monitorId}?start=${start}&end=${end}`;
-        const url = `${packingSiteConfig.shinobiUrl}${videoUrl}`;
-        const data = await axios.post(url);
+        const videoUrl = `/${packingSiteConfig.shinobiToken}/videos/${packingSiteConfig.shinobiGroupKey}/${monitorId}`;
+        const timeUrl = `?start=${start.toISOString().split('.')[0]}&end=${end.toISOString().split('.')[0]}`;
+        const url = `${packingSiteConfig.shinobiUrl}${videoUrl}${timeUrl}&endIsStartTo`;
 
-        console.log(data.data.videos);
-        console.log('-----------------------');
-        console.log('-----------------------');
-        console.log('-----------------------');
-        console.log('-----------------------');
-
-        axios({
+        console.log(url);
+        const videoList = await axios.post(url);
+        console.log(videoList.data);
+        const lastVideo = videoList.data.videos[videoList.data.videos.length - 1].href;
+        console.log(lastVideo);
+        const stream = await axios({
             method: 'get',
-            url: `${packingSiteConfig.shinobiUrl}${data.data.videos[0].href}`,
+            url: `${packingSiteConfig.shinobiUrl}${lastVideo}`,
             responseType: 'stream'
-        })
-            .then(response => {
-                console.log(response);
-                return response;
-            });
+        }).then(response => {
+            return response.data;
+        });
+
+        return [stream, 'video/mp4', `filename="${id}.mp4"`];
     };
 };
diff --git a/modules/ticket/back/models/packingSiteConfig.json b/modules/ticket/back/models/packingSiteConfig.json
index 7e4699c71a..8f0032d41f 100644
--- a/modules/ticket/back/models/packingSiteConfig.json
+++ b/modules/ticket/back/models/packingSiteConfig.json
@@ -18,6 +18,9 @@
         "shinobiGroupKey":{
             "type":"string"
         },
+        "shinobiToken":{
+            "type":"string"
+        },
         "avgBoxingTime":{
             "type":"number"
         }
diff --git a/modules/ticket/front/boxing/index.html b/modules/ticket/front/boxing/index.html
index e47976cd79..17b2b475ae 100644
--- a/modules/ticket/front/boxing/index.html
+++ b/modules/ticket/front/boxing/index.html
@@ -1,5 +1,5 @@
 <vn-card>
-    <video id="videobcg" muted="muted" controls class="video">
-        <source src="http://localhost:5000/api/Boxings/getVideo?id=1" type="video/mp4" autoplay="autoplay" >
+    <video id="videobcg" muted controls class="video" autoplay>
+        <source src="http://localhost:5000/api/Boxings/getVideo?id=1" type="video/mp4">
     </video>
 </vn-card>

From b4b6d61460e347e8abc68b706968ed315e560072 Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Wed, 3 Aug 2022 14:57:39 +0200
Subject: [PATCH 009/151] feat(ticket_boxing): fix getVideo

---
 .../ticket/back/methods/boxing/getVideo.js    | 77 +++++++++++--------
 modules/ticket/front/boxing/index.js          |  2 +-
 2 files changed, 45 insertions(+), 34 deletions(-)

diff --git a/modules/ticket/back/methods/boxing/getVideo.js b/modules/ticket/back/methods/boxing/getVideo.js
index bdd0107f3c..91d538782e 100644
--- a/modules/ticket/back/methods/boxing/getVideo.js
+++ b/modules/ticket/back/methods/boxing/getVideo.js
@@ -1,4 +1,5 @@
 const axios = require('axios');
+const https = require('https');
 
 module.exports = Self => {
     Self.remoteMethod('getVideo', {
@@ -16,23 +17,16 @@ module.exports = Self => {
                 type: 'number',
                 required: false,
                 description: 'Time to add'
-            }
-        ],
-        returns: [
-            {
-                arg: 'body',
-                type: 'file',
-                root: true
             },
             {
-                arg: 'Content-Type',
-                type: 'String',
-                http: {target: 'header'}
+                arg: 'req',
+                type: 'object',
+                http: {source: 'req'}
             },
             {
-                arg: 'Content-Disposition',
-                type: 'String',
-                http: {target: 'header'}
+                arg: 'res',
+                type: 'object',
+                http: {source: 'res'}
             }
         ],
         http: {
@@ -41,42 +35,59 @@ module.exports = Self => {
         },
     });
 
-    Self.getVideo = async(id, time, options) => {
+    Self.getVideo = async(id, time, req, res, options) => {
         const models = Self.app.models;
         const myOptions = {};
-        console.log('ENTRY');
+        // console.log('ENTRY');
         if (typeof options == 'object')
             Object.assign(myOptions, options);
 
         const expedition = await models.Expedition.findById(id, null, myOptions);
         const packingSiteConfig = await models.PackingSiteConfig.findOne({}, myOptions);
-        const monitorId = 'VbiUcajdaT';
-        console.log(packingSiteConfig);
+        const monitorId = 'Xme2hiqz1f';
+        // console.log(packingSiteConfig);
 
         const addTime = (time ? time : packingSiteConfig.avgBoxingTime) * 1000;
         const start = new Date(expedition.created);// '2022-07-27T09:00:00';// new Date('2022-07-27'); //
         const end = new Date(start.getTime() + addTime);
-        console.log(addTime);
-        console.log(start.toISOString().split('.')[0]);
-        console.log(end.toISOString().split('.')[0]);
+        // console.log(addTime);
+        // console.log(start.toString().split('.')[0]);
+        // console.log(end.toString().split('.')[0]);
 
         const videoUrl = `/${packingSiteConfig.shinobiToken}/videos/${packingSiteConfig.shinobiGroupKey}/${monitorId}`;
-        const timeUrl = `?start=${start.toISOString().split('.')[0]}&end=${end.toISOString().split('.')[0]}`;
+        const timeUrl = `?start=${start.toString().split('.')[0]}&end=${end.toString().split('.')[0]}`;
         const url = `${packingSiteConfig.shinobiUrl}${videoUrl}${timeUrl}&endIsStartTo`;
 
-        console.log(url);
+        // console.log(url);
         const videoList = await axios.post(url);
-        console.log(videoList.data);
-        const lastVideo = videoList.data.videos[videoList.data.videos.length - 1].href;
-        console.log(lastVideo);
-        const stream = await axios({
-            method: 'get',
-            url: `${packingSiteConfig.shinobiUrl}${lastVideo}`,
-            responseType: 'stream'
-        }).then(response => {
-            return response.data;
-        });
+        // console.log('videoList.data', videoList.data);
+        // console.log(videoList.data.videos);
+        // console.log(videoList.data.videos.length);
+        const length = videoList.data.videos.length;
+        // console.log(length);
+        if (!length) return [];
 
-        return [stream, 'video/mp4', `filename="${id}.mp4"`];
+        const lastVideo = videoList.data.videos[length - 1].href;
+
+        const headers = Object.assign({}, req.headers, {
+            host: 'shinobi.verdnatura.es'
+        });
+        const httpOptions = {
+            host: 'shinobi.verdnatura.es',
+            path: '/BW4o7FZyJ85she1hlRDe6QnwW3jwEP/videos/xVqft9LFXg/Xme2hiqz1f/2022-08-02T11-45-01.mp4',
+            port: 443,
+            headers
+        };
+
+        return new Promise((resolve, reject) => {
+            const req = https.request(httpOptions,
+                shinobiRes => {
+                    shinobiRes.pause();
+                    res.writeHeader(shinobiRes.statusCode, shinobiRes.headers);
+                    shinobiRes.pipe(res);
+                    resolve();
+                });
+            req.end();
+        });
     };
 };
diff --git a/modules/ticket/front/boxing/index.js b/modules/ticket/front/boxing/index.js
index 722301963d..686bf7d01f 100644
--- a/modules/ticket/front/boxing/index.js
+++ b/modules/ticket/front/boxing/index.js
@@ -7,7 +7,7 @@ class Controller extends Section {
     }
 
     $onInit() {
-        // window.location.href = this.lilium('dashboard');
+        window.location.href = this.lilium(`ticket/${this.ticket.id}/boxing`);
     }
 
     lilium(route) {

From 43df1e7e102000214bb89b94c17a33e3354de164 Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Mon, 5 Sep 2022 12:06:14 +0200
Subject: [PATCH 010/151] refactor(boxing): refactor getVideo

---
 .../00-packingSiteConfig.sql                  |  3 +-
 .../00-packingSiteUpdate.sql                  |  0
 .../ticket/back/methods/boxing/getVideo.js    | 72 +++++++++----------
 .../back/methods/boxing/getVideoList.js       | 17 ++---
 modules/ticket/back/models/boxing.js          |  1 +
 5 files changed, 47 insertions(+), 46 deletions(-)
 rename db/changes/{10480-june => 10490-august}/00-packingSiteConfig.sql (94%)
 rename db/changes/{10480-june => 10490-august}/00-packingSiteUpdate.sql (100%)

diff --git a/db/changes/10480-june/00-packingSiteConfig.sql b/db/changes/10490-august/00-packingSiteConfig.sql
similarity index 94%
rename from db/changes/10480-june/00-packingSiteConfig.sql
rename to db/changes/10490-august/00-packingSiteConfig.sql
index 28e685eb69..bbd0b32def 100644
--- a/db/changes/10480-june/00-packingSiteConfig.sql
+++ b/db/changes/10490-august/00-packingSiteConfig.sql
@@ -7,9 +7,8 @@ CREATE TABLE `vn`.`packingSiteConfig` (
   PRIMARY KEY (`id`)
  );
 
-
 INSERT INTO `vn`.`packingSiteConfig` SET
-    shinobiUrl = 'http://shinobi.verdnatura.es',
+    shinobiUrl = 'https://shinobi.verdnatura.es',
     shinobiToken = 'BW4o7FZyJ85she1hlRDe6QnwW3jwEP',
     shinobiGroupKey = 'xVqft9LFXg',
     avgBoxingTime = 30;
diff --git a/db/changes/10480-june/00-packingSiteUpdate.sql b/db/changes/10490-august/00-packingSiteUpdate.sql
similarity index 100%
rename from db/changes/10480-june/00-packingSiteUpdate.sql
rename to db/changes/10490-august/00-packingSiteUpdate.sql
diff --git a/modules/ticket/back/methods/boxing/getVideo.js b/modules/ticket/back/methods/boxing/getVideo.js
index 91d538782e..8cecbad4d3 100644
--- a/modules/ticket/back/methods/boxing/getVideo.js
+++ b/modules/ticket/back/methods/boxing/getVideo.js
@@ -9,13 +9,13 @@ module.exports = Self => {
             {
                 arg: 'id',
                 type: 'number',
-                required: false,
+                required: true,
                 description: 'Ticket id'
             },
             {
-                arg: 'time',
-                type: 'number',
-                required: false,
+                arg: 'filename',
+                type: 'string',
+                required: true,
                 description: 'Time to add'
             },
             {
@@ -35,58 +35,58 @@ module.exports = Self => {
         },
     });
 
-    Self.getVideo = async(id, time, req, res, options) => {
+    Self.getVideo = async(id, filename, req, res, options) => {
         const models = Self.app.models;
         const myOptions = {};
-        // console.log('ENTRY');
+
+        console.log('getFile', filename);
         if (typeof options == 'object')
             Object.assign(myOptions, options);
 
-        const expedition = await models.Expedition.findById(id, null, myOptions);
         const packingSiteConfig = await models.PackingSiteConfig.findOne({}, myOptions);
-        const monitorId = 'Xme2hiqz1f';
-        // console.log(packingSiteConfig);
 
-        const addTime = (time ? time : packingSiteConfig.avgBoxingTime) * 1000;
-        const start = new Date(expedition.created);// '2022-07-27T09:00:00';// new Date('2022-07-27'); //
-        const end = new Date(start.getTime() + addTime);
-        // console.log(addTime);
-        // console.log(start.toString().split('.')[0]);
-        // console.log(end.toString().split('.')[0]);
+        const query = `
+                SELECT
+                    e.id,
+                    ps.monitorId,
+                    e.created
+                FROM expedition e
+                    JOIN host h ON Convert(h.code USING utf8mb3) COLLATE utf8mb3_unicode_ci = e.hostFk
+                    JOIN packingSite ps ON  ps.hostFk = h.id
+                WHERE e.id = ?;`;
+        const [expedition] = await models.Expedition.rawSql(query, [id]);
 
-        const videoUrl = `/${packingSiteConfig.shinobiToken}/videos/${packingSiteConfig.shinobiGroupKey}/${monitorId}`;
-        const timeUrl = `?start=${start.toString().split('.')[0]}&end=${end.toString().split('.')[0]}`;
-        const url = `${packingSiteConfig.shinobiUrl}${videoUrl}${timeUrl}&endIsStartTo`;
+        const monitorId = '6Ou0D1bhBw'; // expedition.monitorId
 
-        // console.log(url);
-        const videoList = await axios.post(url);
-        // console.log('videoList.data', videoList.data);
-        // console.log(videoList.data.videos);
-        // console.log(videoList.data.videos.length);
-        const length = videoList.data.videos.length;
-        // console.log(length);
-        if (!length) return [];
-
-        const lastVideo = videoList.data.videos[length - 1].href;
+        const videoUrl =
+            `/${packingSiteConfig.shinobiToken}/videos/${packingSiteConfig.shinobiGroupKey}/${monitorId}/${filename}`;
 
         const headers = Object.assign({}, req.headers, {
             host: 'shinobi.verdnatura.es'
         });
         const httpOptions = {
             host: 'shinobi.verdnatura.es',
-            path: '/BW4o7FZyJ85she1hlRDe6QnwW3jwEP/videos/xVqft9LFXg/Xme2hiqz1f/2022-08-02T11-45-01.mp4',
+            path: videoUrl,
             port: 443,
             headers
         };
+        console.log('shinobi.verdnatura.es' + videoUrl);
 
         return new Promise((resolve, reject) => {
-            const req = https.request(httpOptions,
-                shinobiRes => {
-                    shinobiRes.pause();
-                    res.writeHeader(shinobiRes.statusCode, shinobiRes.headers);
-                    shinobiRes.pipe(res);
-                    resolve();
-                });
+            const req = https.request(httpOptions, shinobiRes => {
+                console.log('entry');
+                shinobiRes.pause();
+                res.writeHeader(shinobiRes.statusCode, shinobiRes.headers);
+                shinobiRes.pipe(res);
+            });
+
+            req.on('error', error => {
+                console.error(error);
+            });
+
+            req.on('end', res => {
+                resolve();
+            });
             req.end();
         });
     };
diff --git a/modules/ticket/back/methods/boxing/getVideoList.js b/modules/ticket/back/methods/boxing/getVideoList.js
index cdc3555a74..4e74f76ecd 100644
--- a/modules/ticket/back/methods/boxing/getVideoList.js
+++ b/modules/ticket/back/methods/boxing/getVideoList.js
@@ -33,7 +33,7 @@ module.exports = Self => {
 
     Self.getVideoList = async(id, from, to, options) => {
         const myOptions = {};
-        console.log(id);
+
         if (typeof options == 'object')
             Object.assign(myOptions, options);
 
@@ -67,14 +67,15 @@ module.exports = Self => {
         const videoUrl = `/${packingSiteConfig.shinobiToken}/videos/${packingSiteConfig.shinobiGroupKey}/${monitorId}`;
         const timeUrl = `?start=${start.toISOString().split('.')[0]}&end=${end.toISOString().split('.')[0]}`;
         const url = `${packingSiteConfig.shinobiUrl}${videoUrl}${timeUrl}`;
-        console.log(url);
 
-        console.log('try get');
-        const response = await axios(url).then(res => {
-            return res;
-        });
-        console.log('finish get');
+        let response;
 
-        console.log(response);
+        try {
+            response = await axios.get(url);
+        } catch (e) {
+            console.log(e);
+            return [];
+        }
+        return response.data.videos.map(video => video.filename);
     };
 };
diff --git a/modules/ticket/back/models/boxing.js b/modules/ticket/back/models/boxing.js
index 81732d17ac..c251ea0e43 100644
--- a/modules/ticket/back/models/boxing.js
+++ b/modules/ticket/back/models/boxing.js
@@ -1,3 +1,4 @@
 module.exports = Self => {
     require('../methods/boxing/getVideo')(Self);
+    require('../methods/boxing/getVideoList')(Self);
 };

From 8dd02ab6ee2707ce1ebdfabb6020a22bcf3d16eb Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Tue, 6 Sep 2022 15:08:28 +0200
Subject: [PATCH 011/151] quit console.logs

---
 modules/ticket/back/methods/boxing/getVideo.js     | 13 ++++---------
 modules/ticket/back/methods/boxing/getVideoList.js | 11 ++++-------
 modules/ticket/front/boxing/index.html             |  3 ---
 3 files changed, 8 insertions(+), 19 deletions(-)

diff --git a/modules/ticket/back/methods/boxing/getVideo.js b/modules/ticket/back/methods/boxing/getVideo.js
index 8cecbad4d3..cdd46b2574 100644
--- a/modules/ticket/back/methods/boxing/getVideo.js
+++ b/modules/ticket/back/methods/boxing/getVideo.js
@@ -1,4 +1,3 @@
-const axios = require('axios');
 const https = require('https');
 
 module.exports = Self => {
@@ -39,7 +38,6 @@ module.exports = Self => {
         const models = Self.app.models;
         const myOptions = {};
 
-        console.log('getFile', filename);
         if (typeof options == 'object')
             Object.assign(myOptions, options);
 
@@ -55,8 +53,7 @@ module.exports = Self => {
                     JOIN packingSite ps ON  ps.hostFk = h.id
                 WHERE e.id = ?;`;
         const [expedition] = await models.Expedition.rawSql(query, [id]);
-
-        const monitorId = '6Ou0D1bhBw'; // expedition.monitorId
+        const monitorId = expedition.monitorId;
 
         const videoUrl =
             `/${packingSiteConfig.shinobiToken}/videos/${packingSiteConfig.shinobiGroupKey}/${monitorId}/${filename}`;
@@ -70,21 +67,19 @@ module.exports = Self => {
             port: 443,
             headers
         };
-        console.log('shinobi.verdnatura.es' + videoUrl);
 
         return new Promise((resolve, reject) => {
             const req = https.request(httpOptions, shinobiRes => {
-                console.log('entry');
                 shinobiRes.pause();
                 res.writeHeader(shinobiRes.statusCode, shinobiRes.headers);
                 shinobiRes.pipe(res);
             });
 
-            req.on('error', error => {
-                console.error(error);
+            req.on('error', () => {
+                reject();
             });
 
-            req.on('end', res => {
+            req.on('end', () => {
                 resolve();
             });
             req.end();
diff --git a/modules/ticket/back/methods/boxing/getVideoList.js b/modules/ticket/back/methods/boxing/getVideoList.js
index 4e74f76ecd..be6d48c46b 100644
--- a/modules/ticket/back/methods/boxing/getVideoList.js
+++ b/modules/ticket/back/methods/boxing/getVideoList.js
@@ -1,5 +1,4 @@
 const axios = require('axios');
-const https = require('https');
 const models = require('vn-loopback/server/server').models;
 
 module.exports = Self => {
@@ -49,9 +48,7 @@ module.exports = Self => {
                 JOIN packingSite ps ON  ps.hostFk = h.id
             WHERE e.id = ?;`;
         const [expedition] = await models.PackingSiteConfig.rawSql(query, [id]);
-
-        const monitorId = '6Ou0D1bhBw';
-        console.log(id, expedition);
+        console.log(expedition);
         if (!from && !expedition) return [];
         let start = new Date(expedition.created);
         let end = new Date(start.getTime() + (packingSiteConfig.avgBoxingTime * 1000));
@@ -63,8 +60,9 @@ module.exports = Self => {
         const offset = start.getTimezoneOffset();
         start = new Date(start.getTime() - (offset * 60 * 1000));
         end = new Date(end.getTime() - (offset * 60 * 1000));
-        console.log(start, end);
-        const videoUrl = `/${packingSiteConfig.shinobiToken}/videos/${packingSiteConfig.shinobiGroupKey}/${monitorId}`;
+
+        const videoUrl =
+            `/${packingSiteConfig.shinobiToken}/videos/${packingSiteConfig.shinobiGroupKey}/${expedition.monitorId}`;
         const timeUrl = `?start=${start.toISOString().split('.')[0]}&end=${end.toISOString().split('.')[0]}`;
         const url = `${packingSiteConfig.shinobiUrl}${videoUrl}${timeUrl}`;
 
@@ -73,7 +71,6 @@ module.exports = Self => {
         try {
             response = await axios.get(url);
         } catch (e) {
-            console.log(e);
             return [];
         }
         return response.data.videos.map(video => video.filename);
diff --git a/modules/ticket/front/boxing/index.html b/modules/ticket/front/boxing/index.html
index 17b2b475ae..7fb3b870e0 100644
--- a/modules/ticket/front/boxing/index.html
+++ b/modules/ticket/front/boxing/index.html
@@ -1,5 +1,2 @@
 <vn-card>
-    <video id="videobcg" muted controls class="video" autoplay>
-        <source src="http://localhost:5000/api/Boxings/getVideo?id=1" type="video/mp4">
-    </video>
 </vn-card>

From c06d2970ae91a3e4e3f44ec3d4d2c4de4721d86b Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Wed, 7 Sep 2022 13:58:39 +0200
Subject: [PATCH 012/151] test(boxing): getVideoList

---
 .../ticket/back/methods/boxing/getVideo.js    |  2 +-
 .../back/methods/boxing/getVideoList.js       |  4 +-
 .../back/methods/boxing/specs/getVideo.js     | 69 -------------------
 .../back/methods/boxing/specs/getVideoList.js | 35 ++++++++++
 4 files changed, 38 insertions(+), 72 deletions(-)
 delete mode 100644 modules/ticket/back/methods/boxing/specs/getVideo.js
 create mode 100644 modules/ticket/back/methods/boxing/specs/getVideoList.js

diff --git a/modules/ticket/back/methods/boxing/getVideo.js b/modules/ticket/back/methods/boxing/getVideo.js
index cdd46b2574..6f471e837f 100644
--- a/modules/ticket/back/methods/boxing/getVideo.js
+++ b/modules/ticket/back/methods/boxing/getVideo.js
@@ -2,7 +2,7 @@ const https = require('https');
 
 module.exports = Self => {
     Self.remoteMethod('getVideo', {
-        description: 'Get packing video of ticketId',
+        description: 'Get packing video',
         accessType: 'READ',
         accepts: [
             {
diff --git a/modules/ticket/back/methods/boxing/getVideoList.js b/modules/ticket/back/methods/boxing/getVideoList.js
index be6d48c46b..3d45a720d9 100644
--- a/modules/ticket/back/methods/boxing/getVideoList.js
+++ b/modules/ticket/back/methods/boxing/getVideoList.js
@@ -21,7 +21,7 @@ module.exports = Self => {
                 required: false,
             }
         ], returns: {
-            type: ['Object'],
+            type: ['object'],
             root: true
         },
         http: {
@@ -48,7 +48,7 @@ module.exports = Self => {
                 JOIN packingSite ps ON  ps.hostFk = h.id
             WHERE e.id = ?;`;
         const [expedition] = await models.PackingSiteConfig.rawSql(query, [id]);
-        console.log(expedition);
+
         if (!from && !expedition) return [];
         let start = new Date(expedition.created);
         let end = new Date(start.getTime() + (packingSiteConfig.avgBoxingTime * 1000));
diff --git a/modules/ticket/back/methods/boxing/specs/getVideo.js b/modules/ticket/back/methods/boxing/specs/getVideo.js
deleted file mode 100644
index ad5295f0c9..0000000000
--- a/modules/ticket/back/methods/boxing/specs/getVideo.js
+++ /dev/null
@@ -1,69 +0,0 @@
-const models = require('vn-loopback/server/server').models;
-
-xdescribe('sale canEdit()', () => {
-    it('should return true if the role is production regardless of the saleTrackings', async() => {
-        const tx = await models.Sale.beginTransaction({});
-
-        try {
-            const options = {transaction: tx};
-
-            const productionUserID = 49;
-            const ctx = {req: {accessToken: {userId: productionUserID}}};
-
-            const sales = [{id: 3}];
-
-            const result = await models.Sale.canEdit(ctx, sales, options);
-
-            expect(result).toEqual(true);
-
-            await tx.rollback();
-        } catch (e) {
-            await tx.rollback();
-            throw e;
-        }
-    });
-
-    it('should return true if the role is not production and none of the sales has saleTracking', async() => {
-        const tx = await models.Sale.beginTransaction({});
-
-        try {
-            const options = {transaction: tx};
-
-            const salesPersonUserID = 18;
-            const ctx = {req: {accessToken: {userId: salesPersonUserID}}};
-
-            const sales = [{id: 10}];
-
-            const result = await models.Sale.canEdit(ctx, sales, options);
-
-            expect(result).toEqual(true);
-
-            await tx.rollback();
-        } catch (e) {
-            await tx.rollback();
-            throw e;
-        }
-    });
-
-    it('should return false if any of the sales has a saleTracking record', async() => {
-        const tx = await models.Sale.beginTransaction({});
-
-        try {
-            const options = {transaction: tx};
-
-            const salesPersonUserID = 18;
-            const ctx = {req: {accessToken: {userId: salesPersonUserID}}};
-
-            const sales = [{id: 3}];
-
-            const result = await models.Sale.canEdit(ctx, sales, options);
-
-            expect(result).toEqual(false);
-
-            await tx.rollback();
-        } catch (e) {
-            await tx.rollback();
-            throw e;
-        }
-    });
-});
diff --git a/modules/ticket/back/methods/boxing/specs/getVideoList.js b/modules/ticket/back/methods/boxing/specs/getVideoList.js
new file mode 100644
index 0000000000..e703f4c035
--- /dev/null
+++ b/modules/ticket/back/methods/boxing/specs/getVideoList.js
@@ -0,0 +1,35 @@
+const models = require('vn-loopback/server/server').models;
+const axios = require('axios');
+
+describe('boxing getVideoList()', () => {
+    it('should return data', async() => {
+        const tx = await models.PackingSiteConfig.beginTransaction({});
+
+        try {
+            const options = {transaction: tx};
+
+            const params = {
+                id: 1,
+                from: 1,
+                to: 2
+            };
+
+            const response = {
+                data: {
+                    pipe: () => {},
+                    on: () => {},
+                }
+            };
+            spyOn(axios, 'get').and.returnValue(new Promise(resolve => resolve(response)));
+
+            const result = await models.Sale.canEdit(params, options);
+
+            expect(result).toEqual([]);
+
+            await tx.rollback();
+        } catch (e) {
+            await tx.rollback();
+            throw e;
+        }
+    });
+});

From 2a64fde57c74836804c639e7cd21cc2b2f43064f Mon Sep 17 00:00:00 2001
From: vicent <vicent@verdnatura.es>
Date: Thu, 22 Sep 2022 14:58:38 +0200
Subject: [PATCH 013/151] feat: add option "move expedition"

---
 modules/ticket/front/expedition/index.html | 119 ++++++++++++---------
 modules/ticket/front/expedition/index.js   |  11 ++
 2 files changed, 82 insertions(+), 48 deletions(-)

diff --git a/modules/ticket/front/expedition/index.html b/modules/ticket/front/expedition/index.html
index a41d368f6b..37e64fad59 100644
--- a/modules/ticket/front/expedition/index.html
+++ b/modules/ticket/front/expedition/index.html
@@ -8,54 +8,77 @@
     auto-load="true">
 </vn-crud-model>
 <vn-data-viewer model="model">
-    <vn-card class="vn-w-xl">
-    <vn-table model="model">
-        <vn-thead>
-            <vn-tr>
-                <vn-th></vn-th>
-                <vn-th field="itemFk" number>Expedition</vn-th>
-                <vn-th field="itemFk" number>Item</vn-th>
-                <vn-th field="packageItemName">Name</vn-th>
-                <vn-th field="freightItemName">Package type</vn-th>
-                <vn-th field="counter" number>Counter</vn-th>
-                <vn-th field="externalId" number>externalId</vn-th>
-                <vn-th field="created" expand>Created</vn-th>
-                <vn-th field="state" expand>State</vn-th>
-                <vn-th></vn-th>
-            </vn-tr>
-        </vn-thead>
-        <vn-tbody>
-            <vn-tr ng-repeat="expedition in expeditions">
-                <vn-td class="vn-px-md" style="width:30px; color:#FFA410;">
-                    <vn-icon-button icon="delete"
-                        ng-click="deleteExpedition.show(expedition.id)"
-                        vn-tooltip="Delete expedition">
-                    </vn-icon-button>
-                </vn-td>
-                <vn-td number expand>{{expedition.id | zeroFill:6}}</vn-td>
-                <vn-td number>
-                    <span
-                        ng-class="{link: expedition.packagingItemFk}"
-                        ng-click="itemDescriptor.show($event, expedition.packagingItemFk)">
-                        {{expedition.packagingFk}}
-                    </span>
-                </vn-td>
-                <vn-td>{{::expedition.packageItemName}}</vn-td>
-                <vn-td>{{::expedition.freightItemName}}</vn-td>
-                <vn-td number>{{::expedition.counter}}</vn-td>
-                <vn-td expand>{{::expedition.externalId}}</vn-td>
-                <vn-td shrink-datetime>{{::expedition.created | date:'dd/MM/yyyy HH:mm'}}</vn-td>
-                <vn-td>{{::expedition.state}}</vn-td>
-                <vn-td>
-                    <vn-icon-button
-                        vn-click-stop="$ctrl.showLog(expedition)"
-                        vn-tooltip="Status log"
-                        icon="history">
-                    </vn-icon-button>
-                </vn-td>
-            </vn-tr>
-        </vn-tbody>
-    </vn-table>
+    <vn-card class="vn-pa-lg">
+        <vn-horizontal class="header">
+            <vn-tool-bar class="vn-mb-md">
+                <vn-button icon="keyboard_arrow_down"
+                    label="More"
+                    ng-click="moreOptions.show($event)"
+                    ng-show="$ctrl.hasSelectedSales()">
+                </vn-button>
+                <vn-button 
+                    disabled="!$ctrl.hasSelectedSales() || !$ctrl.isEditable"
+                    icon="delete"
+                    ng-click="deleteExpedition.show(expedition.id)"
+                    vn-tooltip="Delete expedition">
+                </vn-button>
+            </vn-tool-bar>
+            <vn-one class="taxes" ng-if="$ctrl.sales.length > 0">
+                <p><vn-label translate>Subtotal</vn-label> {{$ctrl.ticket.totalWithoutVat | currency: 'EUR':2}}</p>
+                <p><vn-label translate>VAT</vn-label> {{$ctrl.ticket.totalWithVat - $ctrl.ticket.totalWithoutVat | currency: 'EUR':2}}</p>
+                <p><vn-label><strong>Total</strong></vn-label> <strong>{{$ctrl.ticket.totalWithVat | currency: 'EUR':2}}</strong></p>
+            </vn-one>
+        </vn-horizontal>
+        <vn-table model="model">
+            <vn-thead>
+                <vn-tr>
+                    <vn-th shrink>
+                        <vn-multi-check 
+                            model="model">
+                        </vn-multi-check>
+                    </vn-th>
+                    <vn-th field="itemFk" number>Expedition</vn-th>
+                    <vn-th field="itemFk" number>Item</vn-th>
+                    <vn-th field="packageItemName">Name</vn-th>
+                    <vn-th field="freightItemName">Package type</vn-th>
+                    <vn-th field="counter" number>Counter</vn-th>
+                    <vn-th field="externalId" number>externalId</vn-th>
+                    <vn-th field="created" expand>Created</vn-th>
+                    <vn-th field="state" expand>State</vn-th>
+                    <vn-th></vn-th>
+                </vn-tr>
+            </vn-thead>
+            <vn-tbody>
+                <vn-tr ng-repeat="expedition in expeditions">
+                    <vn-td shrink>
+                        <vn-check tabindex="-1"
+                            ng-model="expedition.checked">
+                        </vn-check>
+                    </vn-td>
+                    <vn-td number expand>{{expedition.id | zeroFill:6}}</vn-td>
+                    <vn-td number>
+                        <span
+                            ng-class="{link: expedition.packagingItemFk}"
+                            ng-click="itemDescriptor.show($event, expedition.packagingItemFk)">
+                            {{expedition.packagingFk}}
+                        </span>
+                    </vn-td>
+                    <vn-td>{{::expedition.packageItemName}}</vn-td>
+                    <vn-td>{{::expedition.freightItemName}}</vn-td>
+                    <vn-td number>{{::expedition.counter}}</vn-td>
+                    <vn-td expand>{{::expedition.externalId}}</vn-td>
+                    <vn-td shrink-datetime>{{::expedition.created | date:'dd/MM/yyyy HH:mm'}}</vn-td>
+                    <vn-td>{{::expedition.state}}</vn-td>
+                    <vn-td>
+                        <vn-icon-button
+                            vn-click-stop="$ctrl.showLog(expedition)"
+                            vn-tooltip="Status log"
+                            icon="history">
+                        </vn-icon-button>
+                    </vn-td>
+                </vn-tr>
+            </vn-tbody>
+        </vn-table>
     </vn-card>
 </vn-data-viewer>
 <vn-item-descriptor-popover
diff --git a/modules/ticket/front/expedition/index.js b/modules/ticket/front/expedition/index.js
index 120d89bb29..adbbc53d4e 100644
--- a/modules/ticket/front/expedition/index.js
+++ b/modules/ticket/front/expedition/index.js
@@ -11,6 +11,17 @@ class Controller extends Section {
         this.expedition = expedition;
         this.$.statusLog.show();
     }
+
+    get checked() {
+        const rows = this.$.model.data || [];
+        const checkedRows = [];
+        for (let row of rows) {
+            if (row.checked)
+                checkedRows.push(row);
+        }
+
+        return checkedRows;
+    }
 }
 
 ngModule.vnComponent('vnTicketExpedition', {

From c4649352a93af6b9b7e0157b5f3f5498092b2329 Mon Sep 17 00:00:00 2001
From: vicent <vicent@verdnatura.es>
Date: Fri, 23 Sep 2022 08:50:11 +0200
Subject: [PATCH 014/151] feat: add totalChecked

---
 modules/ticket/front/expedition/index.html | 20 ++++++++++++++++----
 modules/ticket/front/expedition/index.js   |  4 ++++
 2 files changed, 20 insertions(+), 4 deletions(-)

diff --git a/modules/ticket/front/expedition/index.html b/modules/ticket/front/expedition/index.html
index 37e64fad59..3a5d5f8a6d 100644
--- a/modules/ticket/front/expedition/index.html
+++ b/modules/ticket/front/expedition/index.html
@@ -12,12 +12,11 @@
         <vn-horizontal class="header">
             <vn-tool-bar class="vn-mb-md">
                 <vn-button icon="keyboard_arrow_down"
-                    label="More"
+                    label="Move"
                     ng-click="moreOptions.show($event)"
-                    ng-show="$ctrl.hasSelectedSales()">
+                    ng-show="$ctrl.totalChecked">
                 </vn-button>
                 <vn-button 
-                    disabled="!$ctrl.hasSelectedSales() || !$ctrl.isEditable"
                     icon="delete"
                     ng-click="deleteExpedition.show(expedition.id)"
                     vn-tooltip="Delete expedition">
@@ -134,4 +133,17 @@
     <vn-worker-descriptor-popover 
         vn-id="workerDescriptor">
     </vn-worker-descriptor-popover>
-</vn-popup>
\ No newline at end of file
+</vn-popup>
+
+<vn-menu vn-id="moreOptions">
+    <vn-item translate
+        name="sms"
+        ng-click="$ctrl.showSMSDialog()">
+        New ticket without route
+    </vn-item>
+    <vn-item translate
+        name="calculatePrice"
+        ng-click="$ctrl.calculateSalePrice()">
+        New ticket with route
+    </vn-item>
+</vn-menu>
\ No newline at end of file
diff --git a/modules/ticket/front/expedition/index.js b/modules/ticket/front/expedition/index.js
index adbbc53d4e..38d02f5484 100644
--- a/modules/ticket/front/expedition/index.js
+++ b/modules/ticket/front/expedition/index.js
@@ -22,6 +22,10 @@ class Controller extends Section {
 
         return checkedRows;
     }
+
+    get totalChecked() {
+        return this.checked.length;
+    }
 }
 
 ngModule.vnComponent('vnTicketExpedition', {

From 2c691eb796b29fed91d2a96ed8dbcc57bccde866 Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Mon, 26 Sep 2022 14:49:11 +0200
Subject: [PATCH 015/151] feat(vnApp): getUrl and create salix.url.
 test(boxing): getVideoList

---
 back/model-config.json                        |  3 ++
 back/models/url.json                          | 25 ++++++++++++
 .../10490-august/00-packingSiteConfig.sql     |  2 +-
 db/changes/10490-august/00-salix_url.sql      | 33 +++++++++++++++
 front/core/services/app.js                    | 17 ++++++++
 .../methods/boxing/specs/getVideo.spec.js     | 40 +++++++++++++++++++
 .../{getVideoList.js => getVideoList.spec.js} | 21 +++++-----
 modules/ticket/front/boxing/index.js          | 17 ++------
 8 files changed, 133 insertions(+), 25 deletions(-)
 create mode 100644 back/models/url.json
 create mode 100644 db/changes/10490-august/00-salix_url.sql
 create mode 100644 modules/ticket/back/methods/boxing/specs/getVideo.spec.js
 rename modules/ticket/back/methods/boxing/specs/{getVideoList.js => getVideoList.spec.js} (58%)

diff --git a/back/model-config.json b/back/model-config.json
index f4adc954b0..5f1c0bbe2e 100644
--- a/back/model-config.json
+++ b/back/model-config.json
@@ -101,6 +101,9 @@
     "Town": {
         "dataSource": "vn"
     },
+    "Url": {
+        "dataSource": "vn"
+    },
     "UserConfig": {
         "dataSource": "vn"
     },
diff --git a/back/models/url.json b/back/models/url.json
new file mode 100644
index 0000000000..8610ff28b6
--- /dev/null
+++ b/back/models/url.json
@@ -0,0 +1,25 @@
+{
+    "name": "Url",
+    "base": "VnModel",
+    "options": {
+        "mysql": {
+            "table": "salix.url"
+        }
+    },
+    "properties": {
+        "appName": {
+            "type": "string",
+            "required": true,
+            "id": 1
+        },
+        "environment": {
+            "type": "string",
+            "required": true,
+            "id": 2
+        },
+        "url": {
+            "type": "string",
+            "required": true
+        }
+    }
+}
diff --git a/db/changes/10490-august/00-packingSiteConfig.sql b/db/changes/10490-august/00-packingSiteConfig.sql
index bbd0b32def..dc5e4c5cfc 100644
--- a/db/changes/10490-august/00-packingSiteConfig.sql
+++ b/db/changes/10490-august/00-packingSiteConfig.sql
@@ -11,7 +11,7 @@ INSERT INTO `vn`.`packingSiteConfig` SET
     shinobiUrl = 'https://shinobi.verdnatura.es',
     shinobiToken = 'BW4o7FZyJ85she1hlRDe6QnwW3jwEP',
     shinobiGroupKey = 'xVqft9LFXg',
-    avgBoxingTime = 30;
+    avgBoxingTime = 6000;
 
 INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
     VALUES
diff --git a/db/changes/10490-august/00-salix_url.sql b/db/changes/10490-august/00-salix_url.sql
new file mode 100644
index 0000000000..ea5c3b6064
--- /dev/null
+++ b/db/changes/10490-august/00-salix_url.sql
@@ -0,0 +1,33 @@
+CREATE TABLE `salix`.`url` (
+	`appName` varchar(100) NOT NULL,
+	`environment` varchar(100) NOT NULL,
+	`url` varchar(255) NOT NULL,
+    PRIMARY KEY (`appName`,`environment`)
+);
+
+INSERT INTO `salix`.`url` (`appName`, `environment`, `url`)
+    VALUES
+        ('salix', 'production', 'https://salix.verdnatura.es/#!/');
+INSERT INTO `salix`.`url` (`appName`, `environment`, `url`)
+    VALUES
+        ('salix', 'test', 'https://test-salix.verdnatura.es/#!/');
+INSERT INTO `salix`.`url` (`appName`, `environment`, `url`)
+    VALUES
+        ('salix', 'dev', 'http://localhost:5000/#!/');
+INSERT INTO `salix`.`url` (`appName`, `environment`, `url`)
+    VALUES
+        ('lilium', 'production', 'https://lilium.verdnatura.es/#/');
+INSERT INTO `salix`.`url` (`appName`, `environment`, `url`)
+    VALUES
+        ('lilium', 'test', 'https://test-lilium.verdnatura.es/#/');
+INSERT INTO `salix`.`url` (`appName`, `environment`, `url`)
+    VALUES
+        ('lilium', 'dev', 'http://localhost:8080/#/');
+
+INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
+    VALUES
+        ('Url', '*', 'READ', 'ALLOW', 'ROLE', 'employee');
+
+INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
+    VALUES
+        ('Url', '*', 'WRITE', 'ALLOW', 'ROLE', 'it');
diff --git a/front/core/services/app.js b/front/core/services/app.js
index 889b24d01b..37bddeca04 100644
--- a/front/core/services/app.js
+++ b/front/core/services/app.js
@@ -54,6 +54,23 @@ export default class App {
             localStorage.setItem('salix-version', newVersion);
         }
     }
+
+    getUrl(route, appName) {
+        if (!appName) appName = 'lilium';
+
+        const env = process.env.NODE_ENV;
+        const filter = {
+            where: {and: [
+                {appName: appName},
+                {environment: env}
+            ]}
+        };
+
+        return this.logger.$http.get('Urls/findOne', {filter})
+            .then(res => {
+                return res.data.url + route;
+            });
+    }
 }
 
 ngModule.service('vnApp', App);
diff --git a/modules/ticket/back/methods/boxing/specs/getVideo.spec.js b/modules/ticket/back/methods/boxing/specs/getVideo.spec.js
new file mode 100644
index 0000000000..8e8cdc5b98
--- /dev/null
+++ b/modules/ticket/back/methods/boxing/specs/getVideo.spec.js
@@ -0,0 +1,40 @@
+const models = require('vn-loopback/server/server').models;
+const https = require('https');
+
+xdescribe('boxing getVideo()', () => {
+    it('should return data', async() => {
+        const tx = await models.PackingSiteConfig.beginTransaction({});
+
+        try {
+            const options = {transaction: tx};
+
+            const id = 1;
+            const video = 'video.mp4';
+
+            const response = {
+                pipe: () => {},
+                on: () => {},
+                end: () => {},
+            };
+
+            const req = {
+                headers: 'apiHeader',
+                data: {
+                    pipe: () => {},
+                    on: () => {},
+                }
+            };
+
+            spyOn(https, 'request').and.returnValue(response);
+
+            const result = await models.Boxing.getVideo(id, video, req, null, options);
+
+            expect(result[0]).toEqual(response.data.videos[0].filename);
+
+            await tx.rollback();
+        } catch (e) {
+            await tx.rollback();
+            throw e;
+        }
+    });
+});
diff --git a/modules/ticket/back/methods/boxing/specs/getVideoList.js b/modules/ticket/back/methods/boxing/specs/getVideoList.spec.js
similarity index 58%
rename from modules/ticket/back/methods/boxing/specs/getVideoList.js
rename to modules/ticket/back/methods/boxing/specs/getVideoList.spec.js
index e703f4c035..c6d1a3e07c 100644
--- a/modules/ticket/back/methods/boxing/specs/getVideoList.js
+++ b/modules/ticket/back/methods/boxing/specs/getVideoList.spec.js
@@ -2,29 +2,30 @@ const models = require('vn-loopback/server/server').models;
 const axios = require('axios');
 
 describe('boxing getVideoList()', () => {
-    it('should return data', async() => {
+    it('should return video list', async() => {
         const tx = await models.PackingSiteConfig.beginTransaction({});
 
         try {
             const options = {transaction: tx};
 
-            const params = {
-                id: 1,
-                from: 1,
-                to: 2
-            };
+            const id = 1;
+            const from = 1;
+            const to = 2;
 
             const response = {
                 data: {
-                    pipe: () => {},
-                    on: () => {},
+                    videos: [{
+                        id: 1,
+                        filename: 'video1.mp4'
+                    }]
                 }
             };
+
             spyOn(axios, 'get').and.returnValue(new Promise(resolve => resolve(response)));
 
-            const result = await models.Sale.canEdit(params, options);
+            const result = await models.Boxing.getVideoList(id, from, to, options);
 
-            expect(result).toEqual([]);
+            expect(result[0]).toEqual(response.data.videos[0].filename);
 
             await tx.rollback();
         } catch (e) {
diff --git a/modules/ticket/front/boxing/index.js b/modules/ticket/front/boxing/index.js
index 686bf7d01f..4e6b398f2f 100644
--- a/modules/ticket/front/boxing/index.js
+++ b/modules/ticket/front/boxing/index.js
@@ -6,20 +6,9 @@ class Controller extends Section {
         super($element, $);
     }
 
-    $onInit() {
-        window.location.href = this.lilium(`ticket/${this.ticket.id}/boxing`);
-    }
-
-    lilium(route) {
-        const env = process.env.NODE_ENV;
-        let newRoute = 'http://localhost:8080/#/' + route;
-
-        if (env == 'test')
-            newRoute = 'https://test-lilium.verdnatura.es/#/' + route;
-        if (env == 'producction')
-            newRoute = 'https://lilium.verdnatura.es/#/' + route;
-
-        return newRoute;
+    async $onInit() {
+        const url = await this.vnApp.getUrl(`ticket/${this.$params.id}/boxing`);
+        window.open(url).focus();
     }
 }
 

From 8082e3071ad2e35d163cff01838372a4682dbde7 Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Tue, 27 Sep 2022 15:17:54 +0200
Subject: [PATCH 016/151] try

---
 front/core/components/searchbar/searchbar.js | 82 +++++++++++++++++++-
 front/core/components/smart-table/index.html |  4 +
 front/core/components/smart-table/index.js   | 82 +++++++++++++++++---
 3 files changed, 152 insertions(+), 16 deletions(-)

diff --git a/front/core/components/searchbar/searchbar.js b/front/core/components/searchbar/searchbar.js
index 89b5d7df69..fc194bc597 100644
--- a/front/core/components/searchbar/searchbar.js
+++ b/front/core/components/searchbar/searchbar.js
@@ -139,8 +139,12 @@ export default class Searchbar extends Component {
     }
 
     removeParam(index) {
+        const field = this.params[index].key;
+        this.filterSanitizer(field);
+
         this.params.splice(index, 1);
-        this.doSearch(this.fromBar(), 'bar');
+        this.toRemove = field;
+        this.doSearch(this.fromBar(), 'removeBar');
     }
 
     fromBar() {
@@ -163,7 +167,7 @@ export default class Searchbar extends Component {
 
         let keys = Object.keys(filter);
         keys.forEach(key => {
-            if (key == 'search') return;
+            if (key == 'search' || key == 'tableQ') return;
             let value = filter[key];
             let chip;
 
@@ -195,9 +199,10 @@ export default class Searchbar extends Component {
 
     doSearch(filter, source) {
         if (filter === this.filter && source != 'state') return;
-        let promise = this.onSearch({$params: filter});
+        let promise = this.onSearch({$params: filter}, source);
         promise = promise || this.$q.resolve();
         promise.then(data => this.onFilter(filter, source, data));
+        this.toBar(filter);
     }
 
     onFilter(filter, source, data) {
@@ -247,8 +252,15 @@ export default class Searchbar extends Component {
 
         this.filter = filter;
 
+        if (source == 'removeBar') {
+            delete params[this.toRemove];
+            delete this.model.userParams[this.toRemove];
+            this.model.refresh();
+        }
+
         if (!filter && this.model)
             this.model.clear();
+
         if (source != 'state')
             this.transition = this.$state.go(state, params, opts).transition;
         if (source != 'bar' && (source != 'state' || this.$state.is(this.baseState)))
@@ -270,6 +282,12 @@ export default class Searchbar extends Component {
             return;
         }
 
+        if (Object.keys(filter).length === 0) {
+            this.filterSanitizer('search');
+            if (this.model.userParams)
+                delete this.model.userParams['search'];
+        }
+
         let where = null;
         let params = null;
 
@@ -283,9 +301,65 @@ export default class Searchbar extends Component {
                 params = this.fetchParams({$params: params});
         }
 
-        return this.model.applyFilter(where ? {where} : null, params)
+        if (this.$params.q)
+            Object.assign(params, JSON.parse(this.$params.q));
+
+        return this.model.addFilter(where ? {where} : null, params)
             .then(() => this.model.data);
     }
+
+    filterSanitizer(field) {
+        const userFilter = this.model.userFilter;
+        const userParams = this.model.userParams;
+        const where = userFilter && userFilter.where;
+        delete this.$params.q[field];
+
+        if (this.exprBuilder) {
+            const param = this.exprBuilder({
+                param: field,
+                value: null
+            });
+            if (param) [field] = Object.keys(param);
+        }
+
+        if (!where) return;
+
+        const whereKeys = Object.keys(where);
+        for (let key of whereKeys) {
+            removeProp(where, field, key);
+
+            if (Object.keys(where).length == 0)
+                delete userFilter.where;
+        }
+
+        function removeProp(obj, targetProp, prop) {
+            if (prop == targetProp)
+                delete obj[prop];
+
+            if (prop === 'and' || prop === 'or' && obj[prop]) {
+                const arrayCopy = obj[prop].slice();
+                for (let param of arrayCopy) {
+                    const [key] = Object.keys(param);
+                    const index = obj[prop].findIndex(param => {
+                        return Object.keys(param)[0] == key;
+                    });
+                    if (key == targetProp)
+                        obj[prop].splice(index, 1);
+
+                    if (param[key] instanceof Array)
+                        removeProp(param, field, key);
+
+                    if (Object.keys(param).length == 0)
+                        obj[prop].splice(index, 1);
+                }
+
+                if (obj[prop].length == 0)
+                    delete obj[prop];
+            }
+        }
+
+        return {userFilter, userParams};
+    }
 }
 
 ngModule.vnComponent('vnSearchbar', {
diff --git a/front/core/components/smart-table/index.html b/front/core/components/smart-table/index.html
index f26a6b4a2d..3168d7ee73 100644
--- a/front/core/components/smart-table/index.html
+++ b/front/core/components/smart-table/index.html
@@ -103,3 +103,7 @@
         </div>
     </tpl-body>
 </vn-popover>
+<vn-button
+    label="TEST"
+    ng-click="$ctrl.test()">
+</vn-button>
diff --git a/front/core/components/smart-table/index.js b/front/core/components/smart-table/index.js
index 9e6e7009c9..7880f257fd 100644
--- a/front/core/components/smart-table/index.js
+++ b/front/core/components/smart-table/index.js
@@ -15,9 +15,15 @@ export default class SmartTable extends Component {
         this.$inputsScope;
         this.columns = [];
         this.autoSave = false;
+        this.autoState = true;
         this.transclude();
     }
 
+    $onInit() {
+        if (this.model)
+            this.defaultFilter();
+    }
+
     $onDestroy() {
         const styleElement = document.querySelector('style[id="smart-table"]');
         if (this.$.css && styleElement)
@@ -49,6 +55,7 @@ export default class SmartTable extends Component {
         this._model = value;
         if (value) {
             this.$.model = value;
+            this.defaultFilter();
             this.defaultOrder();
         }
     }
@@ -160,6 +167,26 @@ export default class SmartTable extends Component {
         }
     }
 
+    defaultFilter() {
+        if (!this.$params.q) return;
+        const stateFilter = JSON.parse(this.$params.q).tableQ;
+        if (!stateFilter || !this.exprBuilder) return;
+
+        const columns = this.columns.map(column => column.field);
+
+        this.displaySearch();
+        if (!this.$inputsScope.searchProps)
+            this.$inputsScope.searchProps = {};
+
+        for (let param in stateFilter) {
+            if (columns.includes(param)) {
+                const whereParams = {[param]: stateFilter[param]};
+                Object.assign(this.$inputsScope.searchProps, whereParams);
+                this.addFilter(param, stateFilter[param]);
+            }
+        }
+    }
+
     defaultOrder() {
         const order = this.model.order;
         if (!order) return;
@@ -394,29 +421,56 @@ export default class SmartTable extends Component {
         this.searchByColumn(field);
     }
 
-    searchByColumn(field) {
-        const searchCriteria = this.$inputsScope.searchProps[field];
-        const emptySearch = searchCriteria === '' || searchCriteria == null;
+    searchPropsSanitizer() {
+        if (!this.$inputsScope || !this.$inputsScope.searchProps) return null;
+        let searchProps = this.$inputsScope.searchProps;
+        const searchPropsArray = Object.entries(searchProps);
+        searchProps = searchPropsArray.filter(
+            ([key, value]) => value && value != ''
+        );
 
+        return Object.fromEntries(searchProps);
+    }
+
+    searchByColumn(field) {
         const filters = this.filterSanitizer(field);
 
         if (filters && filters.userFilter)
             this.model.userFilter = filters.userFilter;
-        if (!emptySearch)
-            this.addFilter(field, this.$inputsScope.searchProps[field]);
-        else this.model.refresh();
+        this.addFilter(field, this.$inputsScope.searchProps[field]);
     }
 
     addFilter(field, value) {
-        let where = {[field]: value};
+        if (value == '') value = null;
 
-        if (this.exprBuilder) {
-            where = buildFilter(where, (param, value) =>
-                this.exprBuilder({param, value})
-            );
+        let filterState;
+        if (this.$params.q) {
+            filterState = JSON.parse(this.$params.q);
+            delete filterState.tableQ[field];
         }
 
-        this.model.addFilter({where});
+        const whereParams = {[field]: value};
+        if (value) {
+            let where = {[field]: value};
+            if (this.exprBuilder) {
+                where = buildFilter(whereParams, (param, value) =>
+                    this.exprBuilder({param, value})
+                );
+            }
+            this.model.addFilter({where});
+        }
+
+        const searchProps = this.searchPropsSanitizer();
+
+        if (filterState.tableQ)
+            Object.assign(searchProps, filterState.tableQ);
+
+        Object.assign(filterState.tableQ, searchProps);
+
+        const params = {q: JSON.stringify(filterState)};
+
+        this.$state.go(this.$state.current.name, params, {location: 'replace'});
+        this.model.refresh();
     }
 
     applySort() {
@@ -517,6 +571,10 @@ export default class SmartTable extends Component {
         this.model.refresh()
             .then(() => this.isRefreshing = false);
     }
+
+    test() {
+        console.log('USER_FILTER', this.model.userFilter, 'USER_PARAMS', this.model.userParams);
+    }
 }
 
 SmartTable.$inject = ['$element', '$scope', '$transclude'];

From 4df99a82e1a9f7cce8602fd07bbef9cdb99c6d4f Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Wed, 28 Sep 2022 11:22:29 +0200
Subject: [PATCH 017/151] feat(tableOrder): save order in url

---
 e2e/paths/04-item/01_summary.spec.js         |  2 +-
 front/core/components/searchbar/searchbar.js | 15 ++++----
 front/core/components/smart-table/index.js   | 36 +++++++++++++++-----
 3 files changed, 37 insertions(+), 16 deletions(-)

diff --git a/e2e/paths/04-item/01_summary.spec.js b/e2e/paths/04-item/01_summary.spec.js
index e24fa6a9f1..373ceb95a5 100644
--- a/e2e/paths/04-item/01_summary.spec.js
+++ b/e2e/paths/04-item/01_summary.spec.js
@@ -1,7 +1,7 @@
 import selectors from '../../helpers/selectors.js';
 import getBrowser from '../../helpers/puppeteer';
 
-describe('Item summary path', () => {
+fdescribe('Item summary path', () => {
     let browser;
     let page;
     beforeAll(async() => {
diff --git a/front/core/components/searchbar/searchbar.js b/front/core/components/searchbar/searchbar.js
index fc194bc597..50f9d00505 100644
--- a/front/core/components/searchbar/searchbar.js
+++ b/front/core/components/searchbar/searchbar.js
@@ -167,7 +167,7 @@ export default class Searchbar extends Component {
 
         let keys = Object.keys(filter);
         keys.forEach(key => {
-            if (key == 'search' || key == 'tableQ') return;
+            if (key == 'search' || key == 'tableQ' || key == 'tableOrder') return;
             let value = filter[key];
             let chip;
 
@@ -281,7 +281,6 @@ export default class Searchbar extends Component {
             this.model.clear();
             return;
         }
-
         if (Object.keys(filter).length === 0) {
             this.filterSanitizer('search');
             if (this.model.userParams)
@@ -301,10 +300,12 @@ export default class Searchbar extends Component {
                 params = this.fetchParams({$params: params});
         }
 
-        if (this.$params.q)
+        if (this.$params.q) {
             Object.assign(params, JSON.parse(this.$params.q));
-
-        return this.model.addFilter(where ? {where} : null, params)
+            return this.model.addFilter(where ? {where} : null, params)
+                .then(() => this.model.data);
+        }
+        return this.model.applyFilter(where ? {where} : null, params)
             .then(() => this.model.data);
     }
 
@@ -312,7 +313,9 @@ export default class Searchbar extends Component {
         const userFilter = this.model.userFilter;
         const userParams = this.model.userParams;
         const where = userFilter && userFilter.where;
-        delete this.$params.q[field];
+
+        if (this.$params.q)
+            delete this.$params.q[field];
 
         if (this.exprBuilder) {
             const param = this.exprBuilder({
diff --git a/front/core/components/smart-table/index.js b/front/core/components/smart-table/index.js
index 7880f257fd..c78cbbca0d 100644
--- a/front/core/components/smart-table/index.js
+++ b/front/core/components/smart-table/index.js
@@ -188,7 +188,12 @@ export default class SmartTable extends Component {
     }
 
     defaultOrder() {
-        const order = this.model.order;
+        let stateOrder;
+        if (this.$params.q)
+            stateOrder = JSON.parse(this.$params.q).tableOrder;
+
+        const order = stateOrder ? stateOrder : this.model.order;
+
         if (!order) return;
 
         const orderFields = order.split(', ');
@@ -222,6 +227,9 @@ export default class SmartTable extends Component {
                 this.setPriority(column.element, priority);
             }
         }
+
+        this.model.order = order;
+        this.model.refresh();
     }
 
     registerColumns() {
@@ -443,10 +451,12 @@ export default class SmartTable extends Component {
     addFilter(field, value) {
         if (value == '') value = null;
 
-        let filterState;
+        let stateFilter = {tableQ: {}};
         if (this.$params.q) {
-            filterState = JSON.parse(this.$params.q);
-            delete filterState.tableQ[field];
+            stateFilter = JSON.parse(this.$params.q);
+            if (!stateFilter.tableQ)
+                stateFilter.tableQ = {};
+            delete stateFilter.tableQ[field];
         }
 
         const whereParams = {[field]: value};
@@ -462,12 +472,9 @@ export default class SmartTable extends Component {
 
         const searchProps = this.searchPropsSanitizer();
 
-        if (filterState.tableQ)
-            Object.assign(searchProps, filterState.tableQ);
+        Object.assign(stateFilter.tableQ, searchProps);
 
-        Object.assign(filterState.tableQ, searchProps);
-
-        const params = {q: JSON.stringify(filterState)};
+        const params = {q: JSON.stringify(stateFilter)};
 
         this.$state.go(this.$state.current.name, params, {location: 'replace'});
         this.model.refresh();
@@ -480,6 +487,17 @@ export default class SmartTable extends Component {
         if (order)
             this.model.order = order;
 
+        let stateFilter = {tableOrder: {}};
+        if (this.$params.q) {
+            stateFilter = JSON.parse(this.$params.q);
+            if (!stateFilter.tableOrder)
+                stateFilter.tableOrder = {};
+        }
+
+        stateFilter.tableOrder = order;
+
+        const params = {q: JSON.stringify(stateFilter)};
+        this.$state.go(this.$state.current.name, params, {location: 'replace'});
         this.model.refresh();
     }
 

From 84003ab09cff510def09ab0100ada39433a9af28 Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Thu, 29 Sep 2022 12:36:16 +0200
Subject: [PATCH 018/151] fix(searchbar): smart-table.tableQ integration

---
 e2e/helpers/selectors.js                      | 11 ++-
 ..._smartTable_searchBar_integrations.spec.js | 77 +++++++++++++++++++
 e2e/paths/04-item/01_summary.spec.js          |  2 +-
 .../core/components/crud-model/crud-model.js  | 12 +++
 front/core/components/searchbar/searchbar.js  | 59 ++++++++++++--
 .../components/searchbar/searchbar.spec.js    |  7 +-
 6 files changed, 156 insertions(+), 12 deletions(-)
 create mode 100644 e2e/paths/01-salix/03_smartTable_searchBar_integrations.spec.js

diff --git a/e2e/helpers/selectors.js b/e2e/helpers/selectors.js
index 0ad9ad7f40..c8e0ae1684 100644
--- a/e2e/helpers/selectors.js
+++ b/e2e/helpers/selectors.js
@@ -392,10 +392,16 @@ export default {
         originCheckbox: '.vn-popover.shown vn-horizontal:nth-child(3) > vn-check[label="Origin"]',
         buyerCheckbox: '.vn-popover.shown vn-horizontal:nth-child(3) > vn-check[label="Buyer"]',
         densityCheckbox: '.vn-popover.shown vn-horizontal:nth-child(3) > vn-check[label="Density"]',
-        saveFieldsButton: '.vn-popover.shown vn-button[label="Save"] > button'
+        saveFieldsButton: '.vn-popover.shown vn-button[label="Save"] > button',
+        openAdvancedSearchButton: 'vn-searchbar .append vn-icon[icon="arrow_drop_down"]',
+        advancedSearchItemType: 'vn-item-search-panel vn-autocomplete[ng-model="filter.typeFk"]',
+        advancedSearchButton: 'vn-item-search-panel button[type=submit]',
+        advancedSmartTableButton: 'vn-item-index vn-button[icon="search"]',
+        advancedSmartTableGrouping: 'vn-item-index vn-textfield[name=grouping]',
     },
     itemFixedPrice: {
         add: 'vn-fixed-price vn-icon-button[icon="add_circle"]',
+        firstItemID: 'vn-fixed-price tr:nth-child(2) vn-autocomplete[ng-model="price.itemFk"]',
         fourthFixedPrice: 'vn-fixed-price tr:nth-child(5)',
         fourthItemID: 'vn-fixed-price tr:nth-child(5) vn-autocomplete[ng-model="price.itemFk"]',
         fourthWarehouse: 'vn-fixed-price tr:nth-child(5) vn-autocomplete[ng-model="price.warehouseFk"]',
@@ -405,7 +411,8 @@ export default {
         fourthMinPrice: 'vn-fixed-price tr:nth-child(5) >  td:nth-child(6) > vn-input-number[ng-model="price.minPrice"]',
         fourthStarted: 'vn-fixed-price tr:nth-child(5) vn-date-picker[ng-model="price.started"]',
         fourthEnded: 'vn-fixed-price tr:nth-child(5) vn-date-picker[ng-model="price.ended"]',
-        fourthDeleteIcon: 'vn-fixed-price tr:nth-child(5) > td:nth-child(9) > vn-icon-button[icon="delete"]'
+        fourthDeleteIcon: 'vn-fixed-price tr:nth-child(5) > td:nth-child(9) > vn-icon-button[icon="delete"]',
+        orderColumnId: 'vn-fixed-price th[field="itemFk"]'
     },
     itemCreateView: {
         temporalName: 'vn-item-create vn-textfield[ng-model="$ctrl.item.provisionalName"]',
diff --git a/e2e/paths/01-salix/03_smartTable_searchBar_integrations.spec.js b/e2e/paths/01-salix/03_smartTable_searchBar_integrations.spec.js
new file mode 100644
index 0000000000..4fc2802098
--- /dev/null
+++ b/e2e/paths/01-salix/03_smartTable_searchBar_integrations.spec.js
@@ -0,0 +1,77 @@
+import selectors from '../../helpers/selectors.js';
+import getBrowser from '../../helpers/puppeteer';
+
+describe('SmartTable SearchBar integration', () => {
+    let browser;
+    let page;
+    beforeAll(async() => {
+        browser = await getBrowser();
+        page = browser.page;
+        await page.loginAndModule('salesPerson', 'item');
+        await page.waitToClick(selectors.globalItems.searchButton);
+    });
+
+    afterAll(async() => {
+        await browser.close();
+    });
+
+    describe('as filters', () => {
+        it('should search by type in searchBar', async() => {
+            await page.waitToClick(selectors.itemsIndex.openAdvancedSearchButton);
+            await page.autocompleteSearch(selectors.itemsIndex.advancedSearchItemType, 'Anthurium');
+            await page.waitToClick(selectors.itemsIndex.advancedSearchButton);
+            await page.waitForNumberOfElements(selectors.itemsIndex.searchResult, 3);
+        });
+
+        it('should reload page and have same results', async() => {
+            await page.reload({
+                waitUntil: 'networkidle2'
+            });
+
+            await page.waitForNumberOfElements(selectors.itemsIndex.searchResult, 3);
+        });
+
+        it('should search by grouping in smartTable', async() => {
+            await page.waitToClick(selectors.itemsIndex.advancedSmartTableButton);
+            await page.write(selectors.itemsIndex.advancedSmartTableGrouping, '1');
+            await page.keyboard.press('Enter');
+            await page.waitForNumberOfElements(selectors.itemsIndex.searchResult, 2);
+        });
+
+        it('should now reload page and have same results', async() => {
+            await page.reload({
+                waitUntil: 'networkidle2'
+            });
+
+            await page.waitForNumberOfElements(selectors.itemsIndex.searchResult, 2);
+        });
+    });
+
+    describe('as orders', () => {
+        it('should order by first id', async() => {
+            await page.loginAndModule('developer', 'item');
+            await page.accessToSection('item.fixedPrice');
+            await page.doSearch();
+
+            const result = await page.waitToGetProperty(selectors.itemFixedPrice.firstItemID, 'value');
+
+            expect(result).toEqual('1');
+        });
+
+        it('should order by last id', async() => {
+            await page.waitToClick(selectors.itemFixedPrice.orderColumnId);
+            const result = await page.waitToGetProperty(selectors.itemFixedPrice.firstItemID, 'value');
+
+            expect(result).toEqual('13');
+        });
+
+        it('should reload page and have same order', async() => {
+            await page.reload({
+                waitUntil: 'networkidle2'
+            });
+            const result = await page.waitToGetProperty(selectors.itemFixedPrice.firstItemID, 'value');
+
+            expect(result).toEqual('13');
+        });
+    });
+});
diff --git a/e2e/paths/04-item/01_summary.spec.js b/e2e/paths/04-item/01_summary.spec.js
index 373ceb95a5..e24fa6a9f1 100644
--- a/e2e/paths/04-item/01_summary.spec.js
+++ b/e2e/paths/04-item/01_summary.spec.js
@@ -1,7 +1,7 @@
 import selectors from '../../helpers/selectors.js';
 import getBrowser from '../../helpers/puppeteer';
 
-fdescribe('Item summary path', () => {
+describe('Item summary path', () => {
     let browser;
     let page;
     beforeAll(async() => {
diff --git a/front/core/components/crud-model/crud-model.js b/front/core/components/crud-model/crud-model.js
index 4994e15475..1095985dc1 100644
--- a/front/core/components/crud-model/crud-model.js
+++ b/front/core/components/crud-model/crud-model.js
@@ -99,6 +99,18 @@ export default class CrudModel extends ModelProxy {
         return this.refresh();
     }
 
+    /**
+     * Applies a new filter to the model.
+     *
+     * @param {Object} params Custom parameters
+     * @return {Promise} The request promise
+     */
+
+    applyParams(params) {
+        this.userParams = params;
+        return this.refresh();
+    }
+
     removeFilter() {
         return this.applyFilter(null, null);
     }
diff --git a/front/core/components/searchbar/searchbar.js b/front/core/components/searchbar/searchbar.js
index 50f9d00505..6e74a37795 100644
--- a/front/core/components/searchbar/searchbar.js
+++ b/front/core/components/searchbar/searchbar.js
@@ -199,7 +199,7 @@ export default class Searchbar extends Component {
 
     doSearch(filter, source) {
         if (filter === this.filter && source != 'state') return;
-        let promise = this.onSearch({$params: filter}, source);
+        let promise = this.onSearch({$params: filter});
         promise = promise || this.$q.resolve();
         promise.then(data => this.onFilter(filter, source, data));
         this.toBar(filter);
@@ -243,8 +243,11 @@ export default class Searchbar extends Component {
             } else {
                 state = this.searchState;
 
-                if (filter)
+                if (filter) {
+                    if (this.tableQ)
+                        filter.tableQ = this.tableQ;
                     params = {q: JSON.stringify(filter)};
+                }
                 if (this.$state.is(state))
                     opts = {location: 'replace'};
             }
@@ -253,6 +256,7 @@ export default class Searchbar extends Component {
         this.filter = filter;
 
         if (source == 'removeBar') {
+            console.log(params);
             delete params[this.toRemove];
             delete this.model.userParams[this.toRemove];
             this.model.refresh();
@@ -260,7 +264,6 @@ export default class Searchbar extends Component {
 
         if (!filter && this.model)
             this.model.clear();
-
         if (source != 'state')
             this.transition = this.$state.go(state, params, opts).transition;
         if (source != 'bar' && (source != 'state' || this.$state.is(this.baseState)))
@@ -296,26 +299,66 @@ export default class Searchbar extends Component {
         } else {
             params = Object.assign({}, filter);
 
+            console.log('pre', params);
             if (this.fetchParams)
                 params = this.fetchParams({$params: params});
+            console.log('post', params);
         }
 
-        if (this.$params.q) {
-            Object.assign(params, JSON.parse(this.$params.q));
-            return this.model.addFilter(where ? {where} : null, params)
+        /* console.log(params);
+        const paramsKeys = Object.keys(params);
+        const suggestedKeys = Object.keys(this.suggestedFilter);
+        if (params != this.suggestedFilter) {
+            for (let suggested in this.suggestedFilter)
+                delete this.model.userParams[suggested];
+        }*/
+        console.log('this.fromBar()', this.fromBar());
+        console.log('this.$params.q', this.$params.q);
+        console.log('param', params);
+        console.log('userParams', this.model.userParams);
+        console.log('userFilter', this.model.userFilter);
+        console.log('suggestedFilter', this.suggestedFilter);
+        console.log('fetch-params', this.fetchParams);
+        /* if (this.fromBar()) {
+            for (let param in params)
+                delete this.model.userParams[param];
+        }*/
+        this.tableQ = null;
+        if (this.$params.q && Object.keys(JSON.parse(this.$params.q)).length) {
+            const stateFilter = JSON.parse(this.$params.q);
+            for (let param in stateFilter) {
+                if (param != 'tableQ' && param != 'orderQ')
+                    this.filterSanitizer(param);
+            }
+
+            for (let param in this.suggestedFilter) {
+                this.filterSanitizer(param);
+                delete stateFilter[param];
+            }
+
+            this.tableQ = stateFilter.tableQ;
+            for (let param in stateFilter.tableQ)
+                params[param] = stateFilter.tableQ[param];
+
+            Object.assign(stateFilter, params);
+            console.log('PRE FINAL PARAMS: ', params);
+            return this.model.applyParams(params)
                 .then(() => this.model.data);
         }
+        console.log('FINAL PARAMS: ', params);
+
         return this.model.applyFilter(where ? {where} : null, params)
             .then(() => this.model.data);
     }
 
     filterSanitizer(field) {
+        if (!field) return;
         const userFilter = this.model.userFilter;
         const userParams = this.model.userParams;
         const where = userFilter && userFilter.where;
 
-        if (this.$params.q)
-            delete this.$params.q[field];
+        if (this.model.userParams)
+            delete this.model.userParams[field];
 
         if (this.exprBuilder) {
             const param = this.exprBuilder({
diff --git a/front/core/components/searchbar/searchbar.spec.js b/front/core/components/searchbar/searchbar.spec.js
index e4f58d294c..efa98818d8 100644
--- a/front/core/components/searchbar/searchbar.spec.js
+++ b/front/core/components/searchbar/searchbar.spec.js
@@ -172,13 +172,18 @@ describe('Component vnSearchbar', () => {
     describe('removeParam()', () => {
         it(`should remove the parameter from the filter`, () => {
             jest.spyOn(controller, 'doSearch');
+            controller.model = {
+                applyParams: () => {
+                    return new Promise(resolve => resolve());
+                }
+            };
 
             controller.filter = filter;
             controller.removeParam(0);
 
             expect(controller.doSearch).toHaveBeenCalledWith({
                 search: 'needle'
-            }, 'bar');
+            }, 'removeBar');
         });
     });
 

From 94c143bc4ceca4b82f46284971eac172f1f6966d Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Thu, 29 Sep 2022 14:28:50 +0200
Subject: [PATCH 019/151] test(searchbar_smart-table): fix for integration

---
 front/core/components/searchbar/searchbar.js  |  23 ---
 .../components/searchbar/searchbar.spec.js    |  26 +--
 front/core/components/smart-table/index.html  |   5 +-
 front/core/components/smart-table/index.js    |  26 ++-
 .../core/components/smart-table/index.spec.js | 159 ++++++++++++------
 5 files changed, 131 insertions(+), 108 deletions(-)

diff --git a/front/core/components/searchbar/searchbar.js b/front/core/components/searchbar/searchbar.js
index 6e74a37795..57a77d9801 100644
--- a/front/core/components/searchbar/searchbar.js
+++ b/front/core/components/searchbar/searchbar.js
@@ -256,7 +256,6 @@ export default class Searchbar extends Component {
         this.filter = filter;
 
         if (source == 'removeBar') {
-            console.log(params);
             delete params[this.toRemove];
             delete this.model.userParams[this.toRemove];
             this.model.refresh();
@@ -299,30 +298,10 @@ export default class Searchbar extends Component {
         } else {
             params = Object.assign({}, filter);
 
-            console.log('pre', params);
             if (this.fetchParams)
                 params = this.fetchParams({$params: params});
-            console.log('post', params);
         }
 
-        /* console.log(params);
-        const paramsKeys = Object.keys(params);
-        const suggestedKeys = Object.keys(this.suggestedFilter);
-        if (params != this.suggestedFilter) {
-            for (let suggested in this.suggestedFilter)
-                delete this.model.userParams[suggested];
-        }*/
-        console.log('this.fromBar()', this.fromBar());
-        console.log('this.$params.q', this.$params.q);
-        console.log('param', params);
-        console.log('userParams', this.model.userParams);
-        console.log('userFilter', this.model.userFilter);
-        console.log('suggestedFilter', this.suggestedFilter);
-        console.log('fetch-params', this.fetchParams);
-        /* if (this.fromBar()) {
-            for (let param in params)
-                delete this.model.userParams[param];
-        }*/
         this.tableQ = null;
         if (this.$params.q && Object.keys(JSON.parse(this.$params.q)).length) {
             const stateFilter = JSON.parse(this.$params.q);
@@ -341,11 +320,9 @@ export default class Searchbar extends Component {
                 params[param] = stateFilter.tableQ[param];
 
             Object.assign(stateFilter, params);
-            console.log('PRE FINAL PARAMS: ', params);
             return this.model.applyParams(params)
                 .then(() => this.model.data);
         }
-        console.log('FINAL PARAMS: ', params);
 
         return this.model.applyFilter(where ? {where} : null, params)
             .then(() => this.model.data);
diff --git a/front/core/components/searchbar/searchbar.spec.js b/front/core/components/searchbar/searchbar.spec.js
index efa98818d8..ed8fd9d074 100644
--- a/front/core/components/searchbar/searchbar.spec.js
+++ b/front/core/components/searchbar/searchbar.spec.js
@@ -6,7 +6,7 @@ describe('Component vnSearchbar', () => {
     let $state;
     let $params;
     let $scope;
-    let filter = {id: 1, search: 'needle'};
+    const filter = {id: 1, search: 'needle'};
 
     beforeEach(ngModule('vnCore', $stateProvider => {
         $stateProvider
@@ -70,8 +70,8 @@ describe('Component vnSearchbar', () => {
 
     describe('filter() setter', () => {
         it(`should update the bar params and search`, () => {
-            let withoutHours = new Date(2000, 1, 1);
-            let withHours = new Date(withoutHours.getTime());
+            const withoutHours = new Date(2000, 1, 1);
+            const withHours = new Date(withoutHours.getTime());
             withHours.setHours(12, 30, 15, 10);
 
             controller.filter = {
@@ -83,8 +83,8 @@ describe('Component vnSearchbar', () => {
                 myObjectProp: {myProp: 1}
             };
 
-            let chips = {};
-            for (let param of controller.params || [])
+            const chips = {};
+            for (const param of controller.params || [])
                 chips[param.key] = param.chip;
 
             expect(controller.searchString).toBe('needle');
@@ -173,11 +173,15 @@ describe('Component vnSearchbar', () => {
         it(`should remove the parameter from the filter`, () => {
             jest.spyOn(controller, 'doSearch');
             controller.model = {
-                applyParams: () => {
-                    return new Promise(resolve => resolve());
+                refresh: jest.fn(),
+                userParams: {
+                    id: 1
                 }
             };
 
+            controller.model.applyParams = jest.fn().mockReturnValue(Promise.resolve());
+            jest.spyOn(controller.model, 'applyParams');
+
             controller.filter = filter;
             controller.removeParam(0);
 
@@ -204,7 +208,7 @@ describe('Component vnSearchbar', () => {
         it(`should go to the summary state when one result`, () => {
             jest.spyOn($state, 'go');
 
-            let data = [{id: 1}];
+            const data = [{id: 1}];
 
             controller.baseState = 'foo';
             controller.onFilter(filter, 'any', data);
@@ -219,7 +223,7 @@ describe('Component vnSearchbar', () => {
             $scope.$apply();
 
             jest.spyOn($state, 'go');
-            let data = [{id: 1}];
+            const data = [{id: 1}];
 
             controller.baseState = 'foo';
             controller.onFilter(filter, 'any', data);
@@ -234,7 +238,7 @@ describe('Component vnSearchbar', () => {
             $scope.$apply();
 
             jest.spyOn($state, 'go');
-            let data = [{id: 1}];
+            const data = [{id: 1}];
 
             controller.baseState = 'foo';
             controller.onFilter(filter, 'any', data);
@@ -252,7 +256,7 @@ describe('Component vnSearchbar', () => {
             controller.onFilter(filter, 'any');
             $scope.$apply();
 
-            let queryParams = {q: JSON.stringify(filter)};
+            const queryParams = {q: JSON.stringify(filter)};
 
             expect($state.go).toHaveBeenCalledWith('search.state', queryParams, undefined);
             expect(controller.filter).toEqual(filter);
diff --git a/front/core/components/smart-table/index.html b/front/core/components/smart-table/index.html
index 3168d7ee73..752019313c 100644
--- a/front/core/components/smart-table/index.html
+++ b/front/core/components/smart-table/index.html
@@ -103,7 +103,4 @@
         </div>
     </tpl-body>
 </vn-popover>
-<vn-button
-    label="TEST"
-    ng-click="$ctrl.test()">
-</vn-button>
+
diff --git a/front/core/components/smart-table/index.js b/front/core/components/smart-table/index.js
index c78cbbca0d..31541143cc 100644
--- a/front/core/components/smart-table/index.js
+++ b/front/core/components/smart-table/index.js
@@ -229,7 +229,7 @@ export default class SmartTable extends Component {
         }
 
         this.model.order = order;
-        this.model.refresh();
+        this.refresh();
     }
 
     registerColumns() {
@@ -429,6 +429,14 @@ export default class SmartTable extends Component {
         this.searchByColumn(field);
     }
 
+    searchByColumn(field) {
+        const filters = this.filterSanitizer(field);
+
+        if (filters && filters.userFilter)
+            this.model.userFilter = filters.userFilter;
+        this.addFilter(field, this.$inputsScope.searchProps[field]);
+    }
+
     searchPropsSanitizer() {
         if (!this.$inputsScope || !this.$inputsScope.searchProps) return null;
         let searchProps = this.$inputsScope.searchProps;
@@ -440,14 +448,6 @@ export default class SmartTable extends Component {
         return Object.fromEntries(searchProps);
     }
 
-    searchByColumn(field) {
-        const filters = this.filterSanitizer(field);
-
-        if (filters && filters.userFilter)
-            this.model.userFilter = filters.userFilter;
-        this.addFilter(field, this.$inputsScope.searchProps[field]);
-    }
-
     addFilter(field, value) {
         if (value == '') value = null;
 
@@ -477,7 +477,7 @@ export default class SmartTable extends Component {
         const params = {q: JSON.stringify(stateFilter)};
 
         this.$state.go(this.$state.current.name, params, {location: 'replace'});
-        this.model.refresh();
+        this.refresh();
     }
 
     applySort() {
@@ -498,7 +498,7 @@ export default class SmartTable extends Component {
 
         const params = {q: JSON.stringify(stateFilter)};
         this.$state.go(this.$state.current.name, params, {location: 'replace'});
-        this.model.refresh();
+        this.refresh();
     }
 
     filterSanitizer(field) {
@@ -589,10 +589,6 @@ export default class SmartTable extends Component {
         this.model.refresh()
             .then(() => this.isRefreshing = false);
     }
-
-    test() {
-        console.log('USER_FILTER', this.model.userFilter, 'USER_PARAMS', this.model.userParams);
-    }
 }
 
 SmartTable.$inject = ['$element', '$scope', '$transclude'];
diff --git a/front/core/components/smart-table/index.spec.js b/front/core/components/smart-table/index.spec.js
index 720e24c7e3..5fd4c33b7d 100644
--- a/front/core/components/smart-table/index.spec.js
+++ b/front/core/components/smart-table/index.spec.js
@@ -9,6 +9,11 @@ describe('Component smartTable', () => {
         $httpBackend = _$httpBackend_;
         $element = $compile(`<smart-table></smart-table>`)($rootScope);
         controller = $element.controller('smartTable');
+        controller.model = {
+            refresh: jest.fn().mockReturnValue(new Promise(resolve => resolve())),
+            addFilter: jest.fn(),
+            userParams: {}
+        };
     }));
 
     afterEach(() => {
@@ -83,7 +88,7 @@ describe('Component smartTable', () => {
     describe('defaultOrder', () => {
         it('should insert a new object to the controller sortCriteria with a sortType value of "ASC"', () => {
             const element = document.createElement('div');
-            controller.model = {order: 'id'};
+            controller.model.order = 'id';
             controller.columns = [
                 {field: 'id', element: element},
                 {field: 'test1', element: element},
@@ -101,7 +106,8 @@ describe('Component smartTable', () => {
 
         it('should add new entries to the controller sortCriteria with a sortType values of "ASC" and "DESC"', () => {
             const element = document.createElement('div');
-            controller.model = {order: 'test1, id DESC'};
+            controller.model.order = 'test1, id DESC';
+
             controller.columns = [
                 {field: 'id', element: element},
                 {field: 'test1', element: element},
@@ -125,8 +131,6 @@ describe('Component smartTable', () => {
 
     describe('addFilter()', () => {
         it('should call the model addFilter() with a basic where filter if exprBuilder() was not received', () => {
-            controller.model = {addFilter: jest.fn()};
-
             controller.addFilter('myField', 'myValue');
 
             const expectedFilter = {
@@ -140,7 +144,6 @@ describe('Component smartTable', () => {
 
         it('should call the model addFilter() with a built where filter resultant of exprBuilder()', () => {
             controller.exprBuilder = jest.fn().mockReturnValue({builtField: 'builtValue'});
-            controller.model = {addFilter: jest.fn()};
 
             controller.addFilter('myField', 'myValue');
 
@@ -155,35 +158,48 @@ describe('Component smartTable', () => {
     });
 
     describe('applySort()', () => {
-        it('should call the model refresh() without making changes on the model order', () => {
-            controller.model = {refresh: jest.fn()};
+        it('should call the $state go and model refresh without making changes on the model order', () => {
+            controller.$state = {
+                go: jest.fn(),
+                current: {
+                    name: 'section'
+                }
+            };
+            jest.spyOn(controller, 'refresh');
 
             controller.applySort();
 
             expect(controller.model.order).toBeUndefined();
-            expect(controller.model.refresh).toHaveBeenCalled();
+            expect(controller.$state.go).toHaveBeenCalled();
+            expect(controller.refresh).toHaveBeenCalled();
         });
 
-        it('should call the model.refresh() after setting model order according to the controller sortCriteria', () => {
-            controller.model = {refresh: jest.fn()};
+        it('should call the $state go and model refresh after setting model order according to the controller sortCriteria', () => {
             const orderBy = {field: 'myField', sortType: 'ASC'};
+            controller.$state = {
+                go: jest.fn(),
+                current: {
+                    name: 'section'
+                }
+            };
+            jest.spyOn(controller, 'refresh');
+
             controller.sortCriteria = [orderBy];
 
             controller.applySort();
 
             expect(controller.model.order).toEqual(`${orderBy.field} ${orderBy.sortType}`);
-            expect(controller.model.refresh).toHaveBeenCalled();
+            expect(controller.$state.go).toHaveBeenCalled();
+            expect(controller.refresh).toHaveBeenCalled();
         });
     });
 
     describe('filterSanitizer()', () => {
         it('should remove the where filter after leaving no fields in it', () => {
-            controller.model = {
-                userFilter: {
-                    where: {fieldToRemove: 'valueToRemove'}
-                },
-                userParams: {}
+            controller.model.userFilter = {
+                where: {fieldToRemove: 'valueToRemove'}
             };
+            controller.model.userParams = {};
 
             const result = controller.filterSanitizer('fieldToRemove');
 
@@ -193,23 +209,21 @@ describe('Component smartTable', () => {
         });
 
         it('should remove the where filter after leaving no fields and "empty ands/ors" in it', () => {
-            controller.model = {
-                userFilter: {
-                    where: {
-                        and: [
-                            {aFieldToRemove: 'aValueToRemove'},
-                            {aFieldToRemove: 'aValueToRemove'},
-                            {
-                                or: [
-                                    {aFieldToRemove: 'aValueToRemove'},
-                                    {aFieldToRemove: 'aValueToRemove'},
-                                ]
-                            }
-                        ]
-                    }
-                },
-                userParams: {}
-            };
+            controller.model.userFilter = {
+                where: {
+                    and: [
+                        {aFieldToRemove: 'aValueToRemove'},
+                        {aFieldToRemove: 'aValueToRemove'},
+                        {
+                            or: [
+                                {aFieldToRemove: 'aValueToRemove'},
+                                {aFieldToRemove: 'aValueToRemove'},
+                            ]
+                        }
+                    ]
+                }
+            },
+            controller.model.userParams = {};
 
             const result = controller.filterSanitizer('aFieldToRemove');
 
@@ -219,24 +233,22 @@ describe('Component smartTable', () => {
         });
 
         it('should not remove the where filter after leaving no empty "ands/ors" in it', () => {
-            controller.model = {
-                userFilter: {
-                    where: {
-                        and: [
-                            {aFieldToRemove: 'aValueToRemove'},
-                            {aFieldToRemove: 'aValueToRemove'},
-                            {
-                                or: [
-                                    {aFieldToRemove: 'aValueToRemove'},
-                                    {aFieldToRemove: 'aValueToRemove'},
-                                ]
-                            }
-                        ],
-                        or: [{dontKillMe: 'thanks'}]
-                    }
-                },
-                userParams: {}
+            controller.model.userFilter = {
+                where: {
+                    and: [
+                        {aFieldToRemove: 'aValueToRemove'},
+                        {aFieldToRemove: 'aValueToRemove'},
+                        {
+                            or: [
+                                {aFieldToRemove: 'aValueToRemove'},
+                                {aFieldToRemove: 'aValueToRemove'},
+                            ]
+                        }
+                    ],
+                    or: [{dontKillMe: 'thanks'}]
+                }
             };
+            controller.model.userParams = {};
 
             const result = controller.filterSanitizer('aFieldToRemove');
 
@@ -249,7 +261,7 @@ describe('Component smartTable', () => {
     describe('saveAll()', () => {
         it('should throw an error if there are no changes to save in the model', () => {
             jest.spyOn(controller.vnApp, 'showError');
-            controller.model = {isChanged: false};
+            controller.model.isChanged = false;
             controller.saveAll();
 
             expect(controller.vnApp.showError).toHaveBeenCalledWith('No changes to save');
@@ -258,10 +270,8 @@ describe('Component smartTable', () => {
         it('should call the showSuccess() if there are changes to save in the model', done => {
             jest.spyOn(controller.vnApp, 'showSuccess');
 
-            controller.model = {
-                save: jest.fn().mockReturnValue(Promise.resolve()),
-                isChanged: true
-            };
+            controller.model.save = jest.fn().mockReturnValue(Promise.resolve());
+            controller.model.isChanged = true;
 
             controller.saveAll().then(() => {
                 expect(controller.vnApp.showSuccess).toHaveBeenCalledWith('Data saved!');
@@ -269,4 +279,43 @@ describe('Component smartTable', () => {
             }).catch(done.fail);
         });
     });
+
+    describe('defaultFilter()', () => {
+        it('should call model refresh and model addFilter with filter', () => {
+            controller.exprBuilder = jest.fn().mockReturnValue({builtField: 'builtValue'});
+
+            controller.$params = {
+                q: '{"tableQ": {"fieldName":"value"}}'
+            };
+            controller.columns = [
+                {field: 'fieldName'}
+            ];
+            controller.$inputsScope = {
+                searchProps: {}
+            };
+            jest.spyOn(controller, 'refresh');
+
+            controller.defaultFilter();
+
+            expect(controller.model.addFilter).toHaveBeenCalled();
+            expect(controller.refresh).toHaveBeenCalled();
+        });
+    });
+
+    describe('searchPropsSanitizer()', () => {
+        it('should searchProps sanitize', () => {
+            controller.$inputsScope = {
+                searchProps: {
+                    filterOne: '1',
+                    filterTwo: ''
+                }
+            };
+            const searchPropsExpected = {
+                filterOne: '1'
+            };
+            const newSearchProps = controller.searchPropsSanitizer();
+
+            expect(newSearchProps).toEqual(searchPropsExpected);
+        });
+    });
 });

From e931414bb7d7fd33b6a3caec661d7c1e26e7b8cd Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Fri, 30 Sep 2022 08:59:49 +0200
Subject: [PATCH 020/151] unnecessary code

---
 db/changes/10490-august/00-packingSiteConfig.sql | 12 ------------
 front/core/lib/lilium.js                         | 12 ------------
 front/core/services/app.js                       |  4 +---
 3 files changed, 1 insertion(+), 27 deletions(-)
 delete mode 100644 front/core/lib/lilium.js

diff --git a/db/changes/10490-august/00-packingSiteConfig.sql b/db/changes/10490-august/00-packingSiteConfig.sql
index dc5e4c5cfc..945b5a54c6 100644
--- a/db/changes/10490-august/00-packingSiteConfig.sql
+++ b/db/changes/10490-august/00-packingSiteConfig.sql
@@ -7,18 +7,6 @@ CREATE TABLE `vn`.`packingSiteConfig` (
   PRIMARY KEY (`id`)
  );
 
-INSERT INTO `vn`.`packingSiteConfig` SET
-    shinobiUrl = 'https://shinobi.verdnatura.es',
-    shinobiToken = 'BW4o7FZyJ85she1hlRDe6QnwW3jwEP',
-    shinobiGroupKey = 'xVqft9LFXg',
-    avgBoxingTime = 6000;
-
 INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
     VALUES
         ('Boxing', '*', '*', 'ALLOW', 'ROLE', 'employee');
-
-SELECT e.id expeditionFk, e.ticketFk, ps.code, ps.monitorId
-	FROM expedition e
-		JOIN host h ON Convert(h.code USING utf8mb3) COLLATE utf8mb3_unicode_ci = e.hostFk
-		JOIN packingSite ps ON  ps.hostFk = h.id
-	WHERE e.ticketFk = 1;
diff --git a/front/core/lib/lilium.js b/front/core/lib/lilium.js
deleted file mode 100644
index ca10d3511b..0000000000
--- a/front/core/lib/lilium.js
+++ /dev/null
@@ -1,12 +0,0 @@
-
-export default function lilium(route) {
-    const env = process.env.NODE_ENV;
-    let newRoute = 'https://localhost:8080/#/' + route;
-
-    if (env == 'test')
-        newRoute = 'https://test-lilium.verdnatura.es/#/' + route;
-    if (env == 'producction')
-        newRoute = 'https://lilium.verdnatura.es/#/' + route;
-
-    return newRoute;
-}
diff --git a/front/core/services/app.js b/front/core/services/app.js
index 37bddeca04..fb0a087773 100644
--- a/front/core/services/app.js
+++ b/front/core/services/app.js
@@ -55,9 +55,7 @@ export default class App {
         }
     }
 
-    getUrl(route, appName) {
-        if (!appName) appName = 'lilium';
-
+    getUrl(route, appName = 'lilium') {
         const env = process.env.NODE_ENV;
         const filter = {
             where: {and: [

From eec1d6df4ad09fbbd2db274035971bb8486cf243 Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Fri, 30 Sep 2022 09:06:43 +0200
Subject: [PATCH 021/151] add translation

---
 modules/ticket/front/locale/es.yml | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/modules/ticket/front/locale/es.yml b/modules/ticket/front/locale/es.yml
index 752dd7b36e..748ba210f5 100644
--- a/modules/ticket/front/locale/es.yml
+++ b/modules/ticket/front/locale/es.yml
@@ -4,6 +4,7 @@ Agency: Agencia
 Amount: Importe
 Base to commission: Base comisionable
 Boxes: Cajas
+Boxing: Encajado
 by: por
 Checked: Comprobado
 Client: Cliente
@@ -45,7 +46,7 @@ Price gap: Diferencia de precio
 Quantity: Cantidad
 Remove lines: Eliminar lineas
 Route: Ruta
-SET OK: PONER OK 
+SET OK: PONER OK
 Shipment: Salida
 Shipped: F. envío
 Some fields are invalid: Algunos campos no son válidos
@@ -81,4 +82,4 @@ Sale tracking: Líneas preparadas
 Pictures: Fotos
 Log: Historial
 Packager: Encajador
-Palletizer: Palletizador
\ No newline at end of file
+Palletizer: Palletizador

From f81b2775a00a8431b89bdeb4c63a10644fd138e0 Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Fri, 30 Sep 2022 09:36:51 +0200
Subject: [PATCH 022/151] add fixture

---
 db/dump/fixtures.sql | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql
index 189b1ebe63..b54bb1c825 100644
--- a/db/dump/fixtures.sql
+++ b/db/dump/fixtures.sql
@@ -2642,7 +2642,11 @@ INSERT INTO `vn`.`host` (`id`, `code`, `description`, `warehouseFk`, `bankFk`)
 
 INSERT INTO `vn`.`packingSite` (`id`, `code`, `hostFk`, `monitorId`)
     VALUES
-        (1, 'h1', 1, 'VbiUcajdaT');
+        (1, 'h1', 1, '');
+
+INSERT INTO `vn`.`packingSiteConfig` (`shinobiUrl`, `shinobiToken`, `shinobiGroupKey`, `avgBoxingTime`)
+    VALUES
+        ('', 'SHINNOBI_TOKEN', 'GROUP_TOKEN', 6000);
 
 INSERT INTO `vn`.`routeConfig` (`id`, `defaultWorkCenterFk`)
     VALUES

From 11484edd105c0c57210b523c89f246a55bb1f17d Mon Sep 17 00:00:00 2001
From: vicent <vicent@verdnatura.es>
Date: Mon, 3 Oct 2022 15:18:07 +0200
Subject: [PATCH 023/151] feat: create new ticket

---
 modules/ticket/front/expedition/index.html | 22 +++++++++++++++++++---
 modules/ticket/front/expedition/index.js   | 17 +++++++++++++++++
 2 files changed, 36 insertions(+), 3 deletions(-)

diff --git a/modules/ticket/front/expedition/index.html b/modules/ticket/front/expedition/index.html
index 3a5d5f8a6d..694b3eb33c 100644
--- a/modules/ticket/front/expedition/index.html
+++ b/modules/ticket/front/expedition/index.html
@@ -138,12 +138,28 @@
 <vn-menu vn-id="moreOptions">
     <vn-item translate
         name="sms"
-        ng-click="$ctrl.showSMSDialog()">
+        ng-click="$ctrl.createTicket()">
         New ticket without route
     </vn-item>
     <vn-item translate
         name="calculatePrice"
-        ng-click="$ctrl.calculateSalePrice()">
+        ng-click="selectRoute.show()">
         New ticket with route
     </vn-item>
-</vn-menu>
\ No newline at end of file
+</vn-menu>
+
+<vn-dialog 
+    vn-id="selectRoute"
+    on-accept="$ctrl.createTicket($ctrl.ticket.newRoute)">
+    <tpl-body>
+        <vn-textfield
+            vn-one
+            label="Id route"
+            ng-model="$ctrl.ticket.newRoute">
+        </vn-textfield>
+    </tpl-body>
+    <tpl-buttons>
+        <input type="button" response="cancel" translate-attr="{value: 'Cancel'}"/>
+        <button response="accept" translate>Accept</button>
+    </tpl-buttons>
+</vn-dialog>
\ No newline at end of file
diff --git a/modules/ticket/front/expedition/index.js b/modules/ticket/front/expedition/index.js
index 38d02f5484..d80c8e812b 100644
--- a/modules/ticket/front/expedition/index.js
+++ b/modules/ticket/front/expedition/index.js
@@ -26,6 +26,23 @@ class Controller extends Section {
     get totalChecked() {
         return this.checked.length;
     }
+
+    createTicket(routeFk) {
+        const tomorrow = new Date();
+        const params = {
+            clientId: this.ticket.clientFk,
+            landed: tomorrow.getDay() + 1,
+            addressId: this.ticket.addressFk,
+            agencyModeId: this.ticket.agencyModeFk,
+            warehouseId: this.ticket.warehouseFk
+        };
+        const query = `Tickets/new`;
+        this.$http.post(query, params).then(res => {
+            if (routeFk) this.$http.patch(`Tickets/${res.data.id}`, {routeFk: routeFk});
+            this.vnApp.showSuccess(this.$t('Data saved!'));
+            this.$state.go('ticket.card.summary', {id: res.data.id});
+        });
+    }
 }
 
 ngModule.vnComponent('vnTicketExpedition', {

From 600dd7a4347d40bb49a4a0e2cdecda346178f521 Mon Sep 17 00:00:00 2001
From: Pau Navarro <pau@verdnatura.es>
Date: Wed, 5 Oct 2022 11:52:14 +0200
Subject: [PATCH 024/151] Created the model and UI

---
 .../workerDisableExclueded/checkExcluded.js   | 26 +++++++++++++++++++
 modules/worker/back/model-config.json         |  3 +++
 .../back/models/workerDisableExcluded.json    | 23 ++++++++++++++++
 modules/worker/front/descriptor/index.html    | 10 +++++++
 modules/worker/front/descriptor/index.js      |  8 ++++++
 5 files changed, 70 insertions(+)
 create mode 100644 modules/worker/back/methods/workerDisableExclueded/checkExcluded.js
 create mode 100644 modules/worker/back/models/workerDisableExcluded.json

diff --git a/modules/worker/back/methods/workerDisableExclueded/checkExcluded.js b/modules/worker/back/methods/workerDisableExclueded/checkExcluded.js
new file mode 100644
index 0000000000..32260c01f1
--- /dev/null
+++ b/modules/worker/back/methods/workerDisableExclueded/checkExcluded.js
@@ -0,0 +1,26 @@
+
+module.exports = Self => {
+    Self.remoteMethod('workerDisableExcluded', {
+        description: 'Check an email inbox and process it',
+        accessType: 'READ',
+        accepts: {
+            arg: 'workerFk',
+            type: 'Number',
+            required: true,
+            description: `The worker id`
+        },
+        returns: {
+            type: ['Object'],
+            root: true
+        },
+        http: {
+            path: `/workerDisableExcluded`,
+            verb: 'GET'
+        }
+    });
+
+    Self.workerDisableExcluded = workerFk => {
+        console.log(workerFk);
+        return 'tests123';
+    };
+};
diff --git a/modules/worker/back/model-config.json b/modules/worker/back/model-config.json
index c155e331de..a41997908f 100644
--- a/modules/worker/back/model-config.json
+++ b/modules/worker/back/model-config.json
@@ -64,6 +64,9 @@
     },
     "WorkerTimeControlMail": {
         "dataSource": "vn"
+    },
+    "workerDisableExcluded": {
+        "dataSource": "vn"
     }
 }
 
diff --git a/modules/worker/back/models/workerDisableExcluded.json b/modules/worker/back/models/workerDisableExcluded.json
new file mode 100644
index 0000000000..eeffb4b15d
--- /dev/null
+++ b/modules/worker/back/models/workerDisableExcluded.json
@@ -0,0 +1,23 @@
+{
+	"name": "workerDisableExcluded",
+	"base": "VnModel",
+	"options": {
+		"mysql": {
+			"table": "workerDisableExcluded"
+		}
+	},
+	"properties": {
+		"id": {
+			"id": true,
+			"type": "number"
+		}
+	},
+	"acls": [
+        {
+        "accessType": "READ",
+        "principalType": "ROLE",
+        "principalId": "$everyone",
+        "permission": "ALLOW"
+        }
+    ]
+}
\ No newline at end of file
diff --git a/modules/worker/front/descriptor/index.html b/modules/worker/front/descriptor/index.html
index 01681ebb80..0616f179fd 100644
--- a/modules/worker/front/descriptor/index.html
+++ b/modules/worker/front/descriptor/index.html
@@ -14,6 +14,16 @@
             </vn-float-button>
         </div>
     </slot-before>
+    <slot-menu>
+        <label class="vn-item">
+            <!--
+            <input ng-if="$ctrl.isExcluded()" type="checkbox" id="canBeDisabled" disabled checked>
+            <input ng-if="!$ctrl.isExcluded()" type="checkbox" id="canBeDisabled" disabled>
+            -->
+
+            <p>{{$ctrl.isExcluded()}}</p>
+        </label>       
+    </slot-menu>
     <slot-body>
         <div class="attributes">
             <vn-label-value
diff --git a/modules/worker/front/descriptor/index.js b/modules/worker/front/descriptor/index.js
index 260d3f6121..e1026382df 100644
--- a/modules/worker/front/descriptor/index.js
+++ b/modules/worker/front/descriptor/index.js
@@ -15,6 +15,14 @@ class Controller extends Descriptor {
         this.entity = value;
     }
 
+    async isExcluded() {
+        // eslint-disable-next-line no-console
+        console.log(this.entity);
+        let excluded = await this.$http.get(`workerDisableExcluded`);
+        // eslint-disable-next-line no-console
+        console.log(excluded);
+    }
+
     loadData() {
         const filter = {
             include: [

From 2f17257e46096cdb9049d276df9b1c29c7d3071b Mon Sep 17 00:00:00 2001
From: vicent <vicent@verdnatura.es>
Date: Wed, 5 Oct 2022 15:13:48 +0200
Subject: [PATCH 025/151] feat: add new sub section itemShelving

---
 front/salix/locale/es.yml                     |   1 +
 modules/item/back/model-config.json           |   3 +
 .../item-shelving-placement-supply.json       |  29 +++
 modules/item/front/index.js                   |   2 +
 modules/item/front/item-shelving/index.html   | 172 ++++++++++++++++++
 modules/item/front/item-shelving/index.js     | 132 ++++++++++++++
 .../item/front/item-shelving/index.spec.js    | 121 ++++++++++++
 .../item/front/item-shelving/locale/es.yml    |   9 +
 modules/item/front/locale/es.yml              |   1 +
 modules/item/front/routes.json                |  13 +-
 modules/shelving/front/routes.json            |   2 +-
 11 files changed, 483 insertions(+), 2 deletions(-)
 create mode 100644 modules/item/back/models/item-shelving-placement-supply.json
 create mode 100644 modules/item/front/item-shelving/index.html
 create mode 100644 modules/item/front/item-shelving/index.js
 create mode 100644 modules/item/front/item-shelving/index.spec.js
 create mode 100644 modules/item/front/item-shelving/locale/es.yml

diff --git a/front/salix/locale/es.yml b/front/salix/locale/es.yml
index e5dc82b164..d92c32b337 100644
--- a/front/salix/locale/es.yml
+++ b/front/salix/locale/es.yml
@@ -51,6 +51,7 @@ Entries: Entradas
 Users: Usuarios
 Suppliers: Proveedores
 Monitors: Monitores
+Shelvings: Carros
 
 # Common
 
diff --git a/modules/item/back/model-config.json b/modules/item/back/model-config.json
index 9737d26fc0..40d73f1a61 100644
--- a/modules/item/back/model-config.json
+++ b/modules/item/back/model-config.json
@@ -53,6 +53,9 @@
     "ItemShelvingSale": {
         "dataSource": "vn"
     },
+    "ItemShelvingPlacementSupplyStock": {
+        "dataSource": "vn"
+    },
     "ItemImageQueue": {
         "dataSource": "vn"
     },
diff --git a/modules/item/back/models/item-shelving-placement-supply.json b/modules/item/back/models/item-shelving-placement-supply.json
new file mode 100644
index 0000000000..11497b4fc9
--- /dev/null
+++ b/modules/item/back/models/item-shelving-placement-supply.json
@@ -0,0 +1,29 @@
+{
+    "name": "ItemShelvingPlacementSupplyStock",
+    "base": "VnModel",
+    "options": {
+        "mysql": {
+          "table": "itemShelvingPlacementSupplyStock"
+        }
+    },
+    "properties": {
+        "created": {
+            "type": "date"
+        },
+        "itemFk": {
+            "type": "number"
+        },
+        "concept": {
+            "type": "string"
+        },
+        "parking": {
+            "type": "string"
+        },
+        "shelving": {
+            "type": "string"
+        },
+        "packing": {
+            "type": "number"
+        }
+    }
+}
\ No newline at end of file
diff --git a/modules/item/front/index.js b/modules/item/front/index.js
index 6a8d1b3b78..d2ffcc8fb1 100644
--- a/modules/item/front/index.js
+++ b/modules/item/front/index.js
@@ -24,3 +24,5 @@ import './waste/detail';
 import './fixed-price';
 import './fixed-price-search-panel';
 import './item-type';
+import './item-shelving';
+
diff --git a/modules/item/front/item-shelving/index.html b/modules/item/front/item-shelving/index.html
new file mode 100644
index 0000000000..7949e73a3c
--- /dev/null
+++ b/modules/item/front/item-shelving/index.html
@@ -0,0 +1,172 @@
+<vn-crud-model
+    vn-id="model"
+    url="Defaulters/filter"
+    filter="::$ctrl.filter"
+    limit="20"
+    order="amount DESC"
+    data="defaulters"
+    auto-load="true">
+</vn-crud-model>
+<vn-portal slot="topbar">
+    <vn-searchbar
+        vn-focus
+        placeholder="Search client"
+        info="Search client by id or name"
+        auto-state="false"
+        model="model">
+    </vn-searchbar>
+</vn-portal>
+<vn-card>
+    <smart-table 
+        model="model"
+        options="$ctrl.smartTableOptions" 
+        expr-builder="$ctrl.exprBuilder(param, value)">
+        <slot-actions>
+            <div>
+                <div class="totalBox" style="text-align: center;">
+                    <h6 translate>Total</h6>
+                    <vn-label-value 
+                        label="Balance due" 
+                        value="{{$ctrl.balanceDueTotal | currency: 'EUR': 2}}">
+                    </vn-label-value>
+                </div>
+            </div>
+            <div class="vn-pa-md">
+                <vn-button 
+                    ng-show="$ctrl.checked.length > 0"
+                    ng-click="notesDialog.show()"
+                    name="notesDialog"
+                    vn-tooltip="Add observation"
+                    icon="icon-notes">
+                </vn-button>
+            </div>
+        </slot-actions>
+        <slot-table>
+            <table>
+                <thead>
+                    <tr>
+                        <th shrink>
+                            <vn-multi-check 
+                                model="model">
+                            </vn-multi-check>
+                        </th>
+                        <th field="clientFk">
+                            <span translate>Created</span>
+                        </th>
+                        <th field="salesPersonFk">
+                            <span translate>Item</span>
+                        </th>
+                        <th 
+                            field="amount" 
+                            vn-tooltip="Balance due">
+                            <span translate>Concept</span>
+                        </th>
+                        <th 
+                            field="workerFk" 
+                            vn-tooltip="Worker who made the last observation">
+                            <span translate>Parking</span>
+                        </th>
+                        <th field="observation" expand>
+                            <span translate>Shelving</span>
+                        </th>
+                        <th 
+                            vn-tooltip="Last observation date"
+                            field="created">
+                            <span translate>Etiqueta</span>
+                        </th>
+                        <th 
+                            field="creditInsurance"
+                            shrink>
+                            <span translate>Packing</span>
+                        </th>
+                    </tr>
+                </thead>
+                <tbody>
+                    <tr ng-repeat="defaulter in defaulters">
+                        <td shrink>
+                            <vn-check 
+                                ng-model="defaulter.checked"
+                                vn-click-stop>
+                            </vn-check>
+                        </td>
+                        <td title="{{::defaulter.clientName}}">
+                            <span
+                                vn-click-stop="clientDescriptor.show($event, defaulter.clientFk)"
+                                title ="{{::defaulter.clientName}}"
+                                class="link">
+                                {{::defaulter.clientName}}
+                            </span>
+                        </td>
+                        <td>
+                            <span
+                                title="{{::defaulter.salesPersonName}}"
+                                vn-click-stop="workerDescriptor.show($event, defaulter.salesPersonFk)"
+                                class="link">
+                                {{::defaulter.salesPersonName | dashIfEmpty}}
+                            </span>
+                        </td>
+                        <td>{{::defaulter.amount | currency: 'EUR': 2}}</td>
+                        <td>
+                            <span
+                                title="{{::defaulter.workerName}}"
+                                vn-click-stop="workerDescriptor.show($event, defaulter.workerFk)"
+                                class="link">
+                                {{::defaulter.workerName | dashIfEmpty}}
+                            </span>
+                        </td>
+                        <td expand>
+                            <vn-textarea
+                                vn-three
+                                disabled="true"
+                                ng-model="defaulter.observation">
+                            </vn-textarea>
+                        </td>
+                        <td shrink-date>
+                            <span class="chip {{::$ctrl.chipColor(defaulter.created)}}">
+                                {{::defaulter.created | date: 'dd/MM/yyyy'}}
+                            </span>
+                        </td>
+                        <td shrink>{{::defaulter.creditInsurance | currency: 'EUR': 2}}</td>
+                        <td shrink-date>{{::defaulter.defaulterSinced | date: 'dd/MM/yyyy'}}</td>
+                    </tr>
+                </tbody>
+            </table>
+        </slot-table>
+    </smart-table>
+</vn-card>
+<vn-client-descriptor-popover
+    vn-id="client-descriptor">
+</vn-client-descriptor-popover>
+<vn-worker-descriptor-popover
+    vn-id="worker-descriptor">
+</vn-worker-descriptor-popover>
+<vn-popup vn-id="dialog-summary-client">
+    <vn-client-summary
+        client="$ctrl.clientSelected">
+    </vn-client-summary>
+</vn-popup>
+
+<!-- Dialog of add notes button --> 
+<vn-dialog
+    vn-id="notesDialog"
+    on-accept="$ctrl.onResponse()">
+    <tpl-body>
+        <section class="SMSDialog">
+            <h5 class="vn-py-sm">{{$ctrl.$t('Add observation to all selected clients', {total: $ctrl.checked.length})}}</h5>
+            <vn-horizontal>
+                <vn-textarea vn-one
+                    vn-id="message"
+                    label="Message" 
+                    ng-model="$ctrl.defaulter.observation"
+                    rows="3"
+                    required="true"
+                    rule>
+                </vn-textarea>
+            </vn-horizontal>
+        </section>
+    </tpl-body>
+    <tpl-buttons>
+        <input type="button" response="cancel" translate-attr="{value: 'Cancel'}"/>
+        <button response="accept" translate>Save</button>
+    </tpl-buttons>
+</vn-dialog>
diff --git a/modules/item/front/item-shelving/index.js b/modules/item/front/item-shelving/index.js
new file mode 100644
index 0000000000..f51a1a65b5
--- /dev/null
+++ b/modules/item/front/item-shelving/index.js
@@ -0,0 +1,132 @@
+import ngModule from '../module';
+import Section from 'salix/components/section';
+import UserError from 'core/lib/user-error';
+
+export default class Controller extends Section {
+    constructor($element, $) {
+        super($element, $);
+        this.defaulter = {};
+
+        this.smartTableOptions = {
+            activeButtons: {
+                search: true
+            },
+            columns: [
+                {
+                    field: 'clientFk',
+                    autocomplete: {
+                        url: 'Clients',
+                        showField: 'name',
+                        valueField: 'id'
+                    }
+                },
+                {
+                    field: 'salesPersonFk',
+                    autocomplete: {
+                        url: 'Workers/activeWithInheritedRole',
+                        where: `{role: 'salesPerson'}`,
+                        searchFunction: '{firstName: $search}',
+                        showField: 'name',
+                        valueField: 'id',
+                    }
+                },
+                {
+                    field: 'workerFk',
+                    autocomplete: {
+                        url: 'Workers/activeWithInheritedRole',
+                        searchFunction: '{firstName: $search}',
+                        showField: 'name',
+                        valueField: 'id',
+                    }
+                },
+                {
+                    field: 'observation',
+                    searchable: false
+                },
+                {
+                    field: 'created',
+                    searchable: false
+                },
+                {
+                    field: 'defaulterSinced',
+                    searchable: false
+                }
+            ]
+        };
+
+        this.getBalanceDueTotal();
+    }
+
+    get checked() {
+        const clients = this.$.model.data || [];
+        const checkedLines = [];
+        for (let defaulter of clients) {
+            if (defaulter.checked)
+                checkedLines.push(defaulter);
+        }
+
+        return checkedLines;
+    }
+
+    getBalanceDueTotal() {
+        this.$http.get('Defaulters/filter')
+            .then(res => {
+                if (!res.data) return 0;
+
+                this.balanceDueTotal = res.data.reduce(
+                    (accumulator, currentValue) => {
+                        return accumulator + (currentValue['amount'] || 0);
+                    }, 0);
+            });
+    }
+
+    chipColor(date) {
+        const day = 24 * 60 * 60 * 1000;
+        const today = new Date();
+        today.setHours(0, 0, 0, 0);
+
+        const observationShipped = new Date(date);
+        observationShipped.setHours(0, 0, 0, 0);
+
+        const difference = today - observationShipped;
+
+        if (difference > (day * 20))
+            return 'alert';
+        if (difference > (day * 10))
+            return 'warning';
+    }
+
+    onResponse() {
+        if (!this.defaulter.observation)
+            throw new UserError(`The message can't be empty`);
+
+        const params = [];
+        for (let defaulter of this.checked) {
+            params.push({
+                text: this.defaulter.observation,
+                clientFk: defaulter.clientFk
+            });
+        }
+
+        this.$http.post(`ClientObservations`, params) .then(() => {
+            this.vnApp.showMessage(this.$t('Observation saved!'));
+            this.$state.reload();
+        });
+    }
+
+    exprBuilder(param, value) {
+        switch (param) {
+        case 'creditInsurance':
+        case 'amount':
+        case 'clientFk':
+        case 'workerFk':
+        case 'salesPersonFk':
+            return {[`d.${param}`]: value};
+        }
+    }
+}
+
+ngModule.vnComponent('vnItemShelving', {
+    template: require('./index.html'),
+    controller: Controller
+});
diff --git a/modules/item/front/item-shelving/index.spec.js b/modules/item/front/item-shelving/index.spec.js
new file mode 100644
index 0000000000..0732c68a1e
--- /dev/null
+++ b/modules/item/front/item-shelving/index.spec.js
@@ -0,0 +1,121 @@
+import './index';
+import crudModel from 'core/mocks/crud-model';
+
+describe('client defaulter', () => {
+    describe('Component vnClientDefaulter', () => {
+        let controller;
+        let $httpBackend;
+
+        beforeEach(ngModule('client'));
+
+        beforeEach(inject(($componentController, _$httpBackend_) => {
+            $httpBackend = _$httpBackend_;
+            const $element = angular.element('<vn-client-defaulter></vn-client-defaulter>');
+            controller = $componentController('vnClientDefaulter', {$element});
+            controller.$.model = crudModel;
+            controller.$.model.data = [
+                {clientFk: 1101, amount: 125},
+                {clientFk: 1102, amount: 500},
+                {clientFk: 1103, amount: 250}
+            ];
+        }));
+
+        describe('checked() getter', () => {
+            it('should return the checked lines', () => {
+                const data = controller.$.model.data;
+                data[1].checked = true;
+                data[2].checked = true;
+
+                const checkedRows = controller.checked;
+
+                const firstCheckedRow = checkedRows[0];
+                const secondCheckedRow = checkedRows[1];
+
+                expect(firstCheckedRow.clientFk).toEqual(1102);
+                expect(secondCheckedRow.clientFk).toEqual(1103);
+            });
+        });
+
+        describe('chipColor()', () => {
+            it('should return undefined when the date is the present', () => {
+                let today = new Date();
+                let result = controller.chipColor(today);
+
+                expect(result).toEqual(undefined);
+            });
+
+            it('should return warning when the date is 10 days in the past', () => {
+                let pastDate = new Date();
+                pastDate = pastDate.setDate(pastDate.getDate() - 11);
+                let result = controller.chipColor(pastDate);
+
+                expect(result).toEqual('warning');
+            });
+
+            it('should return alert when the date is 20 days in the past', () => {
+                let pastDate = new Date();
+                pastDate = pastDate.setDate(pastDate.getDate() - 21);
+                let result = controller.chipColor(pastDate);
+
+                expect(result).toEqual('alert');
+            });
+        });
+
+        describe('onResponse()', () => {
+            it('should return error for empty message', () => {
+                let error;
+                try {
+                    controller.onResponse();
+                } catch (e) {
+                    error = e;
+                }
+
+                expect(error).toBeDefined();
+                expect(error.message).toBe(`The message can't be empty`);
+            });
+
+            it('should return saved message', () => {
+                const data = controller.$.model.data;
+                data[1].checked = true;
+                controller.defaulter = {observation: 'My new observation'};
+
+                const params = [{text: controller.defaulter.observation, clientFk: data[1].clientFk}];
+
+                jest.spyOn(controller.vnApp, 'showMessage');
+                $httpBackend.expect('GET', `Defaulters/filter`).respond(200);
+                $httpBackend.expect('POST', `ClientObservations`, params).respond(200, params);
+
+                controller.onResponse();
+                $httpBackend.flush();
+
+                expect(controller.vnApp.showMessage).toHaveBeenCalledWith('Observation saved!');
+            });
+        });
+
+        describe('exprBuilder()', () => {
+            it('should search by sales person', () => {
+                const expr = controller.exprBuilder('salesPersonFk', '5');
+
+                expect(expr).toEqual({'d.salesPersonFk': '5'});
+            });
+
+            it('should search by client', () => {
+                const expr = controller.exprBuilder('clientFk', '5');
+
+                expect(expr).toEqual({'d.clientFk': '5'});
+            });
+        });
+
+        describe('getBalanceDueTotal()', () => {
+            it('should return balance due total', () => {
+                const defaulters = controller.$.model.data;
+                $httpBackend.when('GET', `Defaulters/filter`).respond(defaulters);
+
+                controller.getBalanceDueTotal();
+                $httpBackend.flush();
+
+                expect(controller.balanceDueTotal).toEqual(875);
+            });
+        });
+    });
+});
diff --git a/modules/item/front/item-shelving/locale/es.yml b/modules/item/front/item-shelving/locale/es.yml
new file mode 100644
index 0000000000..c3e1d4e19c
--- /dev/null
+++ b/modules/item/front/item-shelving/locale/es.yml
@@ -0,0 +1,9 @@
+Add observation: Añadir observación
+Add observation to all selected clients: Añadir observación a {{total}} cliente(s) seleccionado(s)
+Balance D.: Saldo V.
+Credit I.: Crédito A.
+Last observation: Última observación
+L. O. Date: Fecha Ú. O.
+Last observation date: Fecha última observación
+Search client: Buscar clientes
+Worker who made the last observation: Trabajador que ha realizado la última observación
\ No newline at end of file
diff --git a/modules/item/front/locale/es.yml b/modules/item/front/locale/es.yml
index 1b75e38021..88ab031e14 100644
--- a/modules/item/front/locale/es.yml
+++ b/modules/item/front/locale/es.yml
@@ -54,6 +54,7 @@ Basic data: Datos básicos
 Tax: IVA
 History: Historial
 Botanical: Botánico
+Shelvings: Carros
 Barcodes: Códigos de barras
 Diary: Histórico
 Item diary: Registro de compra-venta
diff --git a/modules/item/front/routes.json b/modules/item/front/routes.json
index 5743d0ce7f..52cf5d2be9 100644
--- a/modules/item/front/routes.json
+++ b/modules/item/front/routes.json
@@ -16,7 +16,8 @@
             {"state": "item.card.basicData", "icon": "settings"},
             {"state": "item.card.tags", "icon": "icon-tags"},
             {"state": "item.card.tax", "icon": "icon-tax"},
-            {"state": "item.card.botanical", "icon": "local_florist"}, 
+            {"state": "item.card.botanical", "icon": "local_florist"},
+            {"state": "item.card.shelving", "icon": "icon-inventory"},
             {"state": "item.card.itemBarcode", "icon": "icon-barcode"}, 
             {"state": "item.card.diary", "icon": "icon-transaction"}, 
             {"state": "item.card.last-entries", "icon": "icon-regentry"},
@@ -92,6 +93,16 @@
             },
             "acl": ["buyer"]
         },
+        {
+            "url" : "/shelving",
+            "state": "item.card.shelving",
+            "component": "vn-item-shelving",
+            "description": "Shelvings",
+            "params": {
+                "item": "$ctrl.item"
+            },
+            "acl": ["employee"]
+        },
         {
             "url" : "/barcode",
             "state": "item.card.itemBarcode",
diff --git a/modules/shelving/front/routes.json b/modules/shelving/front/routes.json
index b99ca4caca..0a05db9e33 100644
--- a/modules/shelving/front/routes.json
+++ b/modules/shelving/front/routes.json
@@ -14,7 +14,7 @@
         ]
     },
     "keybindings": [
-        {"key": "s", "state": "shelving.index"}
+        {"key": "c", "state": "shelving.index"}
     ],
     "routes": [
         {

From ddbe1057ad9996e42100e156c188faafd40f1a3f Mon Sep 17 00:00:00 2001
From: vicent <vicent@verdnatura.es>
Date: Thu, 6 Oct 2022 09:47:53 +0200
Subject: [PATCH 026/151] feat: add new section

---
 .../10490-august/00-aclItemShelving.sql       |   3 +
 ...00-aclItemShelvingPlacementSupply copy.sql |   3 +
 .../item-shelving-placement-supply.json       |   9 +-
 modules/item/front/item-shelving/index.html   | 132 +++++-------------
 modules/item/front/item-shelving/index.js     | 106 ++++++--------
 .../item/front/item-shelving/locale/es.yml    |  12 +-
 6 files changed, 95 insertions(+), 170 deletions(-)
 create mode 100644 db/changes/10490-august/00-aclItemShelving.sql
 create mode 100644 db/changes/10490-august/00-aclItemShelvingPlacementSupply copy.sql

diff --git a/db/changes/10490-august/00-aclItemShelving.sql b/db/changes/10490-august/00-aclItemShelving.sql
new file mode 100644
index 0000000000..3995bbe497
--- /dev/null
+++ b/db/changes/10490-august/00-aclItemShelving.sql
@@ -0,0 +1,3 @@
+INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
+    VALUES
+        ('ItemShelving', '*', '*', 'ALLOW', 'ROLE', 'employee');
\ No newline at end of file
diff --git a/db/changes/10490-august/00-aclItemShelvingPlacementSupply copy.sql b/db/changes/10490-august/00-aclItemShelvingPlacementSupply copy.sql
new file mode 100644
index 0000000000..cc589a58f4
--- /dev/null
+++ b/db/changes/10490-august/00-aclItemShelvingPlacementSupply copy.sql	
@@ -0,0 +1,3 @@
+INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
+    VALUES
+        ('ItemShelvingPlacementSupplyStock', '*', '*', 'ALLOW', 'ROLE', 'employee');
\ No newline at end of file
diff --git a/modules/item/back/models/item-shelving-placement-supply.json b/modules/item/back/models/item-shelving-placement-supply.json
index 11497b4fc9..a54013e05b 100644
--- a/modules/item/back/models/item-shelving-placement-supply.json
+++ b/modules/item/back/models/item-shelving-placement-supply.json
@@ -7,13 +7,17 @@
         }
     },
     "properties": {
+        "itemShelvingFk": {
+            "type": "number",
+			"id": true
+        },
         "created": {
             "type": "date"
         },
         "itemFk": {
             "type": "number"
         },
-        "concept": {
+        "longName": {
             "type": "string"
         },
         "parking": {
@@ -24,6 +28,9 @@
         },
         "packing": {
             "type": "number"
+        },
+        "stock": {
+            "type": "number"
         }
     }
 }
\ No newline at end of file
diff --git a/modules/item/front/item-shelving/index.html b/modules/item/front/item-shelving/index.html
index 7949e73a3c..115829c8d4 100644
--- a/modules/item/front/item-shelving/index.html
+++ b/modules/item/front/item-shelving/index.html
@@ -1,21 +1,10 @@
 <vn-crud-model
     vn-id="model"
-    url="Defaulters/filter"
-    filter="::$ctrl.filter"
-    limit="20"
-    order="amount DESC"
-    data="defaulters"
+    url="ItemShelvingPlacementSupplyStocks"
+    link="{itemFk: $ctrl.$params.id}"
+    data="itemShelvingPlacementSupplyStocks"
     auto-load="true">
 </vn-crud-model>
-<vn-portal slot="topbar">
-    <vn-searchbar
-        vn-focus
-        placeholder="Search client"
-        info="Search client by id or name"
-        auto-state="false"
-        model="model">
-    </vn-searchbar>
-</vn-portal>
 <vn-card>
     <smart-table 
         model="model"
@@ -34,10 +23,10 @@
             <div class="vn-pa-md">
                 <vn-button 
                     ng-show="$ctrl.checked.length > 0"
-                    ng-click="notesDialog.show()"
-                    name="notesDialog"
-                    vn-tooltip="Add observation"
-                    icon="icon-notes">
+                    ng-click="removeConfirm.show()"
+                    vn-tooltip="Remove selected lines"
+                    vn-acl="replenisherBos"
+                    icon="delete">
                 </vn-button>
             </div>
         </slot-actions>
@@ -50,123 +39,78 @@
                                 model="model">
                             </vn-multi-check>
                         </th>
-                        <th field="clientFk">
+                        <th field="created">
                             <span translate>Created</span>
                         </th>
-                        <th field="salesPersonFk">
+                        <th shrink field="itemFk">
                             <span translate>Item</span>
                         </th>
                         <th 
-                            field="amount" 
-                            vn-tooltip="Balance due">
+                            field="longName">
                             <span translate>Concept</span>
                         </th>
                         <th 
-                            field="workerFk" 
-                            vn-tooltip="Worker who made the last observation">
+                            field="parking">
                             <span translate>Parking</span>
                         </th>
-                        <th field="observation" expand>
+                        <th field="shelving">
                             <span translate>Shelving</span>
                         </th>
                         <th 
-                            vn-tooltip="Last observation date"
-                            field="created">
+                            field="label">
                             <span translate>Etiqueta</span>
                         </th>
                         <th 
-                            field="creditInsurance"
+                            field="packing"
                             shrink>
                             <span translate>Packing</span>
                         </th>
                     </tr>
                 </thead>
                 <tbody>
-                    <tr ng-repeat="defaulter in defaulters">
+                    <tr ng-repeat="itemShelvingPlacementSupplyStock in itemShelvingPlacementSupplyStocks">
                         <td shrink>
                             <vn-check 
-                                ng-model="defaulter.checked"
+                                ng-model="itemShelvingPlacementSupplyStock.checked"
                                 vn-click-stop>
                             </vn-check>
                         </td>
-                        <td title="{{::defaulter.clientName}}">
+                        <td shrink-date>{{::itemShelvingPlacementSupplyStock.created | date: 'dd/MM/yyyy'}}</td>
+                        <td>
+                            {{::itemShelvingPlacementSupplyStock.itemFk}}
+                        </td>
+                        <td expand title="{{::itemShelvingPlacementSupplyStock.longName}}">
                             <span
-                                vn-click-stop="clientDescriptor.show($event, defaulter.clientFk)"
-                                title ="{{::defaulter.clientName}}"
+                                vn-click-stop="itemDescriptor.show($event, itemShelvingPlacementSupplyStock.itemFk)"
                                 class="link">
-                                {{::defaulter.clientName}}
+                                {{itemShelvingPlacementSupplyStock.longName}}
                             </span>
                         </td>
                         <td>
-                            <span
-                                title="{{::defaulter.salesPersonName}}"
-                                vn-click-stop="workerDescriptor.show($event, defaulter.salesPersonFk)"
-                                class="link">
-                                {{::defaulter.salesPersonName | dashIfEmpty}}
-                            </span>
+                            {{::itemShelvingPlacementSupplyStock.parking}}
                         </td>
-                        <td>{{::defaulter.amount | currency: 'EUR': 2}}</td>
                         <td>
-                            <span
-                                title="{{::defaulter.workerName}}"
-                                vn-click-stop="workerDescriptor.show($event, defaulter.workerFk)"
-                                class="link">
-                                {{::defaulter.workerName | dashIfEmpty}}
-                            </span>
+                            {{::itemShelvingPlacementSupplyStock.shelving}}
                         </td>
-                        <td expand>
-                            <vn-textarea
-                                vn-three
-                                disabled="true"
-                                ng-model="defaulter.observation">
-                            </vn-textarea>
+                        <td>
+                            {{::itemShelvingPlacementSupplyStock.label}}
                         </td>
-                        <td shrink-date>
-                            <span class="chip {{::$ctrl.chipColor(defaulter.created)}}">
-                                {{::defaulter.created | date: 'dd/MM/yyyy'}}
-                            </span>
+                        <td>
+                            {{::itemShelvingPlacementSupplyStock.packing}}
                         </td>
-                        <td shrink>{{::defaulter.creditInsurance | currency: 'EUR': 2}}</td>
-                        <td shrink-date>{{::defaulter.defaulterSinced | date: 'dd/MM/yyyy'}}</td>
                     </tr>
                 </tbody>
             </table>
         </slot-table>
     </smart-table>
 </vn-card>
-<vn-client-descriptor-popover
-    vn-id="client-descriptor">
-</vn-client-descriptor-popover>
-<vn-worker-descriptor-popover
-    vn-id="worker-descriptor">
-</vn-worker-descriptor-popover>
-<vn-popup vn-id="dialog-summary-client">
-    <vn-client-summary
-        client="$ctrl.clientSelected">
-    </vn-client-summary>
-</vn-popup>
+<vn-item-descriptor-popover
+    vn-id="item-descriptor">
+</vn-item-descriptor-popover>
 
-<!-- Dialog of add notes button --> 
-<vn-dialog
-    vn-id="notesDialog"
-    on-accept="$ctrl.onResponse()">
-    <tpl-body>
-        <section class="SMSDialog">
-            <h5 class="vn-py-sm">{{$ctrl.$t('Add observation to all selected clients', {total: $ctrl.checked.length})}}</h5>
-            <vn-horizontal>
-                <vn-textarea vn-one
-                    vn-id="message"
-                    label="Message" 
-                    ng-model="$ctrl.defaulter.observation"
-                    rows="3"
-                    required="true"
-                    rule>
-                </vn-textarea>
-            </vn-horizontal>
-        </section>
-    </tpl-body>
-    <tpl-buttons>
-        <input type="button" response="cancel" translate-attr="{value: 'Cancel'}"/>
-        <button response="accept" translate>Save</button>
-    </tpl-buttons>
-</vn-dialog>
+<vn-confirm 
+    vn-id="removeConfirm"
+    message="Selected lines will be deleted"
+    question="Are you sure you want to continue?"
+    on-accept="$ctrl.onRemove()">
+</vn-confirm>
\ No newline at end of file
diff --git a/modules/item/front/item-shelving/index.js b/modules/item/front/item-shelving/index.js
index f51a1a65b5..6fd8825aaf 100644
--- a/modules/item/front/item-shelving/index.js
+++ b/modules/item/front/item-shelving/index.js
@@ -1,11 +1,9 @@
 import ngModule from '../module';
 import Section from 'salix/components/section';
-import UserError from 'core/lib/user-error';
 
 export default class Controller extends Section {
     constructor($element, $) {
         super($element, $);
-        this.defaulter = {};
 
         this.smartTableOptions = {
             activeButtons: {
@@ -13,42 +11,31 @@ export default class Controller extends Section {
             },
             columns: [
                 {
-                    field: 'clientFk',
+                    field: 'parking',
                     autocomplete: {
-                        url: 'Clients',
-                        showField: 'name',
-                        valueField: 'id'
+                        url: 'Parkings',
+                        showField: 'code',
+                        valueField: 'code'
                     }
                 },
                 {
-                    field: 'salesPersonFk',
+                    field: 'shelving',
                     autocomplete: {
-                        url: 'Workers/activeWithInheritedRole',
-                        where: `{role: 'salesPerson'}`,
-                        searchFunction: '{firstName: $search}',
-                        showField: 'name',
-                        valueField: 'id',
+                        url: 'Shelvings',
+                        showField: 'code',
+                        valueField: 'code'
                     }
                 },
-                {
-                    field: 'workerFk',
-                    autocomplete: {
-                        url: 'Workers/activeWithInheritedRole',
-                        searchFunction: '{firstName: $search}',
-                        showField: 'name',
-                        valueField: 'id',
-                    }
-                },
-                {
-                    field: 'observation',
-                    searchable: false
-                },
                 {
                     field: 'created',
                     searchable: false
                 },
                 {
-                    field: 'defaulterSinced',
+                    field: 'itemFk',
+                    searchable: false
+                },
+                {
+                    field: 'longName',
                     searchable: false
                 }
             ]
@@ -58,16 +45,24 @@ export default class Controller extends Section {
     }
 
     get checked() {
-        const clients = this.$.model.data || [];
+        const itemShelvings = this.$.model.data || [];
         const checkedLines = [];
-        for (let defaulter of clients) {
-            if (defaulter.checked)
-                checkedLines.push(defaulter);
+        for (let itemShelving of itemShelvings) {
+            if (itemShelving.checked)
+                checkedLines.push(itemShelving);
         }
 
         return checkedLines;
     }
 
+    get label() {
+        const itemShelvings = this.$.model.data || [];
+        for (let itemShelving of itemShelvings)
+            itemShelving.label = itemShelving.stock / itemShelving.packing;
+
+        return true;
+    }
+
     getBalanceDueTotal() {
         this.$http.get('Defaulters/filter')
             .then(res => {
@@ -80,48 +75,27 @@ export default class Controller extends Section {
             });
     }
 
-    chipColor(date) {
-        const day = 24 * 60 * 60 * 1000;
-        const today = new Date();
-        today.setHours(0, 0, 0, 0);
-
-        const observationShipped = new Date(date);
-        observationShipped.setHours(0, 0, 0, 0);
-
-        const difference = today - observationShipped;
-
-        if (difference > (day * 20))
-            return 'alert';
-        if (difference > (day * 10))
-            return 'warning';
-    }
-
-    onResponse() {
-        if (!this.defaulter.observation)
-            throw new UserError(`The message can't be empty`);
-
+    async onRemove() {
         const params = [];
-        for (let defaulter of this.checked) {
-            params.push({
-                text: this.defaulter.observation,
-                clientFk: defaulter.clientFk
-            });
-        }
+        for (let itemShelving of this.checked)
+            params.push(itemShelving.itemShelvingFk);
 
-        this.$http.post(`ClientObservations`, params) .then(() => {
-            this.vnApp.showMessage(this.$t('Observation saved!'));
-            this.$state.reload();
-        });
+        for (let id of params) {
+            await this.$http.delete(`ItemShelvings/${id}`)
+                .then(() => {
+                    this.vnApp.showSuccess(this.$t('ItemShelving removed'));
+                    this.$state.reload();
+                });
+        }
     }
 
     exprBuilder(param, value) {
         switch (param) {
-        case 'creditInsurance':
-        case 'amount':
-        case 'clientFk':
-        case 'workerFk':
-        case 'salesPersonFk':
-            return {[`d.${param}`]: value};
+        case 'parking':
+        case 'shelving':
+        case 'label':
+        case 'packing':
+            return {[param]: value};
         }
     }
 }
diff --git a/modules/item/front/item-shelving/locale/es.yml b/modules/item/front/item-shelving/locale/es.yml
index c3e1d4e19c..00b6ffe58d 100644
--- a/modules/item/front/item-shelving/locale/es.yml
+++ b/modules/item/front/item-shelving/locale/es.yml
@@ -1,9 +1,3 @@
-Add observation: Añadir observación
-Add observation to all selected clients: Añadir observación a {{total}} cliente(s) seleccionado(s)
-Balance D.: Saldo V.
-Credit I.: Crédito A.
-Last observation: Última observación
-L. O. Date: Fecha Ú. O.
-Last observation date: Fecha última observación
-Search client: Buscar clientes
-Worker who made the last observation: Trabajador que ha realizado la última observación
\ No newline at end of file
+Shelving: Matrícula
+Remove selected lines: Eliminar líneas seleccionadas
+Selected lines will be deleted: Las líneas seleccionadas serán eliminadas
\ No newline at end of file

From 1165e050eb74cee4bc1e76fc9408ecd2de2b4753 Mon Sep 17 00:00:00 2001
From: Pau Navarro <pau@verdnatura.es>
Date: Thu, 6 Oct 2022 10:18:08 +0200
Subject: [PATCH 027/151] feat: workerDisableExcluded update DB field

---
 .../methods/worker/workerDisableExcluded.js   | 30 +++++++++++++
 .../worker/workerExcludeFromDisable.js        | 45 +++++++++++++++++++
 .../workerDisableExclueded/checkExcluded.js   | 26 -----------
 modules/worker/back/models/worker.js          |  2 +
 .../back/models/workerDisableExcluded.json    |  5 ++-
 modules/worker/front/descriptor/index.html    | 21 +++++----
 modules/worker/front/descriptor/index.js      | 24 +++++++---
 7 files changed, 112 insertions(+), 41 deletions(-)
 create mode 100644 modules/worker/back/methods/worker/workerDisableExcluded.js
 create mode 100644 modules/worker/back/methods/worker/workerExcludeFromDisable.js
 delete mode 100644 modules/worker/back/methods/workerDisableExclueded/checkExcluded.js

diff --git a/modules/worker/back/methods/worker/workerDisableExcluded.js b/modules/worker/back/methods/worker/workerDisableExcluded.js
new file mode 100644
index 0000000000..017e044c25
--- /dev/null
+++ b/modules/worker/back/methods/worker/workerDisableExcluded.js
@@ -0,0 +1,30 @@
+
+module.exports = Self => {
+    Self.remoteMethod('workerDisableExcluded', {
+        description: 'Check if the worker can be disabled',
+        accessType: 'READ',
+        accepts: {
+            arg: 'id',
+            type: 'Number',
+            required: true,
+            description: `The worker id`,
+            http: {source: 'path'}
+        },
+        returns: {
+            type: 'boolean',
+            root: true
+        },
+        http: {
+            path: `/workerDisableExcluded/:id`,
+            verb: 'GET'
+        }
+    });
+
+    Self.workerDisableExcluded = async id => {
+        let result;
+        const query = `Select * from vn.workerDisableExcluded where workerFk like ${id}`;
+        let sqlResult = await Self.rawSql(query);
+        sqlResult.length == 0 ? result = false : result = true;
+        return result;
+    };
+};
diff --git a/modules/worker/back/methods/worker/workerExcludeFromDisable.js b/modules/worker/back/methods/worker/workerExcludeFromDisable.js
new file mode 100644
index 0000000000..86d940862d
--- /dev/null
+++ b/modules/worker/back/methods/worker/workerExcludeFromDisable.js
@@ -0,0 +1,45 @@
+module.exports = Self => {
+    Self.remoteMethod('workerExcludeFromDisable', {
+        description: 'Change the status of the worker between can be disabled and cant be disabled',
+        accessType: 'READ',
+        accepts: [{
+            arg: 'id',
+            type: 'Number',
+            required: true,
+            description: `The worker id`,
+            http: {source: 'path'}
+        },
+        {
+            arg: 'currValue',
+            type: 'Boolean',
+            required: true,
+            description: `The current value of workerDisableExcluded`,
+            http: {source: 'path'}
+        }],
+        returns: {
+            type: 'boolean',
+            root: true
+        },
+        http: {
+            path: `/workerExcludeFromDisable/:id/:currValue`,
+            verb: 'GET'
+        }
+    });
+
+    Self.workerExcludeFromDisable = async(id, currValue) => {
+        const models = Self.app.models;
+
+        if (!currValue) {
+            await models.WorkerDisableExcluded.create({
+                workerFk: id,
+                dated: new Date()
+            });
+        } else {
+            await models.WorkerDisableExcluded.remove({
+                workerFk: id
+            });
+        }
+
+        return false;
+    };
+};
diff --git a/modules/worker/back/methods/workerDisableExclueded/checkExcluded.js b/modules/worker/back/methods/workerDisableExclueded/checkExcluded.js
deleted file mode 100644
index 32260c01f1..0000000000
--- a/modules/worker/back/methods/workerDisableExclueded/checkExcluded.js
+++ /dev/null
@@ -1,26 +0,0 @@
-
-module.exports = Self => {
-    Self.remoteMethod('workerDisableExcluded', {
-        description: 'Check an email inbox and process it',
-        accessType: 'READ',
-        accepts: {
-            arg: 'workerFk',
-            type: 'Number',
-            required: true,
-            description: `The worker id`
-        },
-        returns: {
-            type: ['Object'],
-            root: true
-        },
-        http: {
-            path: `/workerDisableExcluded`,
-            verb: 'GET'
-        }
-    });
-
-    Self.workerDisableExcluded = workerFk => {
-        console.log(workerFk);
-        return 'tests123';
-    };
-};
diff --git a/modules/worker/back/models/worker.js b/modules/worker/back/models/worker.js
index ec6c4af282..c90729779a 100644
--- a/modules/worker/back/models/worker.js
+++ b/modules/worker/back/models/worker.js
@@ -13,4 +13,6 @@ module.exports = Self => {
     require('../methods/worker/contracts')(Self);
     require('../methods/worker/holidays')(Self);
     require('../methods/worker/activeContract')(Self);
+    require('../methods/worker/workerDisableExcluded')(Self);
+    require('../methods/worker/workerExcludeFromDisable')(Self);
 };
diff --git a/modules/worker/back/models/workerDisableExcluded.json b/modules/worker/back/models/workerDisableExcluded.json
index eeffb4b15d..cfa810e437 100644
--- a/modules/worker/back/models/workerDisableExcluded.json
+++ b/modules/worker/back/models/workerDisableExcluded.json
@@ -7,9 +7,12 @@
 		}
 	},
 	"properties": {
-		"id": {
+		"workerFk": {
 			"id": true,
 			"type": "number"
+		},
+		"dated": {
+			"type": "date"
 		}
 	},
 	"acls": [
diff --git a/modules/worker/front/descriptor/index.html b/modules/worker/front/descriptor/index.html
index 0616f179fd..d3caa78a80 100644
--- a/modules/worker/front/descriptor/index.html
+++ b/modules/worker/front/descriptor/index.html
@@ -15,14 +15,19 @@
         </div>
     </slot-before>
     <slot-menu>
-        <label class="vn-item">
-            <!--
-            <input ng-if="$ctrl.isExcluded()" type="checkbox" id="canBeDisabled" disabled checked>
-            <input ng-if="!$ctrl.isExcluded()" type="checkbox" id="canBeDisabled" disabled>
-            -->
-
-            <p>{{$ctrl.isExcluded()}}</p>
-        </label>       
+         <!--ng-if="!$ctrl.canBeExcluded"-->
+         <vn-item
+            ng-click="$ctrl.setExcluded()"
+            translate
+            ng-if="!$ctrl.excluded">
+            Marcar para no deshabilitar
+        </vn-item>
+        <vn-item
+            ng-click="$ctrl.setExcluded()"
+            translate
+            ng-if="$ctrl.excluded">
+            Marcar como deshabilitable
+        </vn-item>
     </slot-menu>
     <slot-body>
         <div class="attributes">
diff --git a/modules/worker/front/descriptor/index.js b/modules/worker/front/descriptor/index.js
index e1026382df..2f79c2d807 100644
--- a/modules/worker/front/descriptor/index.js
+++ b/modules/worker/front/descriptor/index.js
@@ -5,6 +5,7 @@ class Controller extends Descriptor {
     constructor($element, $, $rootScope) {
         super($element, $);
         this.$rootScope = $rootScope;
+        this.canBeExcluded();
     }
 
     get worker() {
@@ -15,12 +16,23 @@ class Controller extends Descriptor {
         this.entity = value;
     }
 
-    async isExcluded() {
-        // eslint-disable-next-line no-console
-        console.log(this.entity);
-        let excluded = await this.$http.get(`workerDisableExcluded`);
-        // eslint-disable-next-line no-console
-        console.log(excluded);
+    get excluded() {
+        return this.entity.excluded;
+    }
+
+    set excluded(value) {
+        this.entity.excluded = value;
+    }
+
+    async canBeExcluded() {
+        await new Promise(r => setTimeout(r, 1000));
+        let data = await this.$http.get(`Workers/workerDisableExcluded/${this.entity.id}`);
+        this.excluded = data.data;
+    }
+
+    async setExcluded() {
+        await this.$http.get(`Workers/workerExcludeFromDisable/${this.entity.id}/${this.entity.excluded}`);
+        this.canBeExcluded();
     }
 
     loadData() {

From a3a432c753c19d263d642c379aa1d7c4977b3a6e Mon Sep 17 00:00:00 2001
From: vicent <vicent@verdnatura.es>
Date: Thu, 6 Oct 2022 10:18:19 +0200
Subject: [PATCH 028/151] fix: delete one or more expeditions

---
 modules/ticket/front/expedition/index.html    | 11 ++++++-----
 modules/ticket/front/expedition/index.js      | 14 ++++++++++++++
 modules/ticket/front/expedition/locale/es.yml |  3 ++-
 3 files changed, 22 insertions(+), 6 deletions(-)

diff --git a/modules/ticket/front/expedition/index.html b/modules/ticket/front/expedition/index.html
index 694b3eb33c..caef67f59e 100644
--- a/modules/ticket/front/expedition/index.html
+++ b/modules/ticket/front/expedition/index.html
@@ -17,8 +17,9 @@
                     ng-show="$ctrl.totalChecked">
                 </vn-button>
                 <vn-button 
+                    ng-show="$ctrl.checked.length > 0"
+                    ng-click="removeConfirm.show()"
                     icon="delete"
-                    ng-click="deleteExpedition.show(expedition.id)"
                     vn-tooltip="Delete expedition">
                 </vn-button>
             </vn-tool-bar>
@@ -88,11 +89,11 @@
 <vn-worker-descriptor-popover 
     vn-id="worker-descriptor">
 </vn-worker-descriptor-popover>
-<vn-confirm
-    vn-id="delete-expedition"
-    on-accept="$ctrl.onDialogAccept($data)"
+<vn-confirm 
+    vn-id="removeConfirm"
+    message="Are you sure you want to delete this expedition?"
     question="Delete expedition"
-    message="Are you sure you want to delete this expedition?">
+    on-accept="$ctrl.onRemove()">
 </vn-confirm>
  
 <vn-popup vn-id="statusLog">
diff --git a/modules/ticket/front/expedition/index.js b/modules/ticket/front/expedition/index.js
index d80c8e812b..1525f97b5d 100644
--- a/modules/ticket/front/expedition/index.js
+++ b/modules/ticket/front/expedition/index.js
@@ -27,6 +27,20 @@ class Controller extends Section {
         return this.checked.length;
     }
 
+    async onRemove() {
+        const params = [];
+        for (let expedition of this.checked)
+            params.push(expedition.id);
+
+        for (let id of params) {
+            await this.$http.delete(`Expeditions/${id}`)
+                .then(() => {
+                    this.vnApp.showSuccess(this.$t('Expedition removed'));
+                    this.$state.reload();
+                });
+        }
+    }
+
     createTicket(routeFk) {
         const tomorrow = new Date();
         const params = {
diff --git a/modules/ticket/front/expedition/locale/es.yml b/modules/ticket/front/expedition/locale/es.yml
index d23cf25af3..9c7872fd70 100644
--- a/modules/ticket/front/expedition/locale/es.yml
+++ b/modules/ticket/front/expedition/locale/es.yml
@@ -1 +1,2 @@
-Status log: Hitorial de estados
\ No newline at end of file
+Status log: Hitorial de estados
+Expedition removed: Expedición eliminada
\ No newline at end of file

From 37601934f579e55668e5b2eae07e9b68e95a3e81 Mon Sep 17 00:00:00 2001
From: vicent <vicent@verdnatura.es>
Date: Thu, 6 Oct 2022 11:40:46 +0200
Subject: [PATCH 029/151] feat: first option to delete and update

---
 modules/ticket/front/expedition/index.js | 16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/modules/ticket/front/expedition/index.js b/modules/ticket/front/expedition/index.js
index 1525f97b5d..4f7b34e7cb 100644
--- a/modules/ticket/front/expedition/index.js
+++ b/modules/ticket/front/expedition/index.js
@@ -42,17 +42,25 @@ class Controller extends Section {
     }
 
     createTicket(routeFk) {
-        const tomorrow = new Date();
-        const params = {
+        const date = new Date(); // esta fecha hay que preguntarla a Fran Monsalvez
+        const ticketParams = {
             clientId: this.ticket.clientFk,
-            landed: tomorrow.getDay() + 1,
+            landed: date,
             addressId: this.ticket.addressFk,
             agencyModeId: this.ticket.agencyModeFk,
             warehouseId: this.ticket.warehouseFk
         };
         const query = `Tickets/new`;
-        this.$http.post(query, params).then(res => {
+        this.$http.post(query, ticketParams).then(res => {
             if (routeFk) this.$http.patch(`Tickets/${res.data.id}`, {routeFk: routeFk});
+
+            const params = [];
+            for (let expedition of this.checked)
+                params.push(expedition.id);
+            const expeditionParams = {ticketFk: res.data.id};
+            for (let id of params)
+                this.$http.patch(`Expeditions/${id}`, expeditionParams);
+
             this.vnApp.showSuccess(this.$t('Data saved!'));
             this.$state.go('ticket.card.summary', {id: res.data.id});
         });

From 3376293d1a60e4732346c5eb2e26f81b5e20d62c Mon Sep 17 00:00:00 2001
From: Pau Navarro <pau@verdnatura.es>
Date: Thu, 6 Oct 2022 11:54:14 +0200
Subject: [PATCH 030/151] Added user icon and fixed icon not updating

---
 modules/worker/front/descriptor/index.html | 7 +++++++
 modules/worker/front/descriptor/index.js   | 5 +++--
 2 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/modules/worker/front/descriptor/index.html b/modules/worker/front/descriptor/index.html
index d3caa78a80..c60801bb98 100644
--- a/modules/worker/front/descriptor/index.html
+++ b/modules/worker/front/descriptor/index.html
@@ -52,6 +52,13 @@
                 value="{{$ctrl.worker.sip.extension}}">
             </vn-label-value>
         </div>
+        <div class="icons">
+            <vn-icon
+                vn-tooltip="Fijado para no deshabilitar"
+                icon="person"
+                ng-if="$ctrl.worker.excluded">
+            </vn-icon>
+        </div>
         <div class="quicklinks">
             <div ng-transclude="btnOne">
                 <vn-quick-link
diff --git a/modules/worker/front/descriptor/index.js b/modules/worker/front/descriptor/index.js
index 2f79c2d807..7a3922a089 100644
--- a/modules/worker/front/descriptor/index.js
+++ b/modules/worker/front/descriptor/index.js
@@ -22,17 +22,18 @@ class Controller extends Descriptor {
 
     set excluded(value) {
         this.entity.excluded = value;
+        this.$rootScope.$apply();
     }
 
     async canBeExcluded() {
-        await new Promise(r => setTimeout(r, 1000));
+        await new Promise(r => setTimeout(r, 500));
         let data = await this.$http.get(`Workers/workerDisableExcluded/${this.entity.id}`);
         this.excluded = data.data;
     }
 
     async setExcluded() {
         await this.$http.get(`Workers/workerExcludeFromDisable/${this.entity.id}/${this.entity.excluded}`);
-        this.canBeExcluded();
+        this.excluded = !this.entity.excluded;
     }
 
     loadData() {

From deb8a00dfb2edbd5d3a2a2e84caec89679cce5ad Mon Sep 17 00:00:00 2001
From: vicent <vicent@verdnatura.es>
Date: Fri, 7 Oct 2022 10:47:54 +0200
Subject: [PATCH 031/151] feat: add backRoutes

---
 .../methods/expedition/deleteExpeditions.js   | 48 +++++++++++++++
 .../methods/expedition/moveExpeditions.js     | 59 +++++++++++++++++++
 modules/ticket/back/models/expedition.js      |  2 +
 modules/ticket/front/expedition/index.html    |  4 +-
 modules/ticket/front/expedition/index.js      | 35 +++++------
 modules/ticket/front/expedition/locale/es.yml |  5 +-
 6 files changed, 130 insertions(+), 23 deletions(-)
 create mode 100644 modules/ticket/back/methods/expedition/deleteExpeditions.js
 create mode 100644 modules/ticket/back/methods/expedition/moveExpeditions.js

diff --git a/modules/ticket/back/methods/expedition/deleteExpeditions.js b/modules/ticket/back/methods/expedition/deleteExpeditions.js
new file mode 100644
index 0000000000..b902b9f0c5
--- /dev/null
+++ b/modules/ticket/back/methods/expedition/deleteExpeditions.js
@@ -0,0 +1,48 @@
+
+module.exports = Self => {
+    Self.remoteMethod('deleteExpeditions', {
+        description: 'Delete the selected expeditions',
+        accessType: 'WRITE',
+        accepts: [{
+            arg: 'expeditionsIds',
+            type: ['number'],
+            required: true,
+            description: 'The expeditions ids to delete'
+        }],
+        returns: {
+            type: ['object'],
+            root: true
+        },
+        http: {
+            path: `/deleteExpeditions`,
+            verb: 'POST'
+        }
+    });
+
+    Self.deleteExpeditions = async(expeditionsIds, options) => {
+        const models = Self.app.models;
+        const myOptions = {};
+        let tx;
+
+        if (typeof options == 'object')
+            Object.assign(myOptions, options);
+
+        if (!myOptions.transaction) {
+            tx = await Self.beginTransaction({});
+            myOptions.transaction = tx;
+        }
+
+        try {
+            const deletedExpeditions = await models.Expedition.destroyAll({
+                id: {inq: expeditionsIds}
+            }, myOptions);
+
+            if (tx) await tx.commit();
+
+            return deletedExpeditions;
+        } catch (e) {
+            if (tx) await tx.rollback();
+            throw e;
+        }
+    };
+};
diff --git a/modules/ticket/back/methods/expedition/moveExpeditions.js b/modules/ticket/back/methods/expedition/moveExpeditions.js
new file mode 100644
index 0000000000..2c521dda7c
--- /dev/null
+++ b/modules/ticket/back/methods/expedition/moveExpeditions.js
@@ -0,0 +1,59 @@
+
+module.exports = Self => {
+    Self.remoteMethod('moveExpeditions', {
+        description: 'Move the selected expeditions to another ticket',
+        accessType: 'WRITE',
+        accepts: [{
+            arg: 'expeditionsIds',
+            type: ['number'],
+            required: true,
+            description: 'The expeditions ids to nove'
+        },
+        {
+            arg: 'ticketId',
+            type: 'number',
+            required: true,
+            description: 'the ticket id to which the expeditions are added'
+        }],
+        returns: {
+            type: 'object',
+            root: true
+        },
+        http: {
+            path: `/moveExpeditions`,
+            verb: 'POST'
+        }
+    });
+
+    Self.moveExpeditions = async(expeditionsIds, ticketId, options) => {
+        const models = Self.app.models;
+        const myOptions = {};
+        let tx;
+
+        if (typeof options == 'object')
+            Object.assign(myOptions, options);
+
+        if (!myOptions.transaction) {
+            tx = await Self.beginTransaction({});
+            myOptions.transaction = tx;
+        }
+
+        try {
+            const promises = [];
+            for (let expeditionsId of expeditionsIds) {
+                const expeditionToUpdate = await models.Expedition.findById(expeditionsId);
+                const expeditionUpdated = expeditionToUpdate.updateAttribute('ticketFk', ticketId, myOptions);
+                promises.push(expeditionUpdated);
+            }
+
+            const updated = await Promise.all(promises);
+
+            if (tx) await tx.commit();
+
+            return updated;
+        } catch (e) {
+            if (tx) await tx.rollback();
+            throw e;
+        }
+    };
+};
diff --git a/modules/ticket/back/models/expedition.js b/modules/ticket/back/models/expedition.js
index 9d65643737..46cde68902 100644
--- a/modules/ticket/back/models/expedition.js
+++ b/modules/ticket/back/models/expedition.js
@@ -1,3 +1,5 @@
 module.exports = function(Self) {
     require('../methods/expedition/filter')(Self);
+    require('../methods/expedition/deleteExpeditions')(Self);
+    require('../methods/expedition/moveExpeditions')(Self);
 };
diff --git a/modules/ticket/front/expedition/index.html b/modules/ticket/front/expedition/index.html
index caef67f59e..35f56872c2 100644
--- a/modules/ticket/front/expedition/index.html
+++ b/modules/ticket/front/expedition/index.html
@@ -14,10 +14,10 @@
                 <vn-button icon="keyboard_arrow_down"
                     label="Move"
                     ng-click="moreOptions.show($event)"
-                    ng-show="$ctrl.totalChecked">
+                    disabled="!$ctrl.totalChecked">
                 </vn-button>
                 <vn-button 
-                    ng-show="$ctrl.checked.length > 0"
+                    disabled="!$ctrl.checked.length"
                     ng-click="removeConfirm.show()"
                     icon="delete"
                     vn-tooltip="Delete expedition">
diff --git a/modules/ticket/front/expedition/index.js b/modules/ticket/front/expedition/index.js
index 4f7b34e7cb..a81439d644 100644
--- a/modules/ticket/front/expedition/index.js
+++ b/modules/ticket/front/expedition/index.js
@@ -17,7 +17,7 @@ class Controller extends Section {
         const checkedRows = [];
         for (let row of rows) {
             if (row.checked)
-                checkedRows.push(row);
+                checkedRows.push(row.id);
         }
 
         return checkedRows;
@@ -27,18 +27,14 @@ class Controller extends Section {
         return this.checked.length;
     }
 
-    async onRemove() {
-        const params = [];
-        for (let expedition of this.checked)
-            params.push(expedition.id);
-
-        for (let id of params) {
-            await this.$http.delete(`Expeditions/${id}`)
-                .then(() => {
-                    this.vnApp.showSuccess(this.$t('Expedition removed'));
-                    this.$state.reload();
-                });
-        }
+    onRemove() {
+        const params = {expeditionsIds: this.checked};
+        const query = `Expeditions/deleteExpeditions`;
+        this.$http.post(query, params)
+            .then(() => {
+                this.vnApp.showSuccess(this.$t('Expedition removed'));
+                this.$state.reload();
+            });
     }
 
     createTicket(routeFk) {
@@ -54,13 +50,12 @@ class Controller extends Section {
         this.$http.post(query, ticketParams).then(res => {
             if (routeFk) this.$http.patch(`Tickets/${res.data.id}`, {routeFk: routeFk});
 
-            const params = [];
-            for (let expedition of this.checked)
-                params.push(expedition.id);
-            const expeditionParams = {ticketFk: res.data.id};
-            for (let id of params)
-                this.$http.patch(`Expeditions/${id}`, expeditionParams);
-
+            const params = {
+                expeditionsIds: this.checked,
+                ticketId: res.data.id
+            };
+            const query = `Expeditions/moveExpeditions`;
+            this.$http.post(query, params);
             this.vnApp.showSuccess(this.$t('Data saved!'));
             this.$state.go('ticket.card.summary', {id: res.data.id});
         });
diff --git a/modules/ticket/front/expedition/locale/es.yml b/modules/ticket/front/expedition/locale/es.yml
index 9c7872fd70..bc3ec33455 100644
--- a/modules/ticket/front/expedition/locale/es.yml
+++ b/modules/ticket/front/expedition/locale/es.yml
@@ -1,2 +1,5 @@
 Status log: Hitorial de estados
-Expedition removed: Expedición eliminada
\ No newline at end of file
+Expedition removed: Expedición eliminada
+Move: Mover
+New ticket without route: Nuevo ticket sin ruta
+New ticket with route: Nuevo ticket con ruta
\ No newline at end of file

From bb26fa6502232335c784f9fb101a381bf4f1be39 Mon Sep 17 00:00:00 2001
From: vicent <vicent@verdnatura.es>
Date: Fri, 7 Oct 2022 13:49:42 +0200
Subject: [PATCH 032/151] feat: add tFront

---
 modules/ticket/front/expedition/index.js      | 23 ++++----
 modules/ticket/front/expedition/index.spec.js | 58 +++++++++++++++++++
 2 files changed, 69 insertions(+), 12 deletions(-)

diff --git a/modules/ticket/front/expedition/index.js b/modules/ticket/front/expedition/index.js
index a81439d644..f7674716b1 100644
--- a/modules/ticket/front/expedition/index.js
+++ b/modules/ticket/front/expedition/index.js
@@ -2,16 +2,6 @@ import ngModule from '../module';
 import Section from 'salix/components/section';
 
 class Controller extends Section {
-    onDialogAccept(id) {
-        return this.$http.delete(`Expeditions/${id}`)
-            .then(() => this.$.model.refresh());
-    }
-
-    showLog(expedition) {
-        this.expedition = expedition;
-        this.$.statusLog.show();
-    }
-
     get checked() {
         const rows = this.$.model.data || [];
         const checkedRows = [];
@@ -27,13 +17,23 @@ class Controller extends Section {
         return this.checked.length;
     }
 
+    onDialogAccept(id) {
+        return this.$http.delete(`Expeditions/${id}`)
+            .then(() => this.$.model.refresh());
+    }
+
+    showLog(expedition) {
+        this.expedition = expedition;
+        this.$.statusLog.show();
+    }
+
     onRemove() {
         const params = {expeditionsIds: this.checked};
         const query = `Expeditions/deleteExpeditions`;
         this.$http.post(query, params)
             .then(() => {
                 this.vnApp.showSuccess(this.$t('Expedition removed'));
-                this.$state.reload();
+                this.$.model.refresh();
             });
     }
 
@@ -49,7 +49,6 @@ class Controller extends Section {
         const query = `Tickets/new`;
         this.$http.post(query, ticketParams).then(res => {
             if (routeFk) this.$http.patch(`Tickets/${res.data.id}`, {routeFk: routeFk});
-
             const params = {
                 expeditionsIds: this.checked,
                 ticketId: res.data.id
diff --git a/modules/ticket/front/expedition/index.spec.js b/modules/ticket/front/expedition/index.spec.js
index 586ef21096..fe23046ce2 100644
--- a/modules/ticket/front/expedition/index.spec.js
+++ b/modules/ticket/front/expedition/index.spec.js
@@ -17,6 +17,14 @@ describe('Ticket', () => {
                 refresh: () => {}
             };
             controller = $componentController('vnTicketExpedition', {$element: null, $scope});
+            controller.$.model.data = [
+                {id: 1},
+                {id: 2},
+                {id: 3}
+            ];
+            const modelData = controller.$.model.data;
+            modelData[0].checked = true;
+            modelData[1].checked = true;
         }));
 
         describe('onDialogAccept()', () => {
@@ -50,5 +58,55 @@ describe('Ticket', () => {
                 expect(controller.$.statusLog.show).toHaveBeenCalledWith();
             });
         });
+
+        describe('onRemove()', () => {
+            it('should make a query and then call to the model refresh() method', () => {
+                jest.spyOn($scope.model, 'refresh');
+
+                const expectedParams = {expeditionsIds: [1, 2]};
+                $httpBackend.expect('POST', 'Expeditions/deleteExpeditions', expectedParams).respond(200);
+                controller.onRemove();
+                $httpBackend.flush();
+
+                expect($scope.model.refresh).toHaveBeenCalledWith();
+            });
+        });
+
+        describe('createTicket()', () => {
+            it('should make a query and then call to the $state go() method', () => {
+                jest.spyOn(controller.$state, 'go').mockReturnThis();
+
+                const ticket = {
+                    clientFk: 1101,
+                    landed: new Date(),
+                    addressFk: 121,
+                    agencyModeFk: 1,
+                    warehouseFk: 1
+                };
+                controller.ticket = ticket;
+
+                const expectedTicket = {
+                    clientId: 1101,
+                    landed: new Date(),
+                    addressId: 121,
+                    agencyModeId: 1,
+                    warehouseId: 1
+                };
+
+                const ticketIdToTransfer = 28;
+                const expectedResponse = {id: ticketIdToTransfer};
+
+                const expectedParams = {
+                    expeditionsIds: [1, 2],
+                    ticketId: 28
+                };
+                $httpBackend.expect('POST', 'Tickets/new', expectedTicket).respond(expectedResponse);
+                $httpBackend.expect('POST', 'Expeditions/moveExpeditions', expectedParams).respond(200);
+                controller.createTicket();
+                $httpBackend.flush();
+
+                expect(controller.$state.go).toHaveBeenCalledWith('ticket.card.summary', {id: ticketIdToTransfer});
+            });
+        });
     });
 });

From 843f67919c9992e7e622f01b8dcfca7697fd81b3 Mon Sep 17 00:00:00 2001
From: vicent <vicent@verdnatura.es>
Date: Mon, 10 Oct 2022 12:56:03 +0200
Subject: [PATCH 033/151] feat: add backTest

---
 .../specs/deleteExpeditions.spec.js           | 22 ++++++++++++++++++
 .../expedition/specs/moveExpeditions.spec.js  | 23 +++++++++++++++++++
 2 files changed, 45 insertions(+)
 create mode 100644 modules/ticket/back/methods/expedition/specs/deleteExpeditions.spec.js
 create mode 100644 modules/ticket/back/methods/expedition/specs/moveExpeditions.spec.js

diff --git a/modules/ticket/back/methods/expedition/specs/deleteExpeditions.spec.js b/modules/ticket/back/methods/expedition/specs/deleteExpeditions.spec.js
new file mode 100644
index 0000000000..0a47c78da1
--- /dev/null
+++ b/modules/ticket/back/methods/expedition/specs/deleteExpeditions.spec.js
@@ -0,0 +1,22 @@
+const models = require('vn-loopback/server/server').models;
+
+describe('ticket deleteExpeditions()', () => {
+    it('should delete the selected expeditions', async() => {
+        const tx = await models.Expedition.beginTransaction({});
+
+        try {
+            const options = {transaction: tx};
+
+            const expeditionIds = [12, 13];
+            const result = await models.Expedition.deleteExpeditions(expeditionIds, options);
+
+            expect(result.count).toEqual(2);
+
+            await tx.rollback();
+        } catch (e) {
+            await tx.rollback();
+            throw e;
+        }
+    });
+});
+
diff --git a/modules/ticket/back/methods/expedition/specs/moveExpeditions.spec.js b/modules/ticket/back/methods/expedition/specs/moveExpeditions.spec.js
new file mode 100644
index 0000000000..0bb402a558
--- /dev/null
+++ b/modules/ticket/back/methods/expedition/specs/moveExpeditions.spec.js
@@ -0,0 +1,23 @@
+const models = require('vn-loopback/server/server').models;
+
+describe('ticket moveExpeditions()', () => {
+    it('should delete the selected expeditions', async() => {
+        const tx = await models.Expedition.beginTransaction({});
+
+        try {
+            const options = {transaction: tx};
+
+            const expeditionIds = [12, 13];
+            const ticketId = 1;
+            const result = await models.Expedition.moveExpeditions(expeditionIds, ticketId, options);
+
+            expect(result.length).toEqual(2);
+
+            await tx.rollback();
+        } catch (e) {
+            await tx.rollback();
+            throw e;
+        }
+    });
+});
+

From ea1714240e63f97bd91a9de75d3ca8463c88de17 Mon Sep 17 00:00:00 2001
From: vicent <vicent@verdnatura.es>
Date: Mon, 10 Oct 2022 13:45:34 +0200
Subject: [PATCH 034/151] fix: test e2e

---
 e2e/helpers/selectors.js                           | 3 ++-
 e2e/paths/05-ticket/02_expeditions_and_log.spec.js | 3 ++-
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/e2e/helpers/selectors.js b/e2e/helpers/selectors.js
index fedcaf5f95..97a58ba9c1 100644
--- a/e2e/helpers/selectors.js
+++ b/e2e/helpers/selectors.js
@@ -596,7 +596,8 @@ export default {
         submitNotesButton: 'button[type=submit]'
     },
     ticketExpedition: {
-        thirdExpeditionRemoveButton: 'vn-ticket-expedition vn-table div > vn-tbody > vn-tr:nth-child(3) > vn-td:nth-child(1) > vn-icon-button[icon="delete"]',
+        thirdSaleCheckbox: 'vn-ticket-expedition vn-tr:nth-child(3) vn-check[ng-model="expedition.checked"]',
+        deleteExpeditionButton: 'vn-ticket-expedition vn-tool-bar > vn-button[icon="delete"]',
         expeditionRow: 'vn-ticket-expedition vn-table vn-tbody > vn-tr'
     },
     ticketPackages: {
diff --git a/e2e/paths/05-ticket/02_expeditions_and_log.spec.js b/e2e/paths/05-ticket/02_expeditions_and_log.spec.js
index dd2525f439..f970247e51 100644
--- a/e2e/paths/05-ticket/02_expeditions_and_log.spec.js
+++ b/e2e/paths/05-ticket/02_expeditions_and_log.spec.js
@@ -18,7 +18,8 @@ describe('Ticket expeditions and log path', () => {
     });
 
     it(`should delete a former expedition and confirm the remaining expedition are the expected ones`, async() => {
-        await page.waitToClick(selectors.ticketExpedition.thirdExpeditionRemoveButton);
+        await page.waitToClick(selectors.ticketExpedition.thirdSaleCheckbox);
+        await page.waitToClick(selectors.ticketExpedition.deleteExpeditionButton);
         await page.waitToClick(selectors.globalItems.acceptButton);
         await page.reloadSection('ticket.card.expedition');
 

From 9c52508a88a20d1d5d827b3c8c3e4d08494b32d0 Mon Sep 17 00:00:00 2001
From: vicent <vicent@verdnatura.es>
Date: Tue, 11 Oct 2022 08:40:22 +0200
Subject: [PATCH 035/151] feat: add total labels

---
 .../00-aclItemShelving.sql                    |  0
 .../00-aclItemShelvingPlacementSupply.sql}    |  0
 .../00-itemType.sql                           |  0
 .../item-shelving/deleteItemShelvings.js      | 47 +++++++++++++++++++
 .../specs/deleteItemShelvings.spec.js         | 21 +++++++++
 modules/item/back/models/item-shelving.js     |  3 ++
 modules/item/front/item-shelving/index.html   | 18 +++----
 modules/item/front/item-shelving/index.js     | 45 ++++++------------
 .../item/front/item-shelving/locale/es.yml    |  4 +-
 9 files changed, 98 insertions(+), 40 deletions(-)
 rename db/changes/{10490-august => 10491-august}/00-aclItemShelving.sql (100%)
 rename db/changes/{10490-august/00-aclItemShelvingPlacementSupply copy.sql => 10491-august/00-aclItemShelvingPlacementSupply.sql} (100%)
 rename db/changes/{10480-june => 10491-august}/00-itemType.sql (100%)
 create mode 100644 modules/item/back/methods/item-shelving/deleteItemShelvings.js
 create mode 100644 modules/item/back/methods/item-shelving/specs/deleteItemShelvings.spec.js
 create mode 100644 modules/item/back/models/item-shelving.js

diff --git a/db/changes/10490-august/00-aclItemShelving.sql b/db/changes/10491-august/00-aclItemShelving.sql
similarity index 100%
rename from db/changes/10490-august/00-aclItemShelving.sql
rename to db/changes/10491-august/00-aclItemShelving.sql
diff --git a/db/changes/10490-august/00-aclItemShelvingPlacementSupply copy.sql b/db/changes/10491-august/00-aclItemShelvingPlacementSupply.sql
similarity index 100%
rename from db/changes/10490-august/00-aclItemShelvingPlacementSupply copy.sql
rename to db/changes/10491-august/00-aclItemShelvingPlacementSupply.sql
diff --git a/db/changes/10480-june/00-itemType.sql b/db/changes/10491-august/00-itemType.sql
similarity index 100%
rename from db/changes/10480-june/00-itemType.sql
rename to db/changes/10491-august/00-itemType.sql
diff --git a/modules/item/back/methods/item-shelving/deleteItemShelvings.js b/modules/item/back/methods/item-shelving/deleteItemShelvings.js
new file mode 100644
index 0000000000..0b58970d83
--- /dev/null
+++ b/modules/item/back/methods/item-shelving/deleteItemShelvings.js
@@ -0,0 +1,47 @@
+module.exports = Self => {
+    Self.remoteMethod('deleteItemShelvings', {
+        description: 'Deletes the selected orders',
+        accessType: 'WRITE',
+        accepts: [{
+            arg: 'itemShelvingIds',
+            type: ['number'],
+            required: true,
+            description: 'The itemShelving ids to delete'
+        }],
+        returns: {
+            type: ['object'],
+            root: true
+        },
+        http: {
+            path: `/deleteItemShelvings`,
+            verb: 'POST'
+        }
+    });
+
+    Self.deleteItemShelvings = async(itemShelvingIds, options) => {
+        const models = Self.app.models;
+        const myOptions = {};
+        let tx;
+
+        if (typeof options == 'object')
+            Object.assign(myOptions, options);
+
+        if (!myOptions.transaction) {
+            tx = await Self.beginTransaction({});
+            myOptions.transaction = tx;
+        }
+
+        try {
+            const deletedItemShelvings = await models.ItemShelving.destroyAll({
+                id: {inq: itemShelvingIds}
+            }, myOptions);
+
+            if (tx) await tx.commit();
+
+            return deletedItemShelvings;
+        } catch (e) {
+            if (tx) await tx.rollback();
+            throw e;
+        }
+    };
+};
diff --git a/modules/item/back/methods/item-shelving/specs/deleteItemShelvings.spec.js b/modules/item/back/methods/item-shelving/specs/deleteItemShelvings.spec.js
new file mode 100644
index 0000000000..a152b59815
--- /dev/null
+++ b/modules/item/back/methods/item-shelving/specs/deleteItemShelvings.spec.js
@@ -0,0 +1,21 @@
+const models = require('vn-loopback/server/server').models;
+
+describe('ItemShelving deleteItemShelvings()', () => {
+    it('should return the deleted itemShelvings', async() => {
+        const tx = await models.Order.beginTransaction({});
+
+        try {
+            const options = {transaction: tx};
+
+            const itemShelvingIds = [1, 2];
+            const result = await models.ItemShelving.deleteItemShelvings(itemShelvingIds, options);
+
+            expect(result.count).toEqual(2);
+
+            await tx.rollback();
+        } catch (e) {
+            await tx.rollback();
+            throw e;
+        }
+    });
+});
diff --git a/modules/item/back/models/item-shelving.js b/modules/item/back/models/item-shelving.js
new file mode 100644
index 0000000000..5f372a3be4
--- /dev/null
+++ b/modules/item/back/models/item-shelving.js
@@ -0,0 +1,3 @@
+module.exports = Self => {
+    require('../methods/item-shelving/deleteItemShelvings')(Self);
+};
diff --git a/modules/item/front/item-shelving/index.html b/modules/item/front/item-shelving/index.html
index 115829c8d4..fa7a705440 100644
--- a/modules/item/front/item-shelving/index.html
+++ b/modules/item/front/item-shelving/index.html
@@ -2,7 +2,7 @@
     vn-id="model"
     url="ItemShelvingPlacementSupplyStocks"
     link="{itemFk: $ctrl.$params.id}"
-    data="itemShelvingPlacementSupplyStocks"
+    data="$ctrl.itemShelvingPlacementSupplyStocks"
     auto-load="true">
 </vn-crud-model>
 <vn-card>
@@ -15,18 +15,18 @@
                 <div class="totalBox" style="text-align: center;">
                     <h6 translate>Total</h6>
                     <vn-label-value 
-                        label="Balance due" 
-                        value="{{$ctrl.balanceDueTotal | currency: 'EUR': 2}}">
+                        label="Total labels" 
+                        value="{{$ctrl.labelTotal.toFixed(2)}}">
                     </vn-label-value>
                 </div>
             </div>
             <div class="vn-pa-md">
                 <vn-button 
-                    ng-show="$ctrl.checked.length > 0"
+                    disabled="!$ctrl.checked.length"
                     ng-click="removeConfirm.show()"
+                    icon="delete"
                     vn-tooltip="Remove selected lines"
-                    vn-acl="replenisherBos"
-                    icon="delete">
+                    vn-acl="replenisherBos">
                 </vn-button>
             </div>
         </slot-actions>
@@ -68,7 +68,9 @@
                     </tr>
                 </thead>
                 <tbody>
-                    <tr ng-repeat="itemShelvingPlacementSupplyStock in itemShelvingPlacementSupplyStocks">
+                    <tr 
+                        ng-repeat="itemShelvingPlacementSupplyStock in $ctrl.itemShelvingPlacementSupplyStocks"
+                        vn-repeat-last on-last="$ctrl.calculateTotals()">
                         <td shrink>
                             <vn-check 
                                 ng-model="itemShelvingPlacementSupplyStock.checked"
@@ -93,7 +95,7 @@
                             {{::itemShelvingPlacementSupplyStock.shelving}}
                         </td>
                         <td>
-                            {{::itemShelvingPlacementSupplyStock.label}}
+                            {{(itemShelvingPlacementSupplyStock.stock / itemShelvingPlacementSupplyStock.packing).toFixed(2)}}
                         </td>
                         <td>
                             {{::itemShelvingPlacementSupplyStock.packing}}
diff --git a/modules/item/front/item-shelving/index.js b/modules/item/front/item-shelving/index.js
index 6fd8825aaf..b8584039b8 100644
--- a/modules/item/front/item-shelving/index.js
+++ b/modules/item/front/item-shelving/index.js
@@ -40,8 +40,6 @@ export default class Controller extends Section {
                 }
             ]
         };
-
-        this.getBalanceDueTotal();
     }
 
     get checked() {
@@ -49,46 +47,31 @@ export default class Controller extends Section {
         const checkedLines = [];
         for (let itemShelving of itemShelvings) {
             if (itemShelving.checked)
-                checkedLines.push(itemShelving);
+                checkedLines.push(itemShelving.itemShelvingFk);
         }
 
         return checkedLines;
     }
 
-    get label() {
+    calculateTotals() {
+        this.labelTotal = 0;
         const itemShelvings = this.$.model.data || [];
-        for (let itemShelving of itemShelvings)
-            itemShelving.label = itemShelving.stock / itemShelving.packing;
-
-        return true;
+        itemShelvings.forEach(itemShelving => {
+            const label = itemShelving.stock / itemShelving.packing;
+            this.labelTotal += label;
+        });
     }
 
-    getBalanceDueTotal() {
-        this.$http.get('Defaulters/filter')
-            .then(res => {
-                if (!res.data) return 0;
-
-                this.balanceDueTotal = res.data.reduce(
-                    (accumulator, currentValue) => {
-                        return accumulator + (currentValue['amount'] || 0);
-                    }, 0);
+    onRemove() {
+        const params = {itemShelvingIds: this.checked};
+        const query = `ItemShelvings/deleteItemShelvings`;
+        this.$http.post(query, params)
+            .then(() => {
+                this.vnApp.showSuccess(this.$t('ItemShelvings removed'));
+                this.$.model.refresh();
             });
     }
 
-    async onRemove() {
-        const params = [];
-        for (let itemShelving of this.checked)
-            params.push(itemShelving.itemShelvingFk);
-
-        for (let id of params) {
-            await this.$http.delete(`ItemShelvings/${id}`)
-                .then(() => {
-                    this.vnApp.showSuccess(this.$t('ItemShelving removed'));
-                    this.$state.reload();
-                });
-        }
-    }
-
     exprBuilder(param, value) {
         switch (param) {
         case 'parking':
diff --git a/modules/item/front/item-shelving/locale/es.yml b/modules/item/front/item-shelving/locale/es.yml
index 00b6ffe58d..006363cfa1 100644
--- a/modules/item/front/item-shelving/locale/es.yml
+++ b/modules/item/front/item-shelving/locale/es.yml
@@ -1,3 +1,5 @@
 Shelving: Matrícula
 Remove selected lines: Eliminar líneas seleccionadas
-Selected lines will be deleted: Las líneas seleccionadas serán eliminadas
\ No newline at end of file
+Selected lines will be deleted: Las líneas seleccionadas serán eliminadas
+ItemShelvings removed: Carros eliminados
+Total labels: Total etiquetas
\ No newline at end of file

From 1a38fc307f1364676adadf5feb02dc231daf10c4 Mon Sep 17 00:00:00 2001
From: vicent <vicent@verdnatura.es>
Date: Tue, 11 Oct 2022 08:42:59 +0200
Subject: [PATCH 036/151] delete: duplicated keybinding

---
 modules/shelving/front/routes.json | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/modules/shelving/front/routes.json b/modules/shelving/front/routes.json
index 0a05db9e33..09a8e389ba 100644
--- a/modules/shelving/front/routes.json
+++ b/modules/shelving/front/routes.json
@@ -13,9 +13,6 @@
             {"state": "shelving.card.log", "icon": "history"}
         ]
     },
-    "keybindings": [
-        {"key": "c", "state": "shelving.index"}
-    ],
     "routes": [
         {
             "url": "/shelving",

From bfefec397e68e86c2879bd1f89d3aacc8763a276 Mon Sep 17 00:00:00 2001
From: vicent <vicent@verdnatura.es>
Date: Tue, 11 Oct 2022 09:13:29 +0200
Subject: [PATCH 037/151] feat: add testFront

---
 .../item/front/item-shelving/index.spec.js    | 118 ++++++------------
 1 file changed, 39 insertions(+), 79 deletions(-)

diff --git a/modules/item/front/item-shelving/index.spec.js b/modules/item/front/item-shelving/index.spec.js
index 0732c68a1e..55df1c27dd 100644
--- a/modules/item/front/item-shelving/index.spec.js
+++ b/modules/item/front/item-shelving/index.spec.js
@@ -1,120 +1,80 @@
 import './index';
 import crudModel from 'core/mocks/crud-model';
 
-describe('client defaulter', () => {
-    describe('Component vnClientDefaulter', () => {
+describe('item shelving', () => {
+    describe('Component vnItemShelving', () => {
         let controller;
         let $httpBackend;
 
-        beforeEach(ngModule('client'));
+        beforeEach(ngModule('item'));
 
         beforeEach(inject(($componentController, _$httpBackend_) => {
             $httpBackend = _$httpBackend_;
-            const $element = angular.element('<vn-client-defaulter></vn-client-defaulter>');
-            controller = $componentController('vnClientDefaulter', {$element});
+            const $element = angular.element('<vn-item-shelving></vn-item-shelving>');
+            controller = $componentController('vnItemShelving', {$element});
             controller.$.model = crudModel;
             controller.$.model.data = [
-                {clientFk: 1101, amount: 125},
-                {clientFk: 1102, amount: 500},
-                {clientFk: 1103, amount: 250}
+                {itemShelvingFk: 1, packing: 10, stock: 1},
+                {itemShelvingFk: 2, packing: 12, stock: 5},
+                {itemShelvingFk: 4, packing: 20, stock: 10}
             ];
+            const modelData = controller.$.model.data;
+            modelData[0].checked = true;
+            modelData[1].checked = true;
         }));
 
         describe('checked() getter', () => {
-            it('should return the checked lines', () => {
-                const data = controller.$.model.data;
-                data[1].checked = true;
-                data[2].checked = true;
+            it('should return a the selected rows', () => {
+                const result = controller.checked;
 
-                const checkedRows = controller.checked;
-
-                const firstCheckedRow = checkedRows[0];
-                const secondCheckedRow = checkedRows[1];
-
-                expect(firstCheckedRow.clientFk).toEqual(1102);
-                expect(secondCheckedRow.clientFk).toEqual(1103);
+                expect(result).toEqual(expect.arrayContaining([1, 2]));
             });
         });
 
-        describe('chipColor()', () => {
-            it('should return undefined when the date is the present', () => {
-                let today = new Date();
-                let result = controller.chipColor(today);
+        describe('calculateTotals()', () => {
+            it('should calculate the total of labels', () => {
+                controller.calculateTotals();
 
-                expect(result).toEqual(undefined);
-            });
-
-            it('should return warning when the date is 10 days in the past', () => {
-                let pastDate = new Date();
-                pastDate = pastDate.setDate(pastDate.getDate() - 11);
-                let result = controller.chipColor(pastDate);
-
-                expect(result).toEqual('warning');
-            });
-
-            it('should return alert when the date is 20 days in the past', () => {
-                let pastDate = new Date();
-                pastDate = pastDate.setDate(pastDate.getDate() - 21);
-                let result = controller.chipColor(pastDate);
-
-                expect(result).toEqual('alert');
+                expect(controller.labelTotal).toEqual(1.0166666666666666);
             });
         });
 
-        describe('onResponse()', () => {
-            it('should return error for empty message', () => {
-                let error;
-                try {
-                    controller.onResponse();
-                } catch (e) {
-                    error = e;
-                }
+        describe('onRemove()', () => {
+            it('shoud remove the selected lines', () => {
+                jest.spyOn(controller.$.model, 'refresh');
+                const expectedParams = {itemShelvingIds: [1, 2]};
 
-                expect(error).toBeDefined();
-                expect(error.message).toBe(`The message can't be empty`);
-            });
-
-            it('should return saved message', () => {
-                const data = controller.$.model.data;
-                data[1].checked = true;
-                controller.defaulter = {observation: 'My new observation'};
-
-                const params = [{text: controller.defaulter.observation, clientFk: data[1].clientFk}];
-
-                jest.spyOn(controller.vnApp, 'showMessage');
-                $httpBackend.expect('GET', `Defaulters/filter`).respond(200);
-                $httpBackend.expect('POST', `ClientObservations`, params).respond(200, params);
-
-                controller.onResponse();
+                $httpBackend.expectPOST('ItemShelvings/deleteItemShelvings', expectedParams).respond(200);
+                controller.onRemove();
                 $httpBackend.flush();
 
-                expect(controller.vnApp.showMessage).toHaveBeenCalledWith('Observation saved!');
+                expect(controller.$.model.refresh).toHaveBeenCalled();
             });
         });
 
         describe('exprBuilder()', () => {
-            it('should search by sales person', () => {
-                const expr = controller.exprBuilder('salesPersonFk', '5');
+            it('should search by parking', () => {
+                const expr = controller.exprBuilder('parking', '700-01');
 
-                expect(expr).toEqual({'d.salesPersonFk': '5'});
+                expect(expr).toEqual({'parking': '700-01'});
             });
 
-            it('should search by client', () => {
-                const expr = controller.exprBuilder('clientFk', '5');
+            it('should search by shelving', () => {
+                const expr = controller.exprBuilder('shelving', 'AAA');
 
-                expect(expr).toEqual({'d.clientFk': '5'});
+                expect(expr).toEqual({'shelving': 'AAA'});
             });
-        });
 
-        describe('getBalanceDueTotal()', () => {
-            it('should return balance due total', () => {
-                const defaulters = controller.$.model.data;
-                $httpBackend.when('GET', `Defaulters/filter`).respond(defaulters);
+            it('should search by label', () => {
+                const expr = controller.exprBuilder('label', 0.17);
 
-                controller.getBalanceDueTotal();
-                $httpBackend.flush();
+                expect(expr).toEqual({'label': 0.17});
+            });
 
-                expect(controller.balanceDueTotal).toEqual(875);
+            it('should search by packing', () => {
+                const expr = controller.exprBuilder('packing', 10);
+
+                expect(expr).toEqual({'packing': 10});
             });
         });
     });

From 012cd68c8988e411818dd57caf9f132c16881d44 Mon Sep 17 00:00:00 2001
From: Pau Navarro <pau@verdnatura.es>
Date: Tue, 11 Oct 2022 11:43:01 +0200
Subject: [PATCH 038/151] Added menu to create a new supplier, not working

---
 modules/supplier/back/methods/supplier/new.js | 28 +++++++++++++++
 modules/supplier/back/models/supplier.js      |  1 +
 modules/supplier/front/create/index.html      | 36 +++++++++++++++++++
 modules/supplier/front/create/index.js        | 25 +++++++++++++
 modules/supplier/front/index.js               |  1 +
 modules/supplier/front/index/index.html       |  7 +++-
 modules/supplier/front/index/index.js         |  5 +++
 modules/supplier/front/index/locale/es.yml    |  3 +-
 modules/supplier/front/routes.json            |  8 ++++-
 9 files changed, 111 insertions(+), 3 deletions(-)
 create mode 100644 modules/supplier/back/methods/supplier/new.js
 create mode 100644 modules/supplier/front/create/index.html
 create mode 100644 modules/supplier/front/create/index.js

diff --git a/modules/supplier/back/methods/supplier/new.js b/modules/supplier/back/methods/supplier/new.js
new file mode 100644
index 0000000000..9fb8075327
--- /dev/null
+++ b/modules/supplier/back/methods/supplier/new.js
@@ -0,0 +1,28 @@
+/* eslint-disable no-console */
+// eslint-disable-next-line no-unused-vars
+let UserError = require('vn-loopback/util/user-error');
+
+module.exports = Self => {
+    Self.remoteMethod('new', {
+        description: 'returns the created item',
+        accessType: 'WRITE',
+        accepts: [{
+            arg: 'params',
+            type: 'object',
+            http: {source: 'body'}
+        }],
+        returns: {
+            type: 'number',
+            root: true
+        },
+        http: {
+            path: `/new`,
+            verb: 'POST'
+        }
+    });
+
+    Self.new = async(params, options) => {
+        console.log(params);
+        console.log(options);
+    };
+};
diff --git a/modules/supplier/back/models/supplier.js b/modules/supplier/back/models/supplier.js
index c9af7b2977..a2831845a3 100644
--- a/modules/supplier/back/models/supplier.js
+++ b/modules/supplier/back/models/supplier.js
@@ -10,6 +10,7 @@ module.exports = Self => {
     require('../methods/supplier/freeAgencies')(Self);
     require('../methods/supplier/campaignMetricsPdf')(Self);
     require('../methods/supplier/campaignMetricsEmail')(Self);
+    require('../methods/supplier/new')(Self);
 
     Self.validatesPresenceOf('name', {
         message: 'The social name cannot be empty'
diff --git a/modules/supplier/front/create/index.html b/modules/supplier/front/create/index.html
new file mode 100644
index 0000000000..71fe3b4888
--- /dev/null
+++ b/modules/supplier/front/create/index.html
@@ -0,0 +1,36 @@
+<vn-watcher
+    vn-id="watcher"
+    url="supplier/new"
+    data="$ctrl.supplier"
+    insert-mode="true"
+    form="form">
+</vn-watcher>
+<vn-crud-model
+    auto-load="true"
+    url="Origins"
+    data="originsData"
+    order="name"
+    vn-id="origin-model">
+</vn-crud-model>
+<form name="form" ng-submit="$ctrl.onSubmit()" class="vn-w-md">
+    <vn-card class="vn-pa-lg">
+        <vn-horizontal>
+            <vn-textfield
+                label="Supplier name" 
+                ng-model="$ctrl.supplier.name" 
+                vn-focus>
+            </vn-textfield>
+        </vn-horizontal>
+    </vn-card>
+    <vn-button-bar>
+        <vn-submit
+            disabled="!watcher.dataChanged()"
+            label="Create">
+        </vn-submit>
+        <vn-button
+            class="cancel"
+            label="Cancel"
+            ui-sref="supplier.index">
+        </vn-button>
+    </vn-button-bar>
+</form>
diff --git a/modules/supplier/front/create/index.js b/modules/supplier/front/create/index.js
new file mode 100644
index 0000000000..8708aacd67
--- /dev/null
+++ b/modules/supplier/front/create/index.js
@@ -0,0 +1,25 @@
+/* eslint-disable no-console */
+import ngModule from '../module';
+import Section from 'salix/components/section';
+
+class Controller extends Section {
+    constructor($element, $) {
+        super($element, $);
+        console.log($);
+    }
+
+    onSubmit() {
+        this.$.watcher.submit().then(
+            console.log('abc'),
+            json => this.$state.go('item.card.basicData', {id: json.data.id})
+
+        );
+    }
+}
+
+Controller.$inject = ['$element', '$scope'];
+
+ngModule.vnComponent('vnSupplierCreate', {
+    template: require('./index.html'),
+    controller: Controller
+});
diff --git a/modules/supplier/front/index.js b/modules/supplier/front/index.js
index ba27688547..9216d0781f 100644
--- a/modules/supplier/front/index.js
+++ b/modules/supplier/front/index.js
@@ -20,3 +20,4 @@ import './address/create';
 import './address/edit';
 import './agency-term/index';
 import './agency-term/create';
+import './create/index';
diff --git a/modules/supplier/front/index/index.html b/modules/supplier/front/index/index.html
index 87e822eea6..5d29ba0ebf 100644
--- a/modules/supplier/front/index/index.html
+++ b/modules/supplier/front/index/index.html
@@ -58,4 +58,9 @@
     <vn-supplier-summary
         supplier="$ctrl.supplierSelected">
     </vn-supplier-summary>
-</vn-popup>
\ No newline at end of file
+</vn-popup>
+<!--vn-float-button vn-acl="administrative" icon="add" ng-click="$ctrl.test()" fixed-bottom-right vn-tooltip="New supplier"></vn-float-button>
+-->
+<a vn-acl="administrative" ui-sref="supplier.create" vn-tooltip="New supplier" vn-bind="+" fixed-bottom-right>
+    <vn-float-button icon="add"></vn-float-button>
+</a>
\ No newline at end of file
diff --git a/modules/supplier/front/index/index.js b/modules/supplier/front/index/index.js
index 77b2e83478..b9b43321d5 100644
--- a/modules/supplier/front/index/index.js
+++ b/modules/supplier/front/index/index.js
@@ -10,6 +10,11 @@ export default class Controller extends Section {
         this.supplierSelected = supplier;
         this.$.dialogSummarySupplier.show();
     }
+
+    test() {
+        // eslint-disable-next-line no-console
+        console.log('Creating new supplier');
+    }
 }
 
 ngModule.vnComponent('vnSupplierIndex', {
diff --git a/modules/supplier/front/index/locale/es.yml b/modules/supplier/front/index/locale/es.yml
index ad8a4f0bb7..ce06f462cd 100644
--- a/modules/supplier/front/index/locale/es.yml
+++ b/modules/supplier/front/index/locale/es.yml
@@ -2,4 +2,5 @@ Payment deadline: Plazo de pago
 Pay day: Dia de pago
 Account: Cuenta
 Pay method: Metodo de pago
-Tax number: Nif
\ No newline at end of file
+Tax number: Nif
+New supplier: Nuevo proveedor
\ No newline at end of file
diff --git a/modules/supplier/front/routes.json b/modules/supplier/front/routes.json
index 61420b40d1..03efea0f3d 100644
--- a/modules/supplier/front/routes.json
+++ b/modules/supplier/front/routes.json
@@ -30,7 +30,13 @@
             "abstract": true,
             "component": "vn-supplier",
             "description": "Suppliers"
-        }, 
+        },
+        {
+            "url": "/create",
+            "state": "supplier.create",
+            "component": "vn-supplier-create",
+            "description": "New supplier"
+        },
         {
             "url": "/index?q",
             "state": "supplier.index",

From 24cb8e00bbe7200a2d218162bcbb681a187b919b Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Tue, 11 Oct 2022 13:20:25 +0200
Subject: [PATCH 039/151] creates notification sql in changes

---
 .../10491-august/00-notificationProc.sql      | 28 ++++++++
 .../10491-august/00-notificationTables.sql    | 63 +++++++++++++++++
 db/changes/10491-august/delete.keep           |  0
 db/dump/structure.sql                         | 68 -------------------
 4 files changed, 91 insertions(+), 68 deletions(-)
 create mode 100644 db/changes/10491-august/00-notificationProc.sql
 create mode 100644 db/changes/10491-august/00-notificationTables.sql
 delete mode 100644 db/changes/10491-august/delete.keep

diff --git a/db/changes/10491-august/00-notificationProc.sql b/db/changes/10491-august/00-notificationProc.sql
new file mode 100644
index 0000000000..475b2e3892
--- /dev/null
+++ b/db/changes/10491-august/00-notificationProc.sql
@@ -0,0 +1,28 @@
+DROP FUNCTION IF EXISTS `util`.`notification_send`;
+DELIMITER $$
+CREATE DEFINER=`root`@`localhost` FUNCTION `util`.`notification_send`(vNotificationName VARCHAR(255), vParams TEXT, vAuthorFk INT)
+	RETURNS INT
+    MODIFIES SQL DATA
+BEGIN
+/**
+ * Sends a notification.
+ *
+ * @param vNotificationName The notification name
+ * @param vParams The notification parameters formatted as JSON
+ * @param vAuthorFk The notification author or %NULL if there is no author
+ * @return The notification id
+ */
+    DECLARE vNotificationFk INT;
+
+	SELECT id INTO vNotificationFk
+		FROM `notification`
+		WHERE `name` = vNotificationName;
+
+	INSERT INTO notificationQueue
+		SET notificationFk = vNotificationFk,
+			params = vParams,
+			authorFk = vAuthorFk;
+
+	RETURN LAST_INSERT_ID();
+END$$
+DELIMITER ;
diff --git a/db/changes/10491-august/00-notificationTables.sql b/db/changes/10491-august/00-notificationTables.sql
new file mode 100644
index 0000000000..d5fcf00b20
--- /dev/null
+++ b/db/changes/10491-august/00-notificationTables.sql
@@ -0,0 +1,63 @@
+USE util;
+
+CREATE TABLE notification(
+    id INT PRIMARY KEY,
+    `name` VARCHAR(255) UNIQUE,
+    `description` VARCHAR(255)
+);
+
+CREATE TABLE notificationAcl(
+    notificationFk INT, -- FK notification.id
+    roleFk INT(10) unsigned, -- FK account.role.id
+    PRIMARY KEY(notificationFk, roleFk)
+);
+
+ALTER TABLE `util`.`notificationAcl` ADD CONSTRAINT `notificationAcl_ibfk_1` FOREIGN KEY (`notificationFk`) REFERENCES `util`.`notification` (`id`)
+  ON DELETE CASCADE
+  ON UPDATE CASCADE;
+
+ALTER TABLE `util`.`notificationAcl` ADD CONSTRAINT `notificationAcl_ibfk_2` FOREIGN KEY (`roleFk`) REFERENCES `account`.`role`(`id`)
+  ON DELETE RESTRICT
+  ON UPDATE CASCADE;
+
+CREATE TABLE notificationSubscription(
+    notificationFk INT, -- FK notification.id
+    userFk INT(10) unsigned, -- FK account.user.id
+    PRIMARY KEY(notificationFk, userFk)
+);
+
+ALTER TABLE `util`.`notificationSubscription` ADD CONSTRAINT `notificationSubscription_ibfk_1` FOREIGN KEY (`notificationFk`) REFERENCES `util`.`notification` (`id`)
+  ON DELETE CASCADE
+  ON UPDATE CASCADE;
+
+ALTER TABLE `util`.`notificationSubscription` ADD CONSTRAINT `notificationSubscription_ibfk_2` FOREIGN KEY (`userFk`) REFERENCES  `account`.`user`(`id`)
+  ON DELETE CASCADE
+  ON UPDATE CASCADE;
+
+CREATE TABLE notificationQueue(
+    id INT PRIMARY KEY AUTO_INCREMENT,
+    notificationFk VARCHAR(255), -- FK notification.name
+    params TEXT, -- JSON
+    authorFk INT(10) unsigned NULL, -- FK account.user.id
+    `status` ENUM('pending', 'sent', 'error') NOT NULL DEFAULT 'pending',
+    created DATETIME DEFAULT CURRENT_TIMESTAMP,
+    INDEX(notificationFk),
+    INDEX(authorFk),
+    INDEX(status)
+);
+
+ALTER TABLE `util`.`notificationQueue` ADD CONSTRAINT `nnotificationQueue_ibfk_1` FOREIGN KEY (`notificationFk`) REFERENCES `util`.`notification` (`name`)
+  ON DELETE CASCADE
+  ON UPDATE CASCADE;
+
+ALTER TABLE `util`.`notificationQueue` ADD CONSTRAINT `notificationQueue_ibfk_2` FOREIGN KEY (`authorFk`) REFERENCES `account`.`user`(`id`)
+  ON DELETE CASCADE
+  ON UPDATE CASCADE;
+
+CREATE TABLE notificationConfig(
+    id INT PRIMARY KEY AUTO_INCREMENT,
+    cleanDays MEDIUMINT
+);
+
+INSERT INTO notificationConfig
+    SET cleanDays = 90;
diff --git a/db/changes/10491-august/delete.keep b/db/changes/10491-august/delete.keep
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/db/dump/structure.sql b/db/dump/structure.sql
index 184c7490f3..402c8e695b 100644
--- a/db/dump/structure.sql
+++ b/db/dump/structure.sql
@@ -20369,74 +20369,6 @@ CREATE DATABASE /*!32312 IF NOT EXISTS*/ `util` /*!40100 DEFAULT CHARACTER SET u
 
 USE `util`;
 
-CREATE TABLE notification(
-	id INT PRIMARY KEY,
-	`name` VARCHAR(255) UNIQUE,
-	`description` VARCHAR(255)
-);
-
-CREATE TABLE notificationAcl (
-	notificationFk INT(11),
-	roleFk INT(10) unsigned,
-	PRIMARY KEY(notificationFk, roleFk),
-	CONSTRAINT `notificationAcl_ibfk_1` FOREIGN KEY (`notificationFk`) REFERENCES `notification` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
-	CONSTRAINT `notificationAcl_ibfk_2` FOREIGN KEY (`roleFk`) REFERENCES `account`.`role` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
-);
-
-CREATE TABLE notificationSubscription(
-	notificationFk INT,
-	userFk INT(10) unsigned,
-	PRIMARY KEY(notificationFk, userFk),
-	CONSTRAINT `notificationSubscription_ibfk_1` FOREIGN KEY (`notificationFk`) REFERENCES `notification` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
-	CONSTRAINT `notificationSubscription_ibfk_2` FOREIGN KEY (`userFk`) REFERENCES `account`.`user` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
-);
-
-CREATE TABLE notificationQueue(
-	id INT PRIMARY KEY AUTO_INCREMENT,
-	notificationFk VARCHAR(255),
-	params TEXT,
-	authorFk INT(10) unsigned NULL,
-	`status` ENUM('pending', 'sent', 'error') NOT NULL DEFAULT 'pending',
-	created DATETIME DEFAULT CURRENT_TIMESTAMP,
-	INDEX(notificationFk),
-	INDEX(authorFk),
-	INDEX(status),
-	CONSTRAINT `notificationQueue_ibfk_1` FOREIGN KEY (`notificationFk`) REFERENCES `notification` (`name`) ON DELETE CASCADE ON UPDATE CASCADE,
-	CONSTRAINT `notificationQueue_ibfk_2` FOREIGN KEY (`authorFk`) REFERENCES `account`.`user` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
-);
-
-CREATE TABLE notificationConfig(
-	id INT PRIMARY KEY AUTO_INCREMENT,
-	cleanDays MEDIUMINT
-);
-
-DROP FUNCTION IF EXISTS util.notification_send;
-DELIMITER $$
-CREATE FUNCTION util.notification_send(vNotificationName VARCHAR(255), vParams TEXT, vAuthorFk INT)
-	RETURNS INT
-BEGIN
-/**
- * Sends a notification.
- *
- * @param vNotificationName The notification name
- * @param vParams The notification parameters formatted as JSON
- * @param vAuthorFk The notification author or %NULL if there is no author
- * @return The notification id
- */
-	DECLARE vNotificationFk INT;
-
-	SELECT id INTO vNotificationFk
-		FROM `notification`
-		WHERE `name` = vNotificationName;
-
-	INSERT INTO notificationQueue
-		SET notificationFk = vNotificationFk,
-			params = vParams,
-			authorFk = vAuthorFk;
-
-	RETURN LAST_INSERT_ID();
-END$$
-DELIMITER ;
 --
 -- Table structure for table `binlogQueue`
 --

From e81c39d8dce57d74fd9a5af59885d108210b18f3 Mon Sep 17 00:00:00 2001
From: joan <joan@verdnatura.es>
Date: Thu, 13 Oct 2022 09:30:31 +0200
Subject: [PATCH 040/151] Send delivery note to refund tickets

---
 .../10491-august/ticket_closeByTicket.sql     | 31 +++++++++++++++++++
 .../ticket/back/methods/ticket/closeAll.js    |  2 +-
 2 files changed, 32 insertions(+), 1 deletion(-)
 create mode 100644 db/changes/10491-august/ticket_closeByTicket.sql

diff --git a/db/changes/10491-august/ticket_closeByTicket.sql b/db/changes/10491-august/ticket_closeByTicket.sql
new file mode 100644
index 0000000000..25b04f6296
--- /dev/null
+++ b/db/changes/10491-august/ticket_closeByTicket.sql
@@ -0,0 +1,31 @@
+drop procedure `vn`.`ticket_closeByTicket`;
+
+create
+    definer = root@localhost procedure `vn`.`ticket_closeByTicket`(IN vTicketFk int)
+BEGIN
+
+/**
+ * Inserta el ticket en la tabla temporal
+ * para ser cerrado.
+ *
+ * @param vTicketFk Id del ticket
+ */
+
+	DROP TEMPORARY TABLE IF EXISTS tmp.ticket_close;
+	CREATE TEMPORARY TABLE tmp.ticket_close ENGINE = MEMORY (
+		SELECT 
+			t.id AS ticketFk
+		FROM ticket t
+            JOIN agencyMode am ON am.id = t.agencyModeFk
+			LEFT JOIN ticketState ts ON ts.ticketFk = t.id
+		    JOIN alertLevel al ON al.id = ts.alertLevel
+		WHERE al.code = 'PACKED' OR (am.code = 'refund' AND al.code != 'delivered')
+            AND t.id = vTicketFk
+			AND t.refFk IS NULL
+		GROUP BY t.id);
+        
+	CALL ticket_close();
+
+    DROP TEMPORARY TABLE tmp.ticket_close;
+END;
+
diff --git a/modules/ticket/back/methods/ticket/closeAll.js b/modules/ticket/back/methods/ticket/closeAll.js
index 5e81e38274..327278c2b0 100644
--- a/modules/ticket/back/methods/ticket/closeAll.js
+++ b/modules/ticket/back/methods/ticket/closeAll.js
@@ -52,7 +52,7 @@ module.exports = Self => {
                 JOIN province p ON p.id = c.provinceFk
                 JOIN country co ON co.id = p.countryFk
                 LEFT JOIN account.emailUser eu ON eu.userFk = c.salesPersonFk
-            WHERE al.code = 'PACKED'
+            WHERE al.code = 'PACKED' OR (am.code = 'refund' AND al.code != 'delivered')
                 AND DATE(t.shipped) BETWEEN DATE_ADD(?, INTERVAL -2 DAY) 
                     AND util.dayEnd(?)
                 AND t.refFk IS NULL

From 248572feb438836e32d3b971ea83be1f1b19e03a Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Fri, 14 Oct 2022 07:40:11 +0200
Subject: [PATCH 041/151] use variable

---
 front/core/components/searchbar/searchbar.js | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/front/core/components/searchbar/searchbar.js b/front/core/components/searchbar/searchbar.js
index 57a77d9801..dff4836dbd 100644
--- a/front/core/components/searchbar/searchbar.js
+++ b/front/core/components/searchbar/searchbar.js
@@ -303,7 +303,9 @@ export default class Searchbar extends Component {
         }
 
         this.tableQ = null;
-        if (this.$params.q && Object.keys(JSON.parse(this.$params.q)).length) {
+
+        const hasParams = this.$params.q && Object.keys(JSON.parse(this.$params.q)).length;
+        if (hasParams) {
             const stateFilter = JSON.parse(this.$params.q);
             for (let param in stateFilter) {
                 if (param != 'tableQ' && param != 'orderQ')

From c637f2c8798989b1684ec16f79d33d7e654ea791 Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Fri, 14 Oct 2022 13:22:53 +0200
Subject: [PATCH 042/151] feat(send): use vn-print libary and adapt test

---
 back/methods/notification/send.js             | 59 ++++++++++---------
 back/methods/notification/specs/send.spec.js  |  2 +-
 .../10491-august/00-notificationTables.sql    | 14 ++---
 db/dump/fixtures.sql                          |  8 ++-
 4 files changed, 44 insertions(+), 39 deletions(-)

diff --git a/back/methods/notification/send.js b/back/methods/notification/send.js
index b56d9d6c03..5ae7e748b2 100644
--- a/back/methods/notification/send.js
+++ b/back/methods/notification/send.js
@@ -1,4 +1,5 @@
-const axios = require('axios');
+const {Email} = require('vn-print');
+const UserError = require('vn-loopback/util/user-error');
 
 module.exports = Self => {
     Self.remoteMethod('send', {
@@ -15,27 +16,18 @@ module.exports = Self => {
     });
 
     Self.send = async options => {
-        // const headers = ctx.req.headers;
-        // const origin = headers.origin || 'http://' + headers.host;
-        // const auth = ctx.req.accessToken;
-        // console.log(origin);
+        if (process.env.NODE_ENV == 'test')
+            throw new UserError(`Action not allowed on the test environment`);
 
         const models = Self.app.models;
-        const status = 'pending';
+        const findStatus = 'pending';
 
         const myOptions = {};
-        let tx;
-
         if (typeof options == 'object')
             Object.assign(myOptions, options);
 
-        if (!myOptions.transaction) {
-            tx = await Self.beginTransaction({});
-            myOptions.transaction = tx;
-        }
-
         const notificationQueue = await models.NotificationQueue.find({
-            where: {status: status},
+            where: {status: findStatus},
             include: [
                 {
                     relation: 'notification',
@@ -46,7 +38,7 @@ module.exports = Self => {
                                 include: {
                                     relation: 'user',
                                     scope: {
-                                        fields: ['name']
+                                        fields: ['name', 'email', 'lang']
                                     }
                                 }
                             }
@@ -59,24 +51,33 @@ module.exports = Self => {
 
         const statusSent = 'sent';
         const statusError = 'error';
+
         for (const queue of notificationQueue) {
-            // console.log(queue);
-            // console.log(origin);
-            // console.log(auth);
-            // console.log(queue.notification().name);
-            // console.log(queue.params);
+            const queueName = queue.notification().name;
+            const queueParams = JSON.parse(queue.params);
 
-            // const queueParams = Object.assign({}, JSON.parse(queue.params));
-            // queueParams.authorization = auth.id;
+            for (const notificationUser of queue.notification().subscription()) {
+                try {
+                    const sendParams = {
+                        recipient: notificationUser.user().email,
+                        lang: notificationUser.user().lang
+                    };
 
-            try {
-                // await print axios.get(`print`, queueParams)
-                await queue.updateAttribute('status', statusSent);
-            } catch (error) {
-                await queue.updateAttribute('status', statusError);
+                    if (notificationUser.userFk == queue.authorFk) {
+                        await queue.updateAttribute('status', statusSent);
+                        continue;
+                    }
+
+                    const newParams = Object.assign({}, queueParams, sendParams);
+                    const email = new Email(queueName, newParams);
+
+                    await email.send();
+
+                    await queue.updateAttribute('status', statusSent);
+                } catch (error) {
+                    await queue.updateAttribute('status', statusError);
+                }
             }
         }
-
-        return notificationQueue;
     };
 };
diff --git a/back/methods/notification/specs/send.spec.js b/back/methods/notification/specs/send.spec.js
index 015d1cb4d0..f0b186e065 100644
--- a/back/methods/notification/specs/send.spec.js
+++ b/back/methods/notification/specs/send.spec.js
@@ -27,7 +27,7 @@ describe('Notification Send()', () => {
             throw e;
         }
 
-        expect(before.length).toEqual(1);
+        expect(before.length).toEqual(3);
         expect(after.length).toEqual(0);
     });
 });
diff --git a/db/changes/10491-august/00-notificationTables.sql b/db/changes/10491-august/00-notificationTables.sql
index d5fcf00b20..2db7d9874c 100644
--- a/db/changes/10491-august/00-notificationTables.sql
+++ b/db/changes/10491-august/00-notificationTables.sql
@@ -7,8 +7,8 @@ CREATE TABLE notification(
 );
 
 CREATE TABLE notificationAcl(
-    notificationFk INT, -- FK notification.id
-    roleFk INT(10) unsigned, -- FK account.role.id
+    notificationFk INT,
+    roleFk INT(10) unsigned,
     PRIMARY KEY(notificationFk, roleFk)
 );
 
@@ -21,8 +21,8 @@ ALTER TABLE `util`.`notificationAcl` ADD CONSTRAINT `notificationAcl_ibfk_2` FOR
   ON UPDATE CASCADE;
 
 CREATE TABLE notificationSubscription(
-    notificationFk INT, -- FK notification.id
-    userFk INT(10) unsigned, -- FK account.user.id
+    notificationFk INT,
+    userFk INT(10) unsigned,
     PRIMARY KEY(notificationFk, userFk)
 );
 
@@ -36,9 +36,9 @@ ALTER TABLE `util`.`notificationSubscription` ADD CONSTRAINT `notificationSubscr
 
 CREATE TABLE notificationQueue(
     id INT PRIMARY KEY AUTO_INCREMENT,
-    notificationFk VARCHAR(255), -- FK notification.name
-    params TEXT, -- JSON
-    authorFk INT(10) unsigned NULL, -- FK account.user.id
+    notificationFk VARCHAR(255),
+    params JSON,
+    authorFk INT(10) unsigned NULL,
     `status` ENUM('pending', 'sent', 'error') NOT NULL DEFAULT 'pending',
     created DATETIME DEFAULT CURRENT_TIMESTAMP,
     INDEX(notificationFk),
diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql
index cd2a1c6dd4..9d873f2c6a 100644
--- a/db/dump/fixtures.sql
+++ b/db/dump/fixtures.sql
@@ -2653,7 +2653,7 @@ INSERT INTO `util`.`notificationConfig`
 
 INSERT INTO `util`.`notification` (`id`, `name`, `description`)
     VALUES
-        (1, 'invoice', 'notification fixture one');
+        (1, 'print-email', 'notification fixture one');
 
 INSERT INTO `util`.`notificationAcl` (`notificationFk`, `roleFk`)
     VALUES
@@ -2661,11 +2661,15 @@ INSERT INTO `util`.`notificationAcl` (`notificationFk`, `roleFk`)
 
 INSERT INTO `util`.`notificationQueue` (`id`, `notificationFk`, `params`, `authorFk`, `status`, `created`)
     VALUES
-        (1, 'invoice', '{"invoiceId": 1}', 9, 'pending', util.VN_CURDATE());
+        (1, 'print-email', '{"id": "1"}', 9, 'pending', util.VN_CURDATE()),
+        (2, 'print-email', '{"id": "2"}', null, 'pending', util.VN_CURDATE()),
+        (3, 'print-email', null, null, 'pending', util.VN_CURDATE());
 
 INSERT INTO `util`.`notificationSubscription` (`notificationFk`, `userFk`)
     VALUES
+        (1, 1109),
         (1, 1110);
+
 INSERT INTO `vn`.`routeConfig` (`id`, `defaultWorkCenterFk`)
     VALUES
         (1, 9);

From 2455a11c26744ac45f81b869b618af686d868157 Mon Sep 17 00:00:00 2001
From: vicent <vicent@verdnatura.es>
Date: Fri, 14 Oct 2022 14:29:21 +0200
Subject: [PATCH 043/151] feat: changeMultipleDiscount uses the same popover
 than changeDiscount

---
 modules/ticket/front/sale/index.html | 30 ++----------------------
 modules/ticket/front/sale/index.js   | 34 ++++++++++++----------------
 2 files changed, 17 insertions(+), 47 deletions(-)

diff --git a/modules/ticket/front/sale/index.html b/modules/ticket/front/sale/index.html
index 42eb10cb06..112476c301 100644
--- a/modules/ticket/front/sale/index.html
+++ b/modules/ticket/front/sale/index.html
@@ -300,7 +300,7 @@
                         ng-model="$ctrl.manaCode">
                     </vn-radio>
                 </vn-vertical>
-                <div class="simulator">
+                <div class="simulator" ng-show="$ctrl.edit.sale">
                     <p class="simulatorTitle" translate>New price</p>
                     <p>
                         <strong>{{$ctrl.getNewPrice() | currency: 'EUR': 2}}</strong>
@@ -321,32 +321,6 @@
     </div>
 </vn-popover>
 
-<!-- Multiple discount dialog -->
-<vn-dialog vn-id="editDiscountDialog"
-    on-open="$ctrl.getMana()"
-    message="Edit discount">
-    <tpl-body>
-        <vn-spinner class="vn-pa-xs"
-            ng-if="$ctrl.edit.mana == null"
-            enable="true">
-        </vn-spinner>
-        <div ng-if="$ctrl.edit.mana != null">
-            <div class="vn-pa-md">
-                <vn-input-number vn-focus
-                    label="Discount"
-                    ng-model="$ctrl.edit.discount"
-                    on-change="$ctrl.changeMultipleDiscount()"
-                    clear-disabled="true"
-                    suffix="%">
-                </vn-input-number>
-            </div>
-            <section class="header vn-pa-md">
-                <span>Mana: <strong>{{::$ctrl.edit.mana | currency: 'EUR': 0}}</strong></span>
-            </section>
-        </div>
-    </tpl-body>
-</vn-dialog>
-
 <!-- Transfer Popover -->
 <vn-popover vn-id="transfer">
     <div class="vn-pa-lg transfer">
@@ -490,7 +464,7 @@
     </vn-item>
     <vn-item translate
         name="discount"
-        ng-click="$ctrl.showEditDiscountDialog($event)">
+        ng-click="$ctrl.showEditDiscountPopover($event, sale)">
         Update discount
     </vn-item>
     <vn-item translate
diff --git a/modules/ticket/front/sale/index.js b/modules/ticket/front/sale/index.js
index 2724bb97d9..714baa126c 100644
--- a/modules/ticket/front/sale/index.js
+++ b/modules/ticket/front/sale/index.js
@@ -243,26 +243,21 @@ class Controller extends Section {
 
     showEditDiscountPopover(event, sale) {
         if (this.isLocked) return;
-
-        this.edit = {
-            discount: sale.discount,
-            sale: sale
-        };
+        if (sale) {
+            this.edit = {
+                discount: sale.discount,
+                sale: sale
+            };
+        } else {
+            this.edit = {
+                discount: null,
+                sales: this.selectedValidSales()
+            };
+        }
 
         this.$.editDiscount.show(event);
     }
 
-    showEditDiscountDialog(event) {
-        if (this.isLocked) return;
-
-        this.edit = {
-            discount: null,
-            sales: this.selectedValidSales()
-        };
-
-        this.$.editDiscountDialog.show(event);
-    }
-
     changeDiscount() {
         const sale = this.edit.sale;
         const newDiscount = this.edit.discount;
@@ -282,7 +277,7 @@ class Controller extends Section {
         if (newDiscount != null && hasChanges)
             this.updateDiscount(sales);
 
-        this.$.editDiscountDialog.hide();
+        this.$.editDiscount.hide();
     }
 
     updateDiscount(sales) {
@@ -303,7 +298,7 @@ class Controller extends Section {
     }
 
     getNewPrice() {
-        if (this.edit) {
+        if (this.edit.sale) {
             const sale = this.edit.sale;
             let newDiscount = sale.discount;
             let newPrice = this.edit.price || sale.price;
@@ -505,7 +500,8 @@ class Controller extends Section {
     }
 
     save() {
-        this.changeDiscount();
+        if (this.edit.sale) this.changeDiscount();
+        if (this.edit.sales) this.changeMultipleDiscount();
     }
 
     cancel() {

From 86b7e9cabe7b214ef019062b13cbf5299b91fd7c Mon Sep 17 00:00:00 2001
From: vicent <vicent@verdnatura.es>
Date: Fri, 14 Oct 2022 14:30:37 +0200
Subject: [PATCH 044/151] fix: only can exists 'mana' or 'manaClaim' discount.
 Never both

---
 .../back/methods/ticket/updateDiscount.js     | 41 +++++++++++++++++--
 1 file changed, 37 insertions(+), 4 deletions(-)

diff --git a/modules/ticket/back/methods/ticket/updateDiscount.js b/modules/ticket/back/methods/ticket/updateDiscount.js
index b1291a45bf..99daac5127 100644
--- a/modules/ticket/back/methods/ticket/updateDiscount.js
+++ b/modules/ticket/back/methods/ticket/updateDiscount.js
@@ -115,10 +115,43 @@ module.exports = Self => {
             for (let sale of sales) {
                 const oldDiscount = sale.discount;
                 const value = ((-sale.price * newDiscount) / 100);
-                const newComponent = models.SaleComponent.upsert({
-                    saleFk: sale.id,
-                    value: value,
-                    componentFk: componentId}, myOptions);
+
+                const manaComponent = await models.Component.findOne({
+                    where: {code: 'mana'}
+                }, myOptions);
+
+                const manaClaimComponent = await models.Component.findOne({
+                    where: {code: 'manaClaim'}
+                }, myOptions);
+
+                const oldComponent = await models.SaleComponent.find({
+                    where: {
+                        and: [
+                            {saleFk: sale.id},
+                            {componentFk: {inq: [manaComponent.id, manaClaimComponent.id]}}
+                        ]
+                    }
+                }, myOptions);
+
+                let newComponent;
+                if (oldComponent) {
+                    const filter = {
+                        saleFk: sale.id,
+                        componentFk: oldComponent.componentFk
+                    };
+                    await models.SaleComponent.destroyAll(filter, myOptions);
+
+                    newComponent = models.SaleComponent.create({
+                        saleFk: sale.id,
+                        value: value,
+                        componentFk: componentId
+                    }, myOptions);
+                } else {
+                    newComponent = models.SaleComponent.create({
+                        saleFk: sale.id,
+                        value: value,
+                        componentFk: componentId}, myOptions);
+                }
 
                 const updatedSale = sale.updateAttribute('discount', newDiscount, myOptions);
 

From 40075e7e21633569a5c7eb29d5f60fbedbb4a9c1 Mon Sep 17 00:00:00 2001
From: vicent <vicent@verdnatura.es>
Date: Fri, 14 Oct 2022 14:38:47 +0200
Subject: [PATCH 045/151] fix: testFront

---
 modules/ticket/front/sale/index.js      | 1 -
 modules/ticket/front/sale/index.spec.js | 8 ++++----
 2 files changed, 4 insertions(+), 5 deletions(-)

diff --git a/modules/ticket/front/sale/index.js b/modules/ticket/front/sale/index.js
index 714baa126c..0d1d28b0e5 100644
--- a/modules/ticket/front/sale/index.js
+++ b/modules/ticket/front/sale/index.js
@@ -273,7 +273,6 @@ class Controller extends Section {
         const hasChanges = sales.some(sale => {
             return sale.discount != newDiscount;
         });
-
         if (newDiscount != null && hasChanges)
             this.updateDiscount(sales);
 
diff --git a/modules/ticket/front/sale/index.spec.js b/modules/ticket/front/sale/index.spec.js
index 28d8749328..a59eb3865c 100644
--- a/modules/ticket/front/sale/index.spec.js
+++ b/modules/ticket/front/sale/index.spec.js
@@ -393,7 +393,7 @@ describe('Ticket', () => {
                 secondSelectedSale.checked = true;
 
                 const expectedSales = [firstSelectedSale, secondSelectedSale];
-                controller.$.editDiscountDialog = {hide: jest.fn()};
+                controller.$.editDiscount = {hide: jest.fn()};
                 controller.edit = {
                     discount: 10,
                     sales: expectedSales
@@ -402,7 +402,7 @@ describe('Ticket', () => {
                 controller.changeMultipleDiscount();
 
                 expect(controller.updateDiscount).toHaveBeenCalledWith(expectedSales);
-                expect(controller.$.editDiscountDialog.hide).toHaveBeenCalledWith();
+                expect(controller.$.editDiscount.hide).toHaveBeenCalledWith();
             });
 
             it('should not call to the updateDiscount() method and then to the editDiscountDialog hide() method', () => {
@@ -417,7 +417,7 @@ describe('Ticket', () => {
                 secondSelectedSale.discount = 10;
 
                 const expectedSales = [firstSelectedSale, secondSelectedSale];
-                controller.$.editDiscountDialog = {hide: jest.fn()};
+                controller.$.editDiscount = {hide: jest.fn()};
                 controller.edit = {
                     discount: 10,
                     sales: expectedSales
@@ -426,7 +426,7 @@ describe('Ticket', () => {
                 controller.changeMultipleDiscount();
 
                 expect(controller.updateDiscount).not.toHaveBeenCalledWith(expectedSales);
-                expect(controller.$.editDiscountDialog.hide).toHaveBeenCalledWith();
+                expect(controller.$.editDiscount.hide).toHaveBeenCalledWith();
             });
         });
 

From dc6c8f924d902425aad22b959028ab0a039d4f39 Mon Sep 17 00:00:00 2001
From: Pau Navarro <pau@verdnatura.es>
Date: Mon, 17 Oct 2022 07:25:25 +0200
Subject: [PATCH 046/151] feat: Create new Supplier

---
 .../10491-august/00-newSupplier_ACL.sql       |  2 +
 .../00-newSupplier_Modify_supplier.sql        |  5 ++
 modules/supplier/back/methods/supplier/new.js | 28 -----------
 .../back/methods/supplier/newSupplier.js      | 50 +++++++++++++++++++
 modules/supplier/back/models/supplier.js      | 11 ++--
 modules/supplier/front/create/index.html      |  2 +-
 modules/supplier/front/create/index.js        | 14 ++++--
 modules/supplier/front/routes.json            | 12 ++---
 8 files changed, 83 insertions(+), 41 deletions(-)
 create mode 100644 db/changes/10491-august/00-newSupplier_ACL.sql
 create mode 100644 db/changes/10491-august/00-newSupplier_Modify_supplier.sql
 delete mode 100644 modules/supplier/back/methods/supplier/new.js
 create mode 100644 modules/supplier/back/methods/supplier/newSupplier.js

diff --git a/db/changes/10491-august/00-newSupplier_ACL.sql b/db/changes/10491-august/00-newSupplier_ACL.sql
new file mode 100644
index 0000000000..f23f3026bc
--- /dev/null
+++ b/db/changes/10491-august/00-newSupplier_ACL.sql
@@ -0,0 +1,2 @@
+INSERT INTO salix.ACL (model,property,accessType,principalId)
+	VALUES ('Supplier','newSupplier','WRITE','administrative');
diff --git a/db/changes/10491-august/00-newSupplier_Modify_supplier.sql b/db/changes/10491-august/00-newSupplier_Modify_supplier.sql
new file mode 100644
index 0000000000..d64cd3663a
--- /dev/null
+++ b/db/changes/10491-august/00-newSupplier_Modify_supplier.sql
@@ -0,0 +1,5 @@
+ALTER TABLE vn.supplier MODIFY COLUMN payMethodFk tinyint(3) unsigned DEFAULT NULL NULL;
+
+/* ------------------------------------------------------------------------------------------- */
+
+ALTER TABLE vn.supplier MODIFY COLUMN supplierActivityFk varchar(45) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL NULL;
\ No newline at end of file
diff --git a/modules/supplier/back/methods/supplier/new.js b/modules/supplier/back/methods/supplier/new.js
deleted file mode 100644
index 9fb8075327..0000000000
--- a/modules/supplier/back/methods/supplier/new.js
+++ /dev/null
@@ -1,28 +0,0 @@
-/* eslint-disable no-console */
-// eslint-disable-next-line no-unused-vars
-let UserError = require('vn-loopback/util/user-error');
-
-module.exports = Self => {
-    Self.remoteMethod('new', {
-        description: 'returns the created item',
-        accessType: 'WRITE',
-        accepts: [{
-            arg: 'params',
-            type: 'object',
-            http: {source: 'body'}
-        }],
-        returns: {
-            type: 'number',
-            root: true
-        },
-        http: {
-            path: `/new`,
-            verb: 'POST'
-        }
-    });
-
-    Self.new = async(params, options) => {
-        console.log(params);
-        console.log(options);
-    };
-};
diff --git a/modules/supplier/back/methods/supplier/newSupplier.js b/modules/supplier/back/methods/supplier/newSupplier.js
new file mode 100644
index 0000000000..9fe47fd53e
--- /dev/null
+++ b/modules/supplier/back/methods/supplier/newSupplier.js
@@ -0,0 +1,50 @@
+/* eslint-disable no-console */
+// eslint-disable-next-line no-unused-vars
+
+module.exports = Self => {
+    Self.remoteMethod('newSupplier', {
+        description: 'returns the created item',
+        accessType: 'WRITE',
+        accepts: [{
+            arg: 'params',
+            type: 'object',
+            http: {source: 'body'}
+        }],
+        returns: {
+            type: 'string',
+            root: true
+        },
+        http: {
+            path: `/newSupplier`,
+            verb: 'POST'
+        }
+    });
+
+    Self.newSupplier = async(params, options) => {
+        const models = Self.app.models;
+        const myOptions = {};
+
+        params.payDemFk = 1;
+
+        console.log(params);
+
+        if (!myOptions.transaction) {
+            tx = await Self.beginTransaction({});
+            myOptions.transaction = tx;
+        }
+
+        try {
+            const supplier = await models.Supplier.create(params, myOptions);
+
+            if (tx) await tx.commit();
+
+            return {
+                supplier
+            };
+        } catch (e) {
+            console.log(e);
+            if (tx) await tx.rollback();
+            return params;
+        }
+    };
+};
diff --git a/modules/supplier/back/models/supplier.js b/modules/supplier/back/models/supplier.js
index a2831845a3..6edfe274cb 100644
--- a/modules/supplier/back/models/supplier.js
+++ b/modules/supplier/back/models/supplier.js
@@ -10,7 +10,7 @@ module.exports = Self => {
     require('../methods/supplier/freeAgencies')(Self);
     require('../methods/supplier/campaignMetricsPdf')(Self);
     require('../methods/supplier/campaignMetricsEmail')(Self);
-    require('../methods/supplier/new')(Self);
+    require('../methods/supplier/newSupplier')(Self);
 
     Self.validatesPresenceOf('name', {
         message: 'The social name cannot be empty'
@@ -58,6 +58,9 @@ module.exports = Self => {
     }
 
     async function tinIsValid(err, done) {
+        if (!this.countryFk)
+            return done();
+
         const filter = {
             fields: ['code'],
             where: {id: this.countryFk}
@@ -81,6 +84,7 @@ module.exports = Self => {
     });
 
     async function hasSupplierAccount(err, done) {
+        if (!this.payMethodFk) return done();
         const payMethod = await Self.app.models.PayMethod.findById(this.payMethodFk);
         const supplierAccount = await Self.app.models.SupplierAccount.findOne({where: {supplierFk: this.id}});
         const hasIban = supplierAccount && supplierAccount.iban;
@@ -93,6 +97,7 @@ module.exports = Self => {
     }
 
     Self.observe('before save', async function(ctx) {
+        if (ctx.isNewInstance) return;
         const loopbackContext = LoopBackContext.getCurrentContext();
         const changes = ctx.data || ctx.instance;
         const orgData = ctx.currentInstance;
@@ -102,7 +107,7 @@ module.exports = Self => {
         const isPayMethodChecked = changes.isPayMethodChecked || orgData.isPayMethodChecked;
         const hasChanges = orgData && changes;
         const isPayMethodCheckedChanged = hasChanges
-            && orgData.isPayMethodChecked != isPayMethodChecked;
+         && orgData.isPayMethodChecked != isPayMethodChecked;
 
         if (isNotFinancial && isPayMethodCheckedChanged)
             throw new UserError('You can not modify is pay method checked');
@@ -115,7 +120,7 @@ module.exports = Self => {
         const socialName = changes.name || orgData.name;
         const hasChanges = orgData && changes;
         const socialNameChanged = hasChanges
-            && orgData.socialName != socialName;
+         && orgData.socialName != socialName;
 
         if ((socialNameChanged) && !isAlpha(socialName))
             throw new UserError('The social name has an invalid format');
diff --git a/modules/supplier/front/create/index.html b/modules/supplier/front/create/index.html
index 71fe3b4888..17e4241151 100644
--- a/modules/supplier/front/create/index.html
+++ b/modules/supplier/front/create/index.html
@@ -1,6 +1,6 @@
 <vn-watcher
     vn-id="watcher"
-    url="supplier/new"
+    url="suppliers/newSupplier"
     data="$ctrl.supplier"
     insert-mode="true"
     form="form">
diff --git a/modules/supplier/front/create/index.js b/modules/supplier/front/create/index.js
index 8708aacd67..01b02179b8 100644
--- a/modules/supplier/front/create/index.js
+++ b/modules/supplier/front/create/index.js
@@ -5,14 +5,22 @@ import Section from 'salix/components/section';
 class Controller extends Section {
     constructor($element, $) {
         super($element, $);
-        console.log($);
     }
 
     onSubmit() {
         this.$.watcher.submit().then(
-            console.log('abc'),
-            json => this.$state.go('item.card.basicData', {id: json.data.id})
+            json => {
+                console.log('abc');
+                this.$state.go('item.card.basicData', {id: json.data.id});
+                console.log('ctrl --> ', this.$.$ctrl);
 
+                redirect(this.$.$ctrl);
+
+                async function redirect(ctrl) {
+                    await new Promise(r => setTimeout(r, 100));
+                    window.location.href = `/#!/supplier/${ctrl.supplier.supplier.id}/fiscal-data`;
+                }
+            }
         );
     }
 }
diff --git a/modules/supplier/front/routes.json b/modules/supplier/front/routes.json
index 03efea0f3d..8c9b7f760b 100644
--- a/modules/supplier/front/routes.json
+++ b/modules/supplier/front/routes.json
@@ -31,12 +31,6 @@
             "component": "vn-supplier",
             "description": "Suppliers"
         },
-        {
-            "url": "/create",
-            "state": "supplier.create",
-            "component": "vn-supplier-create",
-            "description": "New supplier"
-        },
         {
             "url": "/index?q",
             "state": "supplier.index",
@@ -57,6 +51,12 @@
             "params": {
                 "supplier": "$ctrl.supplier"
             }
+        },
+        {
+            "url": "/create",
+            "state": "supplier.create",
+            "component": "vn-supplier-create",
+            "description": "New supplier"
         }, 
         {
             "url": "/basic-data",

From 991893837c285ebd9f340959375038dce77f757c Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Mon, 17 Oct 2022 07:34:22 +0200
Subject: [PATCH 047/151] correct fixutures from dev

---
 db/dump/fixtures.sql | 109 +++++++++++++++++++++----------------------
 1 file changed, 54 insertions(+), 55 deletions(-)

diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql
index 912c43bc20..2e00389e5b 100644
--- a/db/dump/fixtures.sql
+++ b/db/dump/fixtures.sql
@@ -866,7 +866,7 @@ INSERT INTO `vn`.`itemFamily`(`code`, `description`)
         ('VT',  'Sales');
 
 INSERT INTO `vn`.`item`(`id`, `typeFk`, `size`, `inkFk`, `stems`, `originFk`, `description`, `producerFk`, `intrastatFk`, `expenceFk`,
-    `comment`, `relevancy`, `image`, `subName`, `minPrice`, `stars`, `family`, `isFloramondo`, `genericFk`, `itemPackingTypeFk`, `hasMinPrice`, `packingShelve`)
+    `comment`, `relevancy`, `image`, `subName`, `minPrice`, `stars`, `family`, `isFloramondo`, `genericFk`, `itemPackingTypeFk`, `hasMinPrice`, `packingShelve`, `weightByPiece`)
     VALUES
         (1,  2, 70,   'YEL', 1,    1, NULL,              1,    06021010, 2000000000, NULL, 0, '1',  NULL, 0, 1, 'VT',   0,  NULL,   'V',  0, 15,3),
         (2,  2, 70,   'BLU', 1,    2, NULL,              1,    06021010, 2000000000, NULL, 0, '2',  NULL, 0, 2, 'VT',   0,  NULL,   'H',  0, 10,2),
@@ -1175,10 +1175,6 @@ INSERT INTO `vn`.`ticketCollection`(`ticketFk`, `collectionFk`, `level`)
         (3, 2, NULL),
         (23, 1, NULL);
 
-INSERT INTO `vn`.`parking` (`column`, `row`, `sectorFk`, `code`, `pickingOrder`)
-    VALUES
-        ('100', '01', 1, '100-01', 1);
-
 INSERT INTO `vn`.`genus`(`id`, `name`)
     VALUES
         (1, 'Abelia'),
@@ -1936,16 +1932,19 @@ INSERT INTO `vn`.`workerBusinessType` (`id`, `name`, `isFullTime`, `isPermanent`
         (100,   'INDEFINIDO A TIEMPO COMPLETO',                     1, 1, 1),
         (109,   'CONVERSION DE TEMPORAL EN INDEFINIDO T.COMPLETO',  1, 1, 1);
 
-UPDATE `postgresql`.`business_labour` bl
-    JOIN `postgresql`.`business` b ON b.business_id = bl.business_id
-    JOIN `postgresql`.`profile` pr ON pr.profile_id = b.client_id
-    JOIN `postgresql`.`person` p ON p.person_id = pr.person_id
-    SET bl.`professional_category_id` = 31
-    WHERE p.`Id_trabajador` = 1110;
+UPDATE `vn`.`business` b
+    SET `rate` = 7,
+        `workerBusinessCategoryFk` = 12,
+        `workerBusinessTypeFk` = 100,
+        `amount` = 900.50
+    WHERE b.id = 1;
 
-UPDATE `postgresql`.`business_labour` bl
-    SET bl.`department_id` = 43
-WHERE business_id IN(18, 19);
+UPDATE `vn`.`business` b
+    SET `rate` = 7,
+        `workerBusinessCategoryFk` = 12,
+        `workerBusinessTypeFk` = 100,
+        `amount` = 1263.03
+    WHERE b.id = 1106;
 
 UPDATE `vn`.`business` b
     SET `rate` = 7,
@@ -1954,17 +1953,12 @@ UPDATE `vn`.`business` b
         `amount` = 2000
     WHERE b.id = 1107;
 
-INSERT INTO `postgresql`.`profile_media`(`profile_media_id`, `profile_id`, `media_id`)
-    VALUES
-        (1, 1106, 1),
-        (2, 1107, 2);
-
-INSERT INTO `vn`.`workCenterHoliday` (`workCenterFk`, `days`, `year`)
-    VALUES
-        ('1', '27.5', YEAR(util.VN_CURDATE())),
-        ('5', '22', YEAR(util.VN_CURDATE())),
-        ('1', '24.5', YEAR(DATE_ADD(util.VN_CURDATE(), INTERVAL -1 YEAR))),
-        ('5', '23', YEAR(DATE_ADD(util.VN_CURDATE(), INTERVAL -1 YEAR)));
+UPDATE `vn`.`business` b
+    SET `rate` = 7,
+        `workerBusinessCategoryFk` = 12,
+        `workerBusinessTypeFk` = 100,
+        `amount` = 1500
+    WHERE b.id = 1108;
 
 INSERT INTO `vn`.`absenceType` (`id`, `name`, `rgb`, `code`, `holidayEntitlementRate`, `discountRate`)
     VALUES
@@ -1975,22 +1969,7 @@ INSERT INTO `vn`.`absenceType` (`id`, `name`, `rgb`, `code`, `holidayEntitlement
         (20, 'Furlough',            '#97B92F', 'furlough',      1,      1),
         (21, 'Furlough half day',   '#778899', 'halfFurlough',  0.5,    1);
 
-ALTER TABLE `postgresql`.`business_labour_payroll` DROP FOREIGN KEY `business_labour_payroll_cod_categoria`;
-
-INSERT INTO `vn`.`workerBusinessType` (`id`, `name`, `isFullTime`, `isPermanent`, `hasHolidayEntitlement`)
-    VALUES
-        (1,     'CONTRATO HOLANDA',                                 1, 0, 1),
-        (100,   'INDEFINIDO A TIEMPO COMPLETO',                     1, 1, 1),
-        (109,   'CONVERSION DE TEMPORAL EN INDEFINIDO T.COMPLETO',  1, 1, 1);
-
-INSERT INTO `postgresql`.`business_labour_payroll` (`business_id`, `cod_tarifa`, `cod_categoria`, `cod_contrato`, `importepactado`)
-    VALUES
-        (1, 7, 12, 100, 900.50),
-        (1106, 7, 12, 100, 1263.03),
-        (1107, 7, 12, 100, 2000),
-        (1108, 7, 12, 100, 1500);
-
-INSERT INTO `postgresql`.`calendar_employee` (`business_id`, `calendar_state_id`, `date`)
+INSERT INTO `postgresql`.`calendar_employee` (`businessFk`, `calendar_state_id`, `date`)
     VALUES
         (1,    6, IF(MONTH(util.VN_CURDATE()) = 12 AND DAY(util.VN_CURDATE()) > 10, DATE_ADD(util.VN_CURDATE(), INTERVAL -10 DAY), DATE_ADD(util.VN_CURDATE(), INTERVAL 10 DAY))),
         (1106, 1, IF(MONTH(util.VN_CURDATE()) = 12 AND DAY(util.VN_CURDATE()) > 10, DATE_ADD(util.VN_CURDATE(), INTERVAL -10 DAY), DATE_ADD(util.VN_CURDATE(), INTERVAL 10 DAY))),
@@ -2485,18 +2464,18 @@ INSERT INTO `vn`.`duaInvoiceIn`(`id`, `duaFk`, `invoiceInFk`)
 
 INSERT INTO `vn`.`invoiceInTax` (`invoiceInFk`, `taxableBase`, `expenceFk`, `foreignValue`, `taxTypeSageFk`, `transactionTypeSageFk`)
     VALUES
-        (1, 99.99, '2000000000', null, null, null),
-        (2, 999.99, '2000000000', null, null, null),
-        (3, 1000.50, '2000000000', null, null, null),
-        (4, 0.50, '2000000000', null, null, null),
-        (5, 150.50, '2000000000', null, null, null),
-        (1, 252.25, '4751000000', NULL, 7, 61),
-        (2, 223.17, '6210000567', NULL, 8, 20),
-        (3, 95.60,  '7001000000', NULL, 8, 35),
-        (4, 446.63, '7001000000', NULL, 6, 61),
-        (5, 64.23,  '6210000567', NULL, 8, 20),
-        (6, 29.95,  '7001000000', NULL, 7, 20),
-        (7, 58.64,  '6210000567', NULL, 8, 20);
+        (1, 99.99,      '2000000000', NULL, NULL, NULL),
+        (2, 999.99,     '2000000000', NULL, NULL, NULL),
+        (3, 1000.50,    '2000000000', NULL, NULL, NULL),
+        (4, 0.50,       '2000000000', NULL, NULL, NULL),
+        (5, 150.50,     '2000000000', NULL, NULL, NULL),
+        (1, 252.25,     '4751000000', NULL, 7, 61),
+        (2, 223.17,     '6210000567', NULL, 8, 20),
+        (3, 95.60,      '7001000000', NULL, 8, 35),
+        (4, 446.63,     '7001000000', NULL, 6, 61),
+        (5, 64.23,      '6210000567', NULL, 8, 20),
+        (6, 29.95,      '7001000000', NULL, 7, 20),
+        (7, 58.64,      '6210000567', NULL, 8, 20);
 
 INSERT INTO `vn`.`invoiceInIntrastat` (`invoiceInFk`, `net`, `intrastatFk`, `amount`, `stems`, `countryFk`)
     VALUES
@@ -2506,8 +2485,8 @@ INSERT INTO `vn`.`invoiceInIntrastat` (`invoiceInFk`, `net`, `intrastatFk`, `amo
         (2, 16.10, 6021010, 25.00, 80,  5);
 
 INSERT INTO `vn`.`ticketRecalc`(`ticketFk`)
-    SELECT `id`
-        FROM `vn`.`ticket` t
+    SELECT t.id
+        FROM vn.ticket t
             LEFT JOIN vn.ticketRecalc tr ON tr.ticketFk = t.id
         WHERE tr.ticketFk IS NULL;
 
@@ -2668,3 +2647,23 @@ INSERT INTO `vn`.`sectorCollectionSaleGroup` (`sectorCollectionFk`, `saleGroupFk
 INSERT INTO `vn`.`workerTimeControlConfig` (`id`, `dayBreak`, `dayBreakDriver`, `shortWeekBreak`, `longWeekBreak`, `weekScope`, `mailPass`, `mailHost`, `mailSuccessFolder`, `mailErrorFolder`, `mailUser`, `minHoursToBreak`, `breakHours`, `hoursCompleteWeek`, `startNightlyHours`, `endNightlyHours`, `maxTimePerDay`, `breakTime`, `timeToBreakTime`, `dayMaxTime`, `shortWeekDays`, `longWeekDays`)
     VALUES
         (1, 43200, 32400, 129600, 259200, 604800, '', '', 'Leidos.exito', 'Leidos.error', 'timeControl', 5.33, 0.33, 40, '22:00:00', '06:00:00', 57600, 1200, 18000, 57600, 6, 13);
+
+INSERT INTO `vn`.`routeConfig` (`id`, `defaultWorkCenterFk`)
+    VALUES
+        (1, 9);
+
+INSERT INTO `vn`.`productionConfig` (`isPreviousPreparationRequired`, `ticketPrintedMax`, `ticketTrolleyMax`, `rookieDays`, `notBuyingMonths`, `id`, `isZoneClosedByExpeditionActivated`, `maxNotReadyCollections`, `minTicketsToCloseZone`, `movingTicketDelRoute`, `defaultZone`, `defautlAgencyMode`, `hasUniqueCollectionTime`, `maxCollectionWithoutUser`, `pendingCollectionsOrder`, `pendingCollectionsAge`)
+    VALUES
+        (0, 8, 80, 0, 0, 1, 0, 15, 25, -1, 697, 1328, 0, 1, 8, 6);
+
+INSERT INTO `vn`.`collection` (`id`, `created`, `workerFk`, `stateFk`, `itemPackingTypeFk`, `saleTotalCount`, `salePickedCount`, `trainFk`, `sectorFk`, `wagons`)
+    VALUES
+        (3, util.VN_NOW(), 1107, 5, NULL, 0, 0, 1, NULL, NULL);
+
+INSERT INTO `vn`.`ticketCollection` (`ticketFk`, `collectionFk`, `created`, `level`, `wagon`, `smartTagFk`, `usedShelves`, `itemCount`, `liters`)
+    VALUES
+        (9, 3, util.VN_NOW(), NULL, 0, NULL, NULL, NULL, NULL);
+
+UPDATE `account`.`user`
+    SET `hasGrant` = 1
+        WHERE `id` = 66;

From 594cee12f3fd982daf4a8c6a54d327f756e9a25d Mon Sep 17 00:00:00 2001
From: Pau Navarro <pau@verdnatura.es>
Date: Mon, 17 Oct 2022 07:35:02 +0200
Subject: [PATCH 048/151] add checks to the existence of object variables

---
 modules/supplier/back/models/supplier.js | 16 ++++++++++------
 1 file changed, 10 insertions(+), 6 deletions(-)

diff --git a/modules/supplier/back/models/supplier.js b/modules/supplier/back/models/supplier.js
index 6edfe274cb..44549c65c7 100644
--- a/modules/supplier/back/models/supplier.js
+++ b/modules/supplier/back/models/supplier.js
@@ -20,13 +20,17 @@ module.exports = Self => {
         message: 'The supplier name must be unique'
     });
 
-    Self.validatesPresenceOf('city', {
-        message: 'City cannot be empty'
-    });
+    if (this.city) {
+        Self.validatesPresenceOf('city', {
+            message: 'City cannot be empty'
+        });
+    }
 
-    Self.validatesPresenceOf('nif', {
-        message: 'The nif cannot be empty'
-    });
+    if (this.nif) {
+        Self.validatesPresenceOf('nif', {
+            message: 'The nif cannot be empty'
+        });
+    }
 
     Self.validatesUniquenessOf('nif', {
         message: 'TIN must be unique'

From 1603619d812a4330fc073ad42bd9d1c7648a0485 Mon Sep 17 00:00:00 2001
From: Pau Navarro <pau@verdnatura.es>
Date: Mon, 17 Oct 2022 07:38:54 +0200
Subject: [PATCH 049/151] removed debugging elements

---
 modules/supplier/back/methods/supplier/newSupplier.js | 6 ------
 modules/supplier/front/create/index.js                | 3 ---
 2 files changed, 9 deletions(-)

diff --git a/modules/supplier/back/methods/supplier/newSupplier.js b/modules/supplier/back/methods/supplier/newSupplier.js
index 9fe47fd53e..7cb292871e 100644
--- a/modules/supplier/back/methods/supplier/newSupplier.js
+++ b/modules/supplier/back/methods/supplier/newSupplier.js
@@ -1,6 +1,3 @@
-/* eslint-disable no-console */
-// eslint-disable-next-line no-unused-vars
-
 module.exports = Self => {
     Self.remoteMethod('newSupplier', {
         description: 'returns the created item',
@@ -26,8 +23,6 @@ module.exports = Self => {
 
         params.payDemFk = 1;
 
-        console.log(params);
-
         if (!myOptions.transaction) {
             tx = await Self.beginTransaction({});
             myOptions.transaction = tx;
@@ -42,7 +37,6 @@ module.exports = Self => {
                 supplier
             };
         } catch (e) {
-            console.log(e);
             if (tx) await tx.rollback();
             return params;
         }
diff --git a/modules/supplier/front/create/index.js b/modules/supplier/front/create/index.js
index 01b02179b8..3104d73b59 100644
--- a/modules/supplier/front/create/index.js
+++ b/modules/supplier/front/create/index.js
@@ -1,4 +1,3 @@
-/* eslint-disable no-console */
 import ngModule from '../module';
 import Section from 'salix/components/section';
 
@@ -10,9 +9,7 @@ class Controller extends Section {
     onSubmit() {
         this.$.watcher.submit().then(
             json => {
-                console.log('abc');
                 this.$state.go('item.card.basicData', {id: json.data.id});
-                console.log('ctrl --> ', this.$.$ctrl);
 
                 redirect(this.$.$ctrl);
 

From a11ef73dfbb70a780dc503767cab76c3e7476112 Mon Sep 17 00:00:00 2001
From: vicent <vicent@verdnatura.es>
Date: Mon, 17 Oct 2022 08:01:55 +0200
Subject: [PATCH 050/151] refactor: code repetead

---
 .../back/methods/ticket/updateDiscount.js     | 24 ++++++++++---------
 1 file changed, 13 insertions(+), 11 deletions(-)

diff --git a/modules/ticket/back/methods/ticket/updateDiscount.js b/modules/ticket/back/methods/ticket/updateDiscount.js
index 99daac5127..d452b03fef 100644
--- a/modules/ticket/back/methods/ticket/updateDiscount.js
+++ b/modules/ticket/back/methods/ticket/updateDiscount.js
@@ -141,17 +141,9 @@ module.exports = Self => {
                     };
                     await models.SaleComponent.destroyAll(filter, myOptions);
 
-                    newComponent = models.SaleComponent.create({
-                        saleFk: sale.id,
-                        value: value,
-                        componentFk: componentId
-                    }, myOptions);
-                } else {
-                    newComponent = models.SaleComponent.create({
-                        saleFk: sale.id,
-                        value: value,
-                        componentFk: componentId}, myOptions);
-                }
+                    await createSaleComponent(sale.id, value, componentId, myOptions);
+                } else
+                    await createSaleComponent(sale.id, value, componentId, myOptions);
 
                 const updatedSale = sale.updateAttribute('discount', newDiscount, myOptions);
 
@@ -198,4 +190,14 @@ module.exports = Self => {
             throw e;
         }
     };
+
+    async function createSaleComponent(saleId, value, componentId, myOptions) {
+        const models = Self.app.models;
+
+        newComponent = models.SaleComponent.create({
+            saleFk: saleId,
+            value: value,
+            componentFk: componentId
+        }, myOptions);
+    }
 };

From 06ecceb478373820cfd0d0c9968ae200462c034c Mon Sep 17 00:00:00 2001
From: vicent <vicent@verdnatura.es>
Date: Mon, 17 Oct 2022 08:02:19 +0200
Subject: [PATCH 051/151] refactor: lines to long

---
 .../back/methods/ticket/specs/componentUpdate.spec.js  | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/modules/ticket/back/methods/ticket/specs/componentUpdate.spec.js b/modules/ticket/back/methods/ticket/specs/componentUpdate.spec.js
index 2aa2a07c4c..a8a4d5048a 100644
--- a/modules/ticket/back/methods/ticket/specs/componentUpdate.spec.js
+++ b/modules/ticket/back/methods/ticket/specs/componentUpdate.spec.js
@@ -18,13 +18,17 @@ describe('ticket componentUpdate()', () => {
     beforeAll(async() => {
         const deliveryComponenet = await models.Component.findOne({where: {code: 'delivery'}});
         deliveryComponentId = deliveryComponenet.id;
-        componentOfSaleSeven = `SELECT value FROM vn.saleComponent WHERE saleFk = 7 AND componentFk = ${deliveryComponentId}`;
-        componentOfSaleEight = `SELECT value FROM vn.saleComponent WHERE saleFk = 8 AND componentFk = ${deliveryComponentId}`;
-
+        componentOfSaleSeven = `SELECT value 
+                                    FROM vn.saleComponent 
+                                    WHERE saleFk = 7 AND componentFk = ${deliveryComponentId}`;
+        componentOfSaleEight = `SELECT value 
+                                    FROM vn.saleComponent 
+                                    WHERE saleFk = 8 AND componentFk = ${deliveryComponentId}`;
         [componentValue] = await models.SaleComponent.rawSql(componentOfSaleSeven);
         firstvalueBeforeChange = componentValue.value;
 
         [componentValue] = await models.SaleComponent.rawSql(componentOfSaleEight);
+
         secondvalueBeforeChange = componentValue.value;
     });
 

From cdce628038a2bea5aefd5589a4e68d13a900d69c Mon Sep 17 00:00:00 2001
From: vicent <vicent@verdnatura.es>
Date: Mon, 17 Oct 2022 08:11:50 +0200
Subject: [PATCH 052/151] refactor: delete line break

---
 modules/ticket/back/methods/ticket/specs/componentUpdate.spec.js | 1 -
 1 file changed, 1 deletion(-)

diff --git a/modules/ticket/back/methods/ticket/specs/componentUpdate.spec.js b/modules/ticket/back/methods/ticket/specs/componentUpdate.spec.js
index a8a4d5048a..b3291c25a4 100644
--- a/modules/ticket/back/methods/ticket/specs/componentUpdate.spec.js
+++ b/modules/ticket/back/methods/ticket/specs/componentUpdate.spec.js
@@ -28,7 +28,6 @@ describe('ticket componentUpdate()', () => {
         firstvalueBeforeChange = componentValue.value;
 
         [componentValue] = await models.SaleComponent.rawSql(componentOfSaleEight);
-
         secondvalueBeforeChange = componentValue.value;
     });
 

From 787d10aac6c08fb7e69643b622505d9d1d3a47d4 Mon Sep 17 00:00:00 2001
From: vicent <vicent@verdnatura.es>
Date: Mon, 17 Oct 2022 08:29:09 +0200
Subject: [PATCH 053/151] fix: select one result only

---
 modules/ticket/back/methods/ticket/updateDiscount.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/modules/ticket/back/methods/ticket/updateDiscount.js b/modules/ticket/back/methods/ticket/updateDiscount.js
index d452b03fef..bfa3cdbf64 100644
--- a/modules/ticket/back/methods/ticket/updateDiscount.js
+++ b/modules/ticket/back/methods/ticket/updateDiscount.js
@@ -124,7 +124,7 @@ module.exports = Self => {
                     where: {code: 'manaClaim'}
                 }, myOptions);
 
-                const oldComponent = await models.SaleComponent.find({
+                const [oldComponent] = await models.SaleComponent.find({
                     where: {
                         and: [
                             {saleFk: sale.id},

From 0cdee89ac31fd380a0b74e8877ef4590da9d305c Mon Sep 17 00:00:00 2001
From: Pau Navarro <pau@verdnatura.es>
Date: Mon, 17 Oct 2022 09:20:45 +0200
Subject: [PATCH 054/151] Button removed when user does not have permissions

---
 modules/supplier/front/index/index.html | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/modules/supplier/front/index/index.html b/modules/supplier/front/index/index.html
index 5d29ba0ebf..49f38cb1bf 100644
--- a/modules/supplier/front/index/index.html
+++ b/modules/supplier/front/index/index.html
@@ -59,8 +59,6 @@
         supplier="$ctrl.supplierSelected">
     </vn-supplier-summary>
 </vn-popup>
-<!--vn-float-button vn-acl="administrative" icon="add" ng-click="$ctrl.test()" fixed-bottom-right vn-tooltip="New supplier"></vn-float-button>
--->
-<a vn-acl="administrative" ui-sref="supplier.create" vn-tooltip="New supplier" vn-bind="+" fixed-bottom-right>
+<a vn-acl-action="remove" vn-acl="administrative" ui-sref="supplier.create" vn-tooltip="New supplier" vn-bind="+" fixed-bottom-right>
     <vn-float-button icon="add"></vn-float-button>
 </a>
\ No newline at end of file

From f0b1591b142437b4949cf736c29482697ad8cb0b Mon Sep 17 00:00:00 2001
From: Pau Navarro <pau@verdnatura.es>
Date: Mon, 17 Oct 2022 09:22:50 +0200
Subject: [PATCH 055/151] Remove debugging elements

---
 modules/supplier/front/index/index.js | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/modules/supplier/front/index/index.js b/modules/supplier/front/index/index.js
index b9b43321d5..77b2e83478 100644
--- a/modules/supplier/front/index/index.js
+++ b/modules/supplier/front/index/index.js
@@ -10,11 +10,6 @@ export default class Controller extends Section {
         this.supplierSelected = supplier;
         this.$.dialogSummarySupplier.show();
     }
-
-    test() {
-        // eslint-disable-next-line no-console
-        console.log('Creating new supplier');
-    }
 }
 
 ngModule.vnComponent('vnSupplierIndex', {

From a4243e14c53a3309125d3caeb5719d0b03ad52f9 Mon Sep 17 00:00:00 2001
From: Pau Navarro <pau@verdnatura.es>
Date: Mon, 17 Oct 2022 10:17:56 +0200
Subject: [PATCH 056/151] Created Back test for newSupplier

---
 .../methods/supplier/specs/newSupplier.spec.js     | 14 ++++++++++++++
 1 file changed, 14 insertions(+)
 create mode 100644 modules/supplier/back/methods/supplier/specs/newSupplier.spec.js

diff --git a/modules/supplier/back/methods/supplier/specs/newSupplier.spec.js b/modules/supplier/back/methods/supplier/specs/newSupplier.spec.js
new file mode 100644
index 0000000000..69a32436ea
--- /dev/null
+++ b/modules/supplier/back/methods/supplier/specs/newSupplier.spec.js
@@ -0,0 +1,14 @@
+const app = require('vn-loopback/server/server');
+
+describe('Supplier newSupplier()', () => {
+    const supplier = {
+        name: 'TestSupplier-1'
+    };
+
+    it('should create a new supplier containing only the name', async() => {
+        const result = await app.models.Supplier.newSupplier(supplier);
+
+        expect(result.payDemFk).toEqual('TestSupplier-1');
+        expect(result.payDemFk).toEqual(1);
+    });
+});

From 79b970286c1b382a8b90a8969e55a1a5a11445d8 Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Mon, 17 Oct 2022 11:22:27 +0200
Subject: [PATCH 057/151] refactor(claim_claimPickupEmail): use text template
 and external form

---
 e2e/paths/06-claim/05_summary.spec.js         |  2 +-
 loopback/locale/en.json                       |  5 ++-
 loopback/locale/es.json                       |  5 ++-
 .../back/methods/claim/claimPickupEmail.js    | 40 +++++++++++++++++++
 modules/claim/front/descriptor/index.js       |  5 ++-
 modules/claim/front/descriptor/index.spec.js  | 12 +++++-
 .../claim-pickup-order.html                   |  2 +-
 .../claim-pickup-order/claim-pickup-order.js  |  2 +-
 .../claim-pickup-order/claim-pickup-order.js  |  3 +-
 9 files changed, 64 insertions(+), 12 deletions(-)

diff --git a/e2e/paths/06-claim/05_summary.spec.js b/e2e/paths/06-claim/05_summary.spec.js
index 00b021f88f..05d18a2c31 100644
--- a/e2e/paths/06-claim/05_summary.spec.js
+++ b/e2e/paths/06-claim/05_summary.spec.js
@@ -2,7 +2,7 @@
 import selectors from '../../helpers/selectors.js';
 import getBrowser from '../../helpers/puppeteer';
 
-describe('Claim summary path', () => {
+fdescribe('Claim summary path', () => {
     let browser;
     let page;
     const claimId = '4';
diff --git a/loopback/locale/en.json b/loopback/locale/en.json
index e5a0fae322..e9311800ec 100644
--- a/loopback/locale/en.json
+++ b/loopback/locale/en.json
@@ -133,5 +133,6 @@
 	"Descanso semanal 36h. / 72h.": "Weekly rest 36h. / 72h.",
 	"Password does not meet requirements": "Password does not meet requirements",
 	"You don't have privileges to change the zone": "You don't have privileges to change the zone or for these parameters there are more than one shipping options, talk to agencies",
-	"Not enough privileges to edit a client": "Not enough privileges to edit a client"
-}
\ No newline at end of file
+	"Not enough privileges to edit a client": "Not enough privileges to edit a client",
+    "Claim pickup order sent": "Claim pickup order sent [({{claimId}})]({{{claimUrl}}}) to client *{{clientName}}*"
+}
diff --git a/loopback/locale/es.json b/loopback/locale/es.json
index 67370b3438..8caf76836c 100644
--- a/loopback/locale/es.json
+++ b/loopback/locale/es.json
@@ -235,5 +235,6 @@
 	"Dirección incorrecta": "Dirección incorrecta",
 	"Modifiable user details only by an administrator": "Detalles de usuario modificables solo por un administrador",
 	"Modifiable password only via recovery or by an administrator": "Contraseña modificable solo a través de la recuperación o por un administrador",
-	"Not enough privileges to edit a client": "No tienes suficientes privilegios para editar un cliente"
-}
\ No newline at end of file
+	"Not enough privileges to edit a client": "No tienes suficientes privilegios para editar un cliente",
+    "Claim pickup order sent": "Reclamación Orden de recogida enviada [({{claimId}})]({{{claimUrl}}}) al cliente *{{clientName}}*"
+}
diff --git a/modules/claim/back/methods/claim/claimPickupEmail.js b/modules/claim/back/methods/claim/claimPickupEmail.js
index 4d64cc66ea..4c9b865025 100644
--- a/modules/claim/back/methods/claim/claimPickupEmail.js
+++ b/modules/claim/back/methods/claim/claimPickupEmail.js
@@ -29,6 +29,24 @@ module.exports = Self => {
                 type: 'number',
                 description: 'The recipient id to send to the recipient preferred language',
                 required: false
+            },
+            {
+                arg: 'ticketId',
+                type: 'number',
+                description: 'The ticket id',
+                required: true
+            },
+            {
+                arg: 'salesPersonId',
+                type: 'number',
+                description: 'The salesPerson id',
+                required: false
+            },
+            {
+                arg: 'clientName',
+                type: 'string',
+                description: 'The client name',
+                required: true
             }
         ],
         returns: {
@@ -42,6 +60,11 @@ module.exports = Self => {
     });
 
     Self.claimPickupEmail = async ctx => {
+        const models = Self.app.models;
+        const userId = ctx.req.accessToken.userId;
+        const $t = ctx.req.__; // $translate
+        const origin = ctx.req.headers.origin;
+
         const args = Object.assign({}, ctx.args);
         const params = {
             recipient: args.recipient,
@@ -52,6 +75,23 @@ module.exports = Self => {
         for (const param in args)
             params[param] = args[param];
 
+        const message = $t('Claim pickup order sent', {
+            claimId: args.id,
+            clientName: args.clientName,
+            claimUrl: `${origin}/#!/claim/${args.id}/summary`,
+        });
+
+        if (args.salesPersonId)
+            await models.Chat.sendCheckingPresence(ctx, args.salesPersonId, message);
+
+        await models.ClaimLog.create({
+            originFk: args.id,
+            userFk: userId,
+            action: 'insert',
+            description: 'Claim-pickup-order sent',
+            changedModel: 'Mail'
+        });
+
         const email = new Email('claim-pickup-order', params);
 
         return email.send();
diff --git a/modules/claim/front/descriptor/index.js b/modules/claim/front/descriptor/index.js
index 0dddadbe14..b36fae3211 100644
--- a/modules/claim/front/descriptor/index.js
+++ b/modules/claim/front/descriptor/index.js
@@ -19,7 +19,10 @@ class Controller extends Descriptor {
     sendPickupOrder() {
         return this.vnEmail.send(`Claims/${this.claim.id}/claim-pickup-email`, {
             recipient: this.claim.client.email,
-            recipientId: this.claim.clientFk
+            recipientId: this.claim.clientFk,
+            clientName: this.claim.client.name,
+            ticketId: this.claim.ticket.id,
+            salesPersonId: this.claim.client.salesPersonFk
         });
     }
 
diff --git a/modules/claim/front/descriptor/index.spec.js b/modules/claim/front/descriptor/index.spec.js
index e6785d3d8a..18ccdaff5e 100644
--- a/modules/claim/front/descriptor/index.spec.js
+++ b/modules/claim/front/descriptor/index.spec.js
@@ -7,7 +7,12 @@ describe('Item Component vnClaimDescriptor', () => {
     const claim = {
         id: 2,
         clientFk: 1101,
-        client: {email: 'client@email'}
+        client: {
+            email: 'client@email',
+            name: 'clientName',
+            salesPersonFk: 18
+        },
+        ticket: {id: 2}
     };
 
     beforeEach(ngModule('claim'));
@@ -40,7 +45,10 @@ describe('Item Component vnClaimDescriptor', () => {
 
             const params = {
                 recipient: claim.client.email,
-                recipientId: claim.clientFk
+                recipientId: claim.clientFk,
+                clientName: claim.client.name,
+                ticketId: claim.ticket.id,
+                salesPersonId: claim.client.salesPersonFk
             };
             controller.sendPickupOrder();
 
diff --git a/print/templates/email/claim-pickup-order/claim-pickup-order.html b/print/templates/email/claim-pickup-order/claim-pickup-order.html
index e6e74ed939..32606bd7b4 100644
--- a/print/templates/email/claim-pickup-order/claim-pickup-order.html
+++ b/print/templates/email/claim-pickup-order/claim-pickup-order.html
@@ -23,7 +23,7 @@
                         <!-- Block -->
                         <div class="grid-row">
                             <div class="grid-block vn-pa-ml">
-                                <h1>{{ $t('title', [claimId]) }}</h1>
+                                <h1>{{ $t('title', [id]) }}</h1>
                                 <p>{{ $t('description.dear') }},</p>
                                 <p v-html="instructions"></p>
                                 <p>{{ $t('description.conclusion') }}</p>
diff --git a/print/templates/email/claim-pickup-order/claim-pickup-order.js b/print/templates/email/claim-pickup-order/claim-pickup-order.js
index 74ee9408d6..51db21cb52 100755
--- a/print/templates/email/claim-pickup-order/claim-pickup-order.js
+++ b/print/templates/email/claim-pickup-order/claim-pickup-order.js
@@ -9,7 +9,7 @@ module.exports = {
         'email-footer': emailFooter.build()
     },
     created() {
-        this.instructions = this.$t('description.instructions', [this.claimId, this.ticketId]);
+        this.instructions = this.$t('description.instructions', [this.id, this.ticketId]);
     },
     data() {
         return {
diff --git a/print/templates/reports/claim-pickup-order/claim-pickup-order.js b/print/templates/reports/claim-pickup-order/claim-pickup-order.js
index 0220428454..c2c11cb88c 100755
--- a/print/templates/reports/claim-pickup-order/claim-pickup-order.js
+++ b/print/templates/reports/claim-pickup-order/claim-pickup-order.js
@@ -7,7 +7,6 @@ module.exports = {
     async serverPrefetch() {
         this.client = await this.fetchClient(this.id);
         this.sales = await this.fetchSales(this.id);
-        this.claimConfig = await this.fetchClaimConfig();
 
         if (!this.client)
             throw new Error('Something went wrong');
@@ -25,7 +24,7 @@ module.exports = {
         },
         fetchSales(id) {
             return this.rawSqlFromDef('sales', [id]);
-        },
+        }
     },
     components: {
         'report-header': reportHeader.build(),

From 57b2ae770da0c34798e01593dad9eed8f9f7b33a Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Mon, 17 Oct 2022 11:44:29 +0200
Subject: [PATCH 058/151] fix(e2e)

---
 e2e/paths/06-claim/05_summary.spec.js  |  2 +-
 modules/claim/front/summary/index.html | 39 +++++++++++++++-----------
 2 files changed, 23 insertions(+), 18 deletions(-)

diff --git a/e2e/paths/06-claim/05_summary.spec.js b/e2e/paths/06-claim/05_summary.spec.js
index 05d18a2c31..00b021f88f 100644
--- a/e2e/paths/06-claim/05_summary.spec.js
+++ b/e2e/paths/06-claim/05_summary.spec.js
@@ -2,7 +2,7 @@
 import selectors from '../../helpers/selectors.js';
 import getBrowser from '../../helpers/puppeteer';
 
-fdescribe('Claim summary path', () => {
+describe('Claim summary path', () => {
     let browser;
     let page;
     const claimId = '4';
diff --git a/modules/claim/front/summary/index.html b/modules/claim/front/summary/index.html
index fc1813467a..6adbfd6840 100644
--- a/modules/claim/front/summary/index.html
+++ b/modules/claim/front/summary/index.html
@@ -25,14 +25,29 @@
         </vn-button-menu>
     </h5>
     <vn-horizontal>
-        <vn-one>
-            <vn-label-value
-                label="Created"
-                value="{{$ctrl.summary.claim.created | date: 'dd/MM/yyyy'}}">
+        <vn-auto>
+            <h4>
+                <a
+                    ui-sref="claim.card.basicData({id:$ctrl.claim.id})"
+                    target="_self">
+                    <span translate vn-tooltip="Go to">Basic data</span>
+                </a>
+            </h4>
+                <vn-label-value
+                    label="Created"
+                    value="{{$ctrl.summary.claim.created | date: 'dd/MM/yyyy'}}">
+                </vn-label-value>
+                <vn-label-value
+                    label="State"
+                    value="{{$ctrl.summary.claim.claimState.description}}">
+                </vn-label-value>
+                <vn-label-value
+                label="Salesperson"
+                value="{{$ctrl.summary.claim.client.salesPersonUser.name}}">
             </vn-label-value>
             <vn-label-value
-                label="State"
-                value="{{$ctrl.summary.claim.claimState.description}}">
+                label="Attended by"
+                value="{{$ctrl.summary.claim.worker.user.nickname}}">
             </vn-label-value>
             <vn-check
                 class="vn-mr-md"
@@ -41,17 +56,7 @@
                 title="{{'When checked will notify to the salesPerson' | translate}}"
                 disabled="true">
             </vn-check>
-        </vn-one>
-        <vn-one>
-            <vn-label-value
-                label="Salesperson"
-                value="{{$ctrl.summary.claim.client.salesPersonUser.name}}">
-            </vn-label-value>
-            <vn-label-value
-                label="Attended by"
-                value="{{$ctrl.summary.claim.worker.user.nickname}}">
-            </vn-label-value>
-        </vn-one>
+        </vn-auto>
         <vn-auto>
             <h4 ng-show="$ctrl.isSalesPerson && $ctrl.summary.observations.length">
                 <a

From 70c9c3d78839a30fa6fbb7c78032e99f7cc9589e Mon Sep 17 00:00:00 2001
From: Pau Navarro <pau@verdnatura.es>
Date: Mon, 17 Oct 2022 12:07:34 +0200
Subject: [PATCH 059/151] initial back test created, modified DB statetments

---
 db/changes/10491-august/00-newSupplier_ACL.sql        |  2 +-
 .../10491-august/00-newSupplier_Modify_supplier.sql   |  4 ++--
 modules/supplier/back/methods/supplier/newSupplier.js | 10 +++++++++-
 .../back/methods/supplier/specs/newSupplier.spec.js   | 11 ++++++++---
 modules/supplier/front/create/index.js                |  1 -
 5 files changed, 20 insertions(+), 8 deletions(-)

diff --git a/db/changes/10491-august/00-newSupplier_ACL.sql b/db/changes/10491-august/00-newSupplier_ACL.sql
index f23f3026bc..c88f3de3f2 100644
--- a/db/changes/10491-august/00-newSupplier_ACL.sql
+++ b/db/changes/10491-august/00-newSupplier_ACL.sql
@@ -1,2 +1,2 @@
-INSERT INTO salix.ACL (model,property,accessType,principalId)
+INSERT INTO `salix`.`ACL` (model,property,accessType,principalId)
 	VALUES ('Supplier','newSupplier','WRITE','administrative');
diff --git a/db/changes/10491-august/00-newSupplier_Modify_supplier.sql b/db/changes/10491-august/00-newSupplier_Modify_supplier.sql
index d64cd3663a..660f5e9328 100644
--- a/db/changes/10491-august/00-newSupplier_Modify_supplier.sql
+++ b/db/changes/10491-august/00-newSupplier_Modify_supplier.sql
@@ -1,5 +1,5 @@
-ALTER TABLE vn.supplier MODIFY COLUMN payMethodFk tinyint(3) unsigned DEFAULT NULL NULL;
+ALTER TABLE `vn`.`supplier` MODIFY COLUMN payMethodFk tinyint(3) unsigned DEFAULT NULL NULL;
 
 /* ------------------------------------------------------------------------------------------- */
 
-ALTER TABLE vn.supplier MODIFY COLUMN supplierActivityFk varchar(45) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL NULL;
\ No newline at end of file
+ALTER TABLE `vn`.`supplier` MODIFY COLUMN supplierActivityFk varchar(45) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL NULL;
\ No newline at end of file
diff --git a/modules/supplier/back/methods/supplier/newSupplier.js b/modules/supplier/back/methods/supplier/newSupplier.js
index 7cb292871e..9d162557cc 100644
--- a/modules/supplier/back/methods/supplier/newSupplier.js
+++ b/modules/supplier/back/methods/supplier/newSupplier.js
@@ -17,10 +17,17 @@ module.exports = Self => {
         }
     });
 
-    Self.newSupplier = async(params, options) => {
+    Self.newSupplier = async params => {
         const models = Self.app.models;
         const myOptions = {};
 
+        process.stdout.write(typeof(params));
+
+        if (typeof(params) == 'string') {
+            console.log('params was a string, why?');
+            params = JSON.parse(params);
+        }
+
         params.payDemFk = 1;
 
         if (!myOptions.transaction) {
@@ -38,6 +45,7 @@ module.exports = Self => {
             };
         } catch (e) {
             if (tx) await tx.rollback();
+            params.e = e;
             return params;
         }
     };
diff --git a/modules/supplier/back/methods/supplier/specs/newSupplier.spec.js b/modules/supplier/back/methods/supplier/specs/newSupplier.spec.js
index 69a32436ea..982a1bb428 100644
--- a/modules/supplier/back/methods/supplier/specs/newSupplier.spec.js
+++ b/modules/supplier/back/methods/supplier/specs/newSupplier.spec.js
@@ -1,14 +1,19 @@
 const app = require('vn-loopback/server/server');
 
 describe('Supplier newSupplier()', () => {
-    const supplier = {
+    const newSupp = {
         name: 'TestSupplier-1'
     };
 
     it('should create a new supplier containing only the name', async() => {
-        const result = await app.models.Supplier.newSupplier(supplier);
+        let result = await app.models.Supplier.newSupplier(JSON.stringify(newSupp));
 
-        expect(result.payDemFk).toEqual('TestSupplier-1');
+        expect(result.name).toEqual('TestSupplier-1');
         expect(result.payDemFk).toEqual(1);
+        console.log(result);
+
+        // const createdSupplier = await app.models.Supplier.
+
+        // process.stdout.write(createdSupplier);
     });
 });
diff --git a/modules/supplier/front/create/index.js b/modules/supplier/front/create/index.js
index 3104d73b59..bed14c8262 100644
--- a/modules/supplier/front/create/index.js
+++ b/modules/supplier/front/create/index.js
@@ -14,7 +14,6 @@ class Controller extends Section {
                 redirect(this.$.$ctrl);
 
                 async function redirect(ctrl) {
-                    await new Promise(r => setTimeout(r, 100));
                     window.location.href = `/#!/supplier/${ctrl.supplier.supplier.id}/fiscal-data`;
                 }
             }

From aef47d46b1ef8c1259c20347b8dd59479ea21309 Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Mon, 17 Oct 2022 12:12:10 +0200
Subject: [PATCH 060/151] env test

---
 back/methods/notification/send.js | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/back/methods/notification/send.js b/back/methods/notification/send.js
index 5ae7e748b2..15baf0175a 100644
--- a/back/methods/notification/send.js
+++ b/back/methods/notification/send.js
@@ -71,7 +71,8 @@ module.exports = Self => {
                     const newParams = Object.assign({}, queueParams, sendParams);
                     const email = new Email(queueName, newParams);
 
-                    await email.send();
+                    if (process.env.NODE_ENV != 'test')
+                        await email.send();
 
                     await queue.updateAttribute('status', statusSent);
                 } catch (error) {

From c24b975f267d33c1f054f48b307781610d33c028 Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Mon, 17 Oct 2022 12:14:11 +0200
Subject: [PATCH 061/151] remove node_env

---
 back/methods/notification/send.js | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/back/methods/notification/send.js b/back/methods/notification/send.js
index 15baf0175a..80faf0305b 100644
--- a/back/methods/notification/send.js
+++ b/back/methods/notification/send.js
@@ -16,9 +16,6 @@ module.exports = Self => {
     });
 
     Self.send = async options => {
-        if (process.env.NODE_ENV == 'test')
-            throw new UserError(`Action not allowed on the test environment`);
-
         const models = Self.app.models;
         const findStatus = 'pending';
 

From e6481af3a9d3f95a852195955416f0e501920825 Mon Sep 17 00:00:00 2001
From: vicent <vicent@verdnatura.es>
Date: Mon, 17 Oct 2022 13:13:14 +0200
Subject: [PATCH 062/151] delete: transaction

---
 back/methods/dms/deleteTrashFiles.js | 77 ++++++++++++----------------
 1 file changed, 33 insertions(+), 44 deletions(-)

diff --git a/back/methods/dms/deleteTrashFiles.js b/back/methods/dms/deleteTrashFiles.js
index 6f9a2a211d..828f9658c6 100644
--- a/back/methods/dms/deleteTrashFiles.js
+++ b/back/methods/dms/deleteTrashFiles.js
@@ -17,61 +17,50 @@ module.exports = Self => {
     });
 
     Self.deleteTrashFiles = async options => {
-        let tx;
         const myOptions = {};
 
         if (typeof options == 'object')
             Object.assign(myOptions, options);
 
-        if (!myOptions.transaction) {
-            tx = await Self.beginTransaction({});
-            myOptions.transaction = tx;
-        }
+        if (process.env.NODE_ENV == 'test')
+            throw new UserError(`Action not allowed on the test environment`);
 
-        try {
-            if (process.env.NODE_ENV == 'test')
-                throw new UserError(`Action not allowed on the test environment`);
+        const models = Self.app.models;
+        const DmsContainer = models.DmsContainer;
 
-            const models = Self.app.models;
-            const DmsContainer = models.DmsContainer;
+        const trashDmsType = await models.DmsType.findOne({
+            where: {code: 'trash'}
+        }, myOptions);
 
-            const trashDmsType = await models.DmsType.findOne({
-                where: {code: 'trash'}
-            }, myOptions);
+        const date = new Date();
+        date.setMonth(date.getMonth() - 4);
 
-            const date = new Date();
-            date.setMonth(date.getMonth() - 4);
-
-            const dmsToDelete = await models.Dms.find({
-                where: {
-                    and: [
-                        {dmsTypeFk: trashDmsType.id},
-                        {created: {lt: date}}
-                    ]
-                }
-            }, myOptions);
-
-            for (let dms of dmsToDelete) {
-                const pathHash = DmsContainer.getHash(dms.id);
-                const dmsContainer = await DmsContainer.container(pathHash);
-                const dstFile = path.join(dmsContainer.client.root, pathHash, dms.file);
-                try {
-                    await fs.unlink(dstFile);
-                } catch (err) {
-                    continue;
-                }
-                const dstFolder = path.join(dmsContainer.client.root, pathHash);
-                try {
-                    await fs.rmdir(dstFolder);
-                } catch (err) {}
-
-                await dms.destroy(myOptions);
+        const dmsToDelete = await models.Dms.find({
+            where: {
+                and: [
+                    {dmsTypeFk: trashDmsType.id},
+                    {created: {lt: date}}
+                ]
             }
-            if (tx) await tx.commit();
-        } catch (e) {
-            if (tx) await tx.rollback();
+        }, myOptions);
 
-            throw e;
+        for (let dms of dmsToDelete) {
+            const pathHash = DmsContainer.getHash(dms.id);
+            const dmsContainer = await DmsContainer.container(pathHash);
+            const dstFile = path.join(dmsContainer.client.root, pathHash, dms.file);
+            try {
+                await fs.unlink(dstFile);
+            } catch (err) {
+                continue;
+            }
+            const dstFolder = path.join(dmsContainer.client.root, pathHash);
+            try {
+                await fs.rmdir(dstFolder);
+            } catch (err) {
+                continue;
+            }
+
+            await dms.destroy(myOptions);
         }
     };
 };

From f85c2e9700dcada8120b286a54a99fd97c333d8e Mon Sep 17 00:00:00 2001
From: vicent <vicent@verdnatura.es>
Date: Mon, 17 Oct 2022 14:01:21 +0200
Subject: [PATCH 063/151] refactor: delete code repeated

---
 modules/ticket/back/methods/ticket/updateDiscount.js | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/modules/ticket/back/methods/ticket/updateDiscount.js b/modules/ticket/back/methods/ticket/updateDiscount.js
index bfa3cdbf64..7e7c4e06d0 100644
--- a/modules/ticket/back/methods/ticket/updateDiscount.js
+++ b/modules/ticket/back/methods/ticket/updateDiscount.js
@@ -140,10 +140,9 @@ module.exports = Self => {
                         componentFk: oldComponent.componentFk
                     };
                     await models.SaleComponent.destroyAll(filter, myOptions);
+                }
 
-                    await createSaleComponent(sale.id, value, componentId, myOptions);
-                } else
-                    await createSaleComponent(sale.id, value, componentId, myOptions);
+                await createSaleComponent(sale.id, value, componentId, myOptions);
 
                 const updatedSale = sale.updateAttribute('discount', newDiscount, myOptions);
 

From 9290cd6fb6281f0c1bc704de73fead29ef7342f7 Mon Sep 17 00:00:00 2001
From: Pau Navarro <pau@verdnatura.es>
Date: Mon, 17 Oct 2022 14:02:18 +0200
Subject: [PATCH 064/151] Finished back tests

---
 .../00-newSupplier_Modify_supplier.sql        |  6 +++-
 .../back/methods/supplier/newSupplier.js      |  8 ++---
 .../supplier/specs/newSupplier.spec.js        | 35 +++++++++++++++++--
 3 files changed, 39 insertions(+), 10 deletions(-)

diff --git a/db/changes/10491-august/00-newSupplier_Modify_supplier.sql b/db/changes/10491-august/00-newSupplier_Modify_supplier.sql
index 660f5e9328..29a1884809 100644
--- a/db/changes/10491-august/00-newSupplier_Modify_supplier.sql
+++ b/db/changes/10491-august/00-newSupplier_Modify_supplier.sql
@@ -2,4 +2,8 @@ ALTER TABLE `vn`.`supplier` MODIFY COLUMN payMethodFk tinyint(3) unsigned DEFAUL
 
 /* ------------------------------------------------------------------------------------------- */
 
-ALTER TABLE `vn`.`supplier` MODIFY COLUMN supplierActivityFk varchar(45) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL NULL;
\ No newline at end of file
+ALTER TABLE `vn`.`supplier` MODIFY COLUMN supplierActivityFk varchar(45) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL NULL;
+
+/* ------------------------------------------------------------------------------------------- */
+
+ALTER TABLE `vn`.`supplierLog` MODIFY COLUMN userFk int(10) unsigned NULL;
diff --git a/modules/supplier/back/methods/supplier/newSupplier.js b/modules/supplier/back/methods/supplier/newSupplier.js
index 9d162557cc..748d7f5ee6 100644
--- a/modules/supplier/back/methods/supplier/newSupplier.js
+++ b/modules/supplier/back/methods/supplier/newSupplier.js
@@ -21,14 +21,11 @@ module.exports = Self => {
         const models = Self.app.models;
         const myOptions = {};
 
-        process.stdout.write(typeof(params));
-
-        if (typeof(params) == 'string') {
-            console.log('params was a string, why?');
+        if (typeof(params) == 'string')
             params = JSON.parse(params);
-        }
 
         params.payDemFk = 1;
+        params.nickname = params.name;
 
         if (!myOptions.transaction) {
             tx = await Self.beginTransaction({});
@@ -45,7 +42,6 @@ module.exports = Self => {
             };
         } catch (e) {
             if (tx) await tx.rollback();
-            params.e = e;
             return params;
         }
     };
diff --git a/modules/supplier/back/methods/supplier/specs/newSupplier.spec.js b/modules/supplier/back/methods/supplier/specs/newSupplier.spec.js
index 982a1bb428..a4ccd05ac9 100644
--- a/modules/supplier/back/methods/supplier/specs/newSupplier.spec.js
+++ b/modules/supplier/back/methods/supplier/specs/newSupplier.spec.js
@@ -8,12 +8,41 @@ describe('Supplier newSupplier()', () => {
     it('should create a new supplier containing only the name', async() => {
         let result = await app.models.Supplier.newSupplier(JSON.stringify(newSupp));
 
+        result = result.supplier;
+
         expect(result.name).toEqual('TestSupplier-1');
         expect(result.payDemFk).toEqual(1);
-        console.log(result);
+        expect(result.id).toEqual(443);
 
-        // const createdSupplier = await app.models.Supplier.
+        const createdSupplier = await app.models.Supplier.findById(result.id);
 
-        // process.stdout.write(createdSupplier);
+        expect(createdSupplier.id).toEqual(result.id);
+        expect(createdSupplier.name).toEqual(result.name);
+        expect(createdSupplier.account).toBeNull();
+        expect(createdSupplier.nif).toBeNull();
+        expect(createdSupplier.phone).toBeNull();
+        expect(createdSupplier.retAccount).toBeNull();
+        expect(createdSupplier.commission).toBeFalse();
+        expect(createdSupplier.created).toBeLessThanOrEqual(new Date);
+        expect(createdSupplier.postcodeFk).toBeNull();
+        expect(createdSupplier.isActive).toBeTrue();
+        expect(createdSupplier.isOfficial).toBeTrue();
+        expect(createdSupplier.isSerious).toBeTrue();
+        expect(createdSupplier.note).toBeNull();
+        expect(createdSupplier.street).toBeNull();
+        expect(createdSupplier.city).toBeNull();
+        expect(createdSupplier.provinceFk).toBeNull();
+        expect(createdSupplier.postCode).toBeNull();
+        expect(createdSupplier.payMethodFk).toBeNull();
+        expect(createdSupplier.payDemFk).toEqual(1);
+        expect(createdSupplier.payDay).toBeNull();
+        expect(createdSupplier.nickname).toEqual(result.name);
+        expect(createdSupplier.workerFk).toBeNull();
+        expect(createdSupplier.sageTaxTypeFk).toBeNull();
+        expect(createdSupplier.sageTransactionTypeFk).toBeNull();
+        expect(createdSupplier.sageWithholdingFk).toBeNull();
+        expect(createdSupplier.isPayMethodChecked).toBeFalse();
+        expect(createdSupplier.supplierActivityFk).toBeNull();
+        expect(createdSupplier.healthRegister).toBeNull();
     });
 });

From eb58839839dc7e9a560ce4bf21af876f998b57aa Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Mon, 17 Oct 2022 15:13:27 +0200
Subject: [PATCH 065/151] feat(invoiceIn): invoiceInPdf

---
 .../back/methods/invoice-in/invoiceInPdf.js   |  50 +++
 modules/invoiceIn/back/models/invoice-in.js   |   1 +
 modules/invoiceIn/front/descriptor/index.html |  27 +-
 modules/invoiceIn/front/descriptor/index.js   |   3 +
 .../reports/invoiceIn/assets/css/import.js    |  12 +
 .../reports/invoiceIn/assets/css/style.css    |  42 +++
 .../invoiceIn/assets/images/europe.png        | Bin 0 -> 55634 bytes
 .../reports/invoiceIn/invoiceIn.html          | 319 ++++++++++++++++++
 .../templates/reports/invoiceIn/invoiceIn.js  |  33 ++
 .../templates/reports/invoiceIn/locale/en.yml |  36 ++
 .../templates/reports/invoiceIn/locale/es.yml |  36 ++
 .../reports/invoiceIn/sql/invoice.sql         |   5 +
 12 files changed, 556 insertions(+), 8 deletions(-)
 create mode 100644 modules/invoiceIn/back/methods/invoice-in/invoiceInPdf.js
 create mode 100644 print/templates/reports/invoiceIn/assets/css/import.js
 create mode 100644 print/templates/reports/invoiceIn/assets/css/style.css
 create mode 100644 print/templates/reports/invoiceIn/assets/images/europe.png
 create mode 100644 print/templates/reports/invoiceIn/invoiceIn.html
 create mode 100755 print/templates/reports/invoiceIn/invoiceIn.js
 create mode 100644 print/templates/reports/invoiceIn/locale/en.yml
 create mode 100644 print/templates/reports/invoiceIn/locale/es.yml
 create mode 100644 print/templates/reports/invoiceIn/sql/invoice.sql

diff --git a/modules/invoiceIn/back/methods/invoice-in/invoiceInPdf.js b/modules/invoiceIn/back/methods/invoice-in/invoiceInPdf.js
new file mode 100644
index 0000000000..71ba5710e6
--- /dev/null
+++ b/modules/invoiceIn/back/methods/invoice-in/invoiceInPdf.js
@@ -0,0 +1,50 @@
+const {Report} = require('vn-print');
+
+module.exports = Self => {
+    Self.remoteMethodCtx('invoiceInPdf', {
+        description: 'Returns the delivery note pdf',
+        accessType: 'READ',
+        accepts: [
+            {
+                arg: 'id',
+                type: 'number',
+                required: true,
+                description: 'The ticket id',
+                http: {source: 'path'}
+            }
+        ],
+        returns: [
+            {
+                arg: 'body',
+                type: 'file',
+                root: true
+            }, {
+                arg: 'Content-Type',
+                type: 'String',
+                http: {target: 'header'}
+            }, {
+                arg: 'Content-Disposition',
+                type: 'String',
+                http: {target: 'header'}
+            }
+        ],
+        http: {
+            path: '/:id/invoiceInPdf',
+            verb: 'GET'
+        }
+    });
+
+    Self.invoiceInPdf = async(ctx, id) => {
+        const args = Object.assign({}, ctx.args);
+        const params = {lang: ctx.req.getLocale()};
+
+        delete args.ctx;
+        for (const param in args)
+            params[param] = args[param];
+
+        const report = new Report('invoiceIn', params);
+        const stream = await report.toPdfStream();
+
+        return [stream, 'application/pdf', `filename="doc-${id}.pdf"`];
+    };
+};
diff --git a/modules/invoiceIn/back/models/invoice-in.js b/modules/invoiceIn/back/models/invoice-in.js
index 3b5aa65d9f..e2c1326714 100644
--- a/modules/invoiceIn/back/models/invoice-in.js
+++ b/modules/invoiceIn/back/models/invoice-in.js
@@ -4,4 +4,5 @@ module.exports = Self => {
     require('../methods/invoice-in/clone')(Self);
     require('../methods/invoice-in/toBook')(Self);
     require('../methods/invoice-in/getTotals')(Self);
+    require('../methods/invoice-in/invoiceInPdf')(Self);
 };
diff --git a/modules/invoiceIn/front/descriptor/index.html b/modules/invoiceIn/front/descriptor/index.html
index 33f9ee8c65..c23a14ffc5 100644
--- a/modules/invoiceIn/front/descriptor/index.html
+++ b/modules/invoiceIn/front/descriptor/index.html
@@ -1,5 +1,5 @@
-<vn-descriptor-content 
-    module="invoiceIn" 
+<vn-descriptor-content
+    module="invoiceIn"
     description="$ctrl.invoiceIn.supplierRef"
     summary="$ctrl.$.summary">
     <slot-menu>
@@ -10,7 +10,6 @@
             translate>
             To book
         </vn-item>
-        
         <vn-item
             ng-click="deleteConfirmation.show()"
             vn-acl="administrative"
@@ -26,6 +25,18 @@
             translate>
             Clone Invoice
         </vn-item>
+        <vn-item
+            ng-if="!$ctrl.hasDocuwareFile"
+            ng-click="$ctrl.showPdfInvoice()"
+            translate>
+            Show Invoice as PDF
+        </vn-item>
+        <vn-item
+            ng-if="!$ctrl.hasDocuwareFile"
+            ng-click="$ctrl.showPdfInvoice()"
+            translate>
+            Send Invoice as PDF
+        </vn-item>
     </slot-menu>
     <slot-body>
         <div class="attributes">
@@ -37,7 +48,7 @@
             </vn-label-value>
             <vn-label-value label="Supplier">
                 <span ng-click="supplierDescriptor.show($event, $ctrl.invoiceIn.supplier.id)" class="link">
-                    {{$ctrl.invoiceIn.supplier.nickname}} 
+                    {{$ctrl.invoiceIn.supplier.nickname}}
                 </span>
             </vn-label-value>
         </div>
@@ -57,9 +68,9 @@
                     icon="icon-invoice-in">
                 </vn-quick-link>
             </div>
-           
+
         </div>
-        
+
     </slot-body>
 </vn-descriptor-content>
 <vn-confirm
@@ -75,11 +86,11 @@
 <vn-supplier-descriptor-popover
     vn-id="supplierDescriptor">
 </vn-supplier-descriptor-popover>
-<vn-confirm 
+<vn-confirm
     vn-id="confirm-toBookAnyway"
     message="Are you sure you want to book this invoice?"
     on-accept="$ctrl.onAcceptToBook()">
 </vn-confirm>
 <vn-popup vn-id="summary">
     <vn-invoice-in-summary invoice-in="$ctrl.invoiceIn"></vn-invoice-in-summary>
-</vn-popup>
\ No newline at end of file
+</vn-popup>
diff --git a/modules/invoiceIn/front/descriptor/index.js b/modules/invoiceIn/front/descriptor/index.js
index cde3242963..0198e868f2 100644
--- a/modules/invoiceIn/front/descriptor/index.js
+++ b/modules/invoiceIn/front/descriptor/index.js
@@ -96,6 +96,9 @@ class Controller extends Descriptor {
             .then(() => this.$state.reload())
             .then(() => this.vnApp.showSuccess(this.$t('InvoiceIn booked')));
     }
+    showPdfInvoice() {
+        this.vnReport.show(`InvoiceIns/${this.id}/invoiceInPdf`);
+    }
 }
 
 ngModule.vnComponent('vnInvoiceInDescriptor', {
diff --git a/print/templates/reports/invoiceIn/assets/css/import.js b/print/templates/reports/invoiceIn/assets/css/import.js
new file mode 100644
index 0000000000..37a98dfddb
--- /dev/null
+++ b/print/templates/reports/invoiceIn/assets/css/import.js
@@ -0,0 +1,12 @@
+const Stylesheet = require(`vn-print/core/stylesheet`);
+
+const path = require('path');
+const vnPrintPath = path.resolve('print');
+
+module.exports = new Stylesheet([
+    `${vnPrintPath}/common/css/spacing.css`,
+    `${vnPrintPath}/common/css/misc.css`,
+    `${vnPrintPath}/common/css/layout.css`,
+    `${vnPrintPath}/common/css/report.css`,
+    `${__dirname}/style.css`])
+    .mergeStyles();
diff --git a/print/templates/reports/invoiceIn/assets/css/style.css b/print/templates/reports/invoiceIn/assets/css/style.css
new file mode 100644
index 0000000000..9fda2a6138
--- /dev/null
+++ b/print/templates/reports/invoiceIn/assets/css/style.css
@@ -0,0 +1,42 @@
+h2 {
+    font-weight: 100;
+    color: #555
+}
+
+.table-title {
+    margin-bottom: 15px;
+    font-size: .8rem
+}
+
+.table-title h2 {
+    margin: 0 15px 0 0
+}
+
+.ticket-info {
+    font-size: 22px
+}
+
+
+#nickname h2 {
+    max-width: 400px;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+    overflow: hidden;
+}
+
+#phytosanitary {
+    padding-right: 10px
+}
+
+#phytosanitary .flag img {
+    width: 100%
+}
+
+#phytosanitary .flag .flag-text {
+    padding-left: 10px;
+    box-sizing: border-box;
+}
+
+.phytosanitary-info {
+    margin-top: 10px
+}
\ No newline at end of file
diff --git a/print/templates/reports/invoiceIn/assets/images/europe.png b/print/templates/reports/invoiceIn/assets/images/europe.png
new file mode 100644
index 0000000000000000000000000000000000000000..673be92ae2f0647fd1748e12a36bf073aa145d64
GIT binary patch
literal 55634
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

literal 0
HcmV?d00001

diff --git a/print/templates/reports/invoiceIn/invoiceIn.html b/print/templates/reports/invoiceIn/invoiceIn.html
new file mode 100644
index 0000000000..1d646a0db9
--- /dev/null
+++ b/print/templates/reports/invoiceIn/invoiceIn.html
@@ -0,0 +1,319 @@
+<!DOCTYPE html>
+<html v-bind:lang="$i18n.locale">
+    <body>
+        <table class="grid">
+            <tbody>
+                <tr>
+                    <td>
+
+                        <!-- Incoterms block -->
+                        <invoice-incoterms 
+                            v-if="hasIncoterms"
+                            v-bind="$props">
+                        </invoice-incoterms>
+
+                        <!-- Header block -->
+                        <report-header v-bind="$props"
+                            v-bind:company-code="invoice.companyCode">
+                        </report-header>
+                        <!-- Block -->
+                        <div class="grid-row">
+                            <div class="grid-block">
+                                <div class="columns vn-mb-lg">
+                                    <div class="size50">
+                                        <div class="size75 vn-mt-ml">
+                                            <h1 class="title uppercase">{{$t('title')}}</h1>
+                                            <table class="row-oriented ticket-info">
+                                                <tbody>
+                                                    <tr>
+                                                        <td class="font gray uppercase">{{$t('clientId')}}</td>
+                                                        <th>{{client.id}}</th>
+                                                    </tr>
+                                                    <tr>
+                                                        <td class="font gray uppercase">{{$t('invoice')}}</td>
+                                                        <th>{{invoice.ref}}</th>
+                                                    </tr>
+                                                    <tr>
+                                                        <td class="font gray uppercase">{{$t('date')}}</td>
+                                                        <th>{{invoice.issued | date('%d-%m-%Y')}}</th>
+                                                    </tr>
+                                                </tbody>
+                                            </table>
+                                        </div>
+                                    </div>
+                                    <div class="size50">
+                                        <div class="panel">
+                                            <div class="header">{{$t('invoiceData')}}</div>
+                                            <div class="body">
+                                                <h3 class="uppercase">{{client.socialName}}</h3>
+                                                <div>
+                                                    {{client.postalAddress}}
+                                                </div>
+                                                <div>
+                                                    {{client.postcodeCity}}
+                                                </div>
+                                                <div>
+                                                    {{$t('fiscalId')}}: {{client.fi}}
+                                                </div>
+                                            </div>
+                                        </div>
+                                    </div>
+                                </div>
+
+                                <!-- Rectified invoices block -->
+                                <div class="size100 no-page-break" v-if="rectified.length > 0">
+                                    <h2>{{$t('rectifiedInvoices')}}</h2>
+                                    <table class="column-oriented">
+                                        <thead>
+                                            <tr>
+                                                <th>{{$t('invoice')}}</th>
+                                                <th>{{$t('issued')}}</th>
+                                                <th class="number">{{$t('amount')}}</th>
+                                                <th width="50%">{{$t('description')}}</th>
+                                            </tr>
+                                        </thead>
+                                        <tbody>
+                                            <tr v-for="row in rectified">
+                                                <td>{{row.ref}}</td>
+                                                <td>{{row.issued | date}}</td>
+                                                <td class="number">{{row.amount | currency('EUR', $i18n.locale)}}</td>
+                                                <td width="50%">{{row.description}}</td>
+                                            </tr>
+                                        </tbody>
+                                    </table>
+                                </div>
+                                <!-- End of rectified invoices block -->
+                
+                                <!-- Sales block -->
+                                <div class="vn-mt-lg" v-for="ticket in tickets">
+                                    <div class="table-title clearfix">
+                                        <div class="pull-left">
+                                            <h2>{{$t('deliveryNote')}}</strong>
+                                        </div>
+                                        <div class="pull-left vn-mr-md">
+                                            <div class="field rectangle">
+                                                <span>{{ticket.id}}</span>
+                                            </div>
+                                        </div>
+                                        <div class="pull-left">
+                                            <h2>{{$t('shipped')}}</h2>
+                                        </div>
+                                        <div class="pull-left">
+                                            <div class="field rectangle">
+                                                <span>{{ticket.shipped | date}}</span>
+                                            </div>
+                                        </div>
+                                        <span id="nickname" class="pull-right">
+                                            <h2>{{ticket.nickname}}</h2>
+                                        </span>
+                                    </div>
+                                    <table class="column-oriented">
+                                        <thead>
+                                            <tr>
+                                                <th width="5%">{{$t('reference')}}</th>
+                                                <th class="number">{{$t('quantity')}}</th>
+                                                <th width="50%">{{$t('concept')}}</th>
+                                                <th class="number">{{$t('price')}}</th>
+                                                <th class="centered" width="5%">{{$t('discount')}}</th>
+                                                <th class="centered">{{$t('vat')}}</th>
+                                                <th class="number">{{$t('amount')}}</th>
+                                            </tr>
+                                        </thead>
+                                        <tbody v-for="sale in ticket.sales" class="no-page-break">
+                                            <tr>
+                                                <td width="5%">{{sale.itemFk | zerofill('000000')}}</td>
+                                                <td class="number">{{sale.quantity}}</td>
+                                                <td width="50%">{{sale.concept}}</td>
+                                                <td class="number">{{sale.price | currency('EUR', $i18n.locale)}}</td>
+                                                <td class="centered" width="5%">{{(sale.discount / 100) | percentage}}</td>
+                                                <td class="centered">{{sale.vatType}}</td>
+                                                <td class="number">{{saleImport(sale) | currency('EUR', $i18n.locale)}}</td>
+                                            </tr>
+                                            <tr class="description font light-gray">
+                                                <td colspan="7">
+                                                    <span v-if="sale.value5">
+                                                        <strong>{{sale.tag5}}</strong> {{sale.value5}}
+                                                    </span> 
+                                                    <span v-if="sale.value6">
+                                                        <strong>{{sale.tag6}}</strong> {{sale.value6}}
+                                                    </span> 
+                                                    <span v-if="sale.value7">
+                                                        <strong>{{sale.tag7}}</strong> {{sale.value7}}
+                                                    </span> 
+                                                </td>
+                                            </tr>
+                                        </tbody>
+                                        <tfoot>
+                                            <tr>
+                                                <td colspan="6" class="font bold">
+                                                    <span class="pull-right">{{$t('subtotal')}}</span>
+                                                </td>
+                                                <td class="number">{{ticketSubtotal(ticket) | currency('EUR', $i18n.locale)}}</td>
+                                            </tr>
+                                        </tfoot>
+                                    </table>
+                                </div>
+                                <!-- End of sales block -->
+                
+                                <div class="columns vn-mt-xl">
+                                    <!-- Taxes block -->
+                                    <div id="taxes" class="size50 pull-right no-page-break" v-if="taxes">
+                                        <table class="column-oriented">
+                                            <thead>
+                                                <tr>
+                                                    <th colspan="4">{{$t('taxBreakdown')}}</th>
+                                                </tr>
+                                            </thead>
+                                            <thead class="light">
+                                                <tr>
+                                                    <th width="45%">{{$t('type')}}</th>
+                                                    <th width="25%" class="number">
+                                                        {{$t('taxBase')}}
+                                                    </th>
+                                                    <th>{{$t('tax')}}</th>
+                                                    <th class="number">{{$t('fee')}}</th>
+                                                </tr>
+                                            </thead>
+                                            <tbody>
+                                                <tr v-for="tax in taxes">
+                                                    <td width="45%">{{tax.name}}</td>
+                                                    <td width="25%" class="number">
+                                                        {{tax.base | currency('EUR', $i18n.locale)}}
+                                                    </td>
+                                                    <td>{{tax.vatPercent | percentage}}</td>
+                                                    <td class="number">{{tax.vat | currency('EUR', $i18n.locale)}}</td>
+                                                </tr>
+                                            </tbody>
+                                            <tfoot>
+                                                <tr class="font bold">
+                                                    <td width="45%">{{$t('subtotal')}}</td>
+                                                    <td width="20%" class="number">
+                                                        {{sumTotal(taxes, 'base') | currency('EUR', $i18n.locale)}}
+                                                    </td>
+                                                    <td></td>
+                                                    <td class="number">{{sumTotal(taxes, 'vat') | currency('EUR', $i18n.locale)}}</td>
+                                                </tr>
+                                                <tr class="font bold">
+                                                    <td colspan="2">{{$t('total')}}</td>
+                                                    <td colspan="2" class="number">{{taxTotal | currency('EUR', $i18n.locale)}}</td>
+                                                </tr>
+                                            </tfoot>
+                                        </table>
+
+                                        <div class="panel" v-if="invoice.footNotes">
+                                            <div class="header">{{$t('notes')}}</div>
+                                            <div class="body">
+                                                <span>{{invoice.footNotes}}</span>
+                                            </div>
+                                        </div>
+                                    </div>
+                                    <!-- End of taxes block -->
+
+                                    <!-- Phytosanitary block -->
+                                    <div id="phytosanitary" class="size50 pull-left no-page-break">
+                                        <div class="panel">
+                                            <div class="body">
+                                                <div class="flag">
+                                                    <div class="columns">
+                                                        <div class="size25">
+                                                            <img v-bind:src="getReportSrc('europe.png')"/>
+                                                        </div>
+                                                        <div class="size75 flag-text">
+                                                            <strong>{{$t('plantPassport')}}</strong><br/>
+                                                        </div>
+                                                    </div>
+                                                </div>
+                                                <div class="phytosanitary-info">
+                                                    <div>
+                                                        <strong>A</strong> 
+                                                        <span>{{botanical}}</span>
+                                                    </div>
+                                                    <div>
+                                                        <strong>B</strong> 
+                                                        <span>ES17462130</span>                                                        
+                                                    </div>
+                                                    <div>
+                                                        <strong>C</strong> 
+                                                        <span>{{ticketsId}}</span>                                                        
+                                                    </div>
+                                                    <div>
+                                                        <strong>D</strong>
+                                                        <span>ES</span>
+                                                    </div>
+                                                </div>
+                                            </div>
+                                        </div>
+                                    </div>
+                                    <!-- End of phytosanitary block -->
+                                </div>
+
+                                
+                                <!-- Intrastat block -->
+                                <div class="size100 no-page-break" v-if="intrastat.length > 0">
+                                    <h2>{{$t('intrastat')}}</h2>
+                                    <table class="column-oriented">
+                                        <thead>
+                                            <tr>
+                                                <th>{{$t('code')}}</th>
+                                                <th width="50%">{{$t('description')}}</th>
+                                                <th class="number">{{$t('stems')}}</th>
+                                                <th class="number">{{$t('netKg')}}</th>
+                                                <th class="number">{{$t('amount')}}</th>
+                                            </tr>
+                                        </thead>
+                                        <tbody>
+                                            <tr v-for="row in intrastat">
+                                                <td>{{row.code}}</td>
+                                                <td width="50%">{{row.description}}</td>
+                                                <td class="number">{{row.stems | number($i18n.locale)}}</td>
+                                                <td class="number">{{row.netKg | number($i18n.locale)}}</td>
+                                                <td class="number">{{row.subtotal | currency('EUR', $i18n.locale)}}</td>
+                                            </tr>
+                                        </tbody>
+                                        <tfoot>
+                                            <tr>
+                                                <td colspan="2"></td>
+                                                <td class="number">
+                                                    <strong>{{sumTotal(intrastat, 'stems') | number($i18n.locale)}}</strong>
+                                                </td>
+                                                <td class="number">
+                                                    <strong>{{sumTotal(intrastat, 'netKg') | number($i18n.locale)}}</strong>
+                                                </td>
+                                                <td class="number">
+                                                    <strong>{{sumTotal(intrastat, 'subtotal') | currency('EUR', $i18n.locale)}}</strong>
+                                                </td>
+                                            </tr>
+                                        </tfoot>
+                                    </table>
+                                </div>
+                                <!-- End of intrastat block -->
+
+                                <!-- Observations block -->
+                                <div class="columns vn-mt-xl" v-if="invoice.payMethodCode == 'wireTransfer'">
+                                    <div class="size50 pull-left no-page-break" >
+                                        <div class="panel" >
+                                            <div class="header">{{$t('observations')}}</div>
+                                            <div class="body">
+                                                <div>{{$t('wireTransfer')}}</div>
+                                                <div>{{$t('accountNumber', [invoice.iban])}}</div>
+                                            </div>
+                                        </div>
+                                    </div>
+                                </div>
+                                <!-- End of observations block -->
+
+                            </div>
+                        </div>
+                        <!-- Footer block -->
+                        <report-footer id="pageFooter"
+                            v-bind:company-code="invoice.companyCode"
+                            v-bind:left-text="$t('invoiceRef', [invoice.ref])"
+                            v-bind:center-text="client.socialName"
+                            v-bind="$props">
+                        </report-footer>
+                    </td>
+                </tr>
+            </tbody>
+        </table>
+    </body>
+</html>
\ No newline at end of file
diff --git a/print/templates/reports/invoiceIn/invoiceIn.js b/print/templates/reports/invoiceIn/invoiceIn.js
new file mode 100755
index 0000000000..3fed1b867e
--- /dev/null
+++ b/print/templates/reports/invoiceIn/invoiceIn.js
@@ -0,0 +1,33 @@
+const Component = require(`vn-print/core/component`);
+const Report = require(`vn-print/core/report`);
+const reportHeader = new Component('report-header');
+const reportFooter = new Component('report-footer');
+const invoiceIncoterms = new Report('invoice-incoterms');
+
+module.exports = {
+    name: 'invoiceIn',
+    async serverPrefetch() {
+        this.invoice = await this.fetchInvoice(this.id);
+
+        if (!this.invoice)
+            throw new Error('Something went wrong');
+    },
+    computed: {
+    },
+    methods: {
+        fetchInvoice(id) {
+            return this.findOneFromDef('invoice', [id]);
+        }
+    },
+    components: {
+        'report-header': reportHeader.build(),
+        'report-footer': reportFooter.build(),
+        'invoice-incoterms': invoiceIncoterms.build()
+    },
+    props: {
+        id: {
+            type: [Number, String],
+            description: 'The invoice id'
+        }
+    }
+};
diff --git a/print/templates/reports/invoiceIn/locale/en.yml b/print/templates/reports/invoiceIn/locale/en.yml
new file mode 100644
index 0000000000..4e4688b554
--- /dev/null
+++ b/print/templates/reports/invoiceIn/locale/en.yml
@@ -0,0 +1,36 @@
+reportName: invoice
+title: Invoice
+invoice: Invoice
+clientId: Client
+invoiceData: Invoice data
+fiscalId: FI / NIF
+invoiceRef: Invoice {0}
+deliveryNote: Delivery note
+shipped: Shipped
+date: Date
+reference: Ref.
+quantity: Qty.
+concept: Concept
+price: PSP/u
+discount: Disc.
+vat: VAT
+amount: Amount
+type: Type
+taxBase: Tax base
+tax: Tax
+fee: Fee
+total: Total
+subtotal: Subtotal
+taxBreakdown: Tax breakdown
+notes: Notes
+intrastat: Intrastat
+code: Code
+description: Description
+stems: Stems
+netKg: Net kg
+rectifiedInvoices: Rectified invoices
+issued: Issued
+plantPassport: Plant passport
+observations: Observations
+wireTransfer: "Pay method: Transferencia"
+accountNumber: "Account number: {0}"
\ No newline at end of file
diff --git a/print/templates/reports/invoiceIn/locale/es.yml b/print/templates/reports/invoiceIn/locale/es.yml
new file mode 100644
index 0000000000..d37e77943f
--- /dev/null
+++ b/print/templates/reports/invoiceIn/locale/es.yml
@@ -0,0 +1,36 @@
+reportName: factura
+title: Factura
+invoice: Factura
+clientId: Cliente
+invoiceData: Datos de facturación
+fiscalId: CIF / NIF
+invoiceRef: Factura {0}
+deliveryNote: Albarán
+shipped: F. envío
+date: Fecha
+reference: Ref.
+quantity: Cant.
+concept: Concepto
+price: PVP/u
+discount: Dto.
+vat: IVA
+amount: Importe
+type: Tipo
+taxBase: Base imp.
+tax: Tasa
+fee: Cuota
+total: Total
+subtotal: Subtotal
+taxBreakdown: Desglose impositivo
+notes: Notas
+intrastat: Intrastat
+code: Código
+description: Descripción
+stems: Tallos
+netKg: KG Neto
+rectifiedInvoices: Facturas rectificadas
+issued: F. emisión
+plantPassport: Pasaporte fitosanitario
+observations: Observaciones
+wireTransfer: "Forma de pago: Transferencia"
+accountNumber: "Número de cuenta: {0}"
\ No newline at end of file
diff --git a/print/templates/reports/invoiceIn/sql/invoice.sql b/print/templates/reports/invoiceIn/sql/invoice.sql
new file mode 100644
index 0000000000..e6b1eb9956
--- /dev/null
+++ b/print/templates/reports/invoiceIn/sql/invoice.sql
@@ -0,0 +1,5 @@
+SELECT *
+	FROM invoiceIn i
+		JOIN supplier s ON s.id = i.supplierFk
+		JOIN company c ON c.id = i.companyFk
+    WHERE i.id = ?

From 047076f189097be54cf7dc500d29da8d3aaba1ce Mon Sep 17 00:00:00 2001
From: Pau Navarro <pau@verdnatura.es>
Date: Tue, 18 Oct 2022 07:14:40 +0200
Subject: [PATCH 066/151] changed tests

---
 .../supplier/back/methods/supplier/specs/newSupplier.spec.js    | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/modules/supplier/back/methods/supplier/specs/newSupplier.spec.js b/modules/supplier/back/methods/supplier/specs/newSupplier.spec.js
index a4ccd05ac9..aacb2d42dd 100644
--- a/modules/supplier/back/methods/supplier/specs/newSupplier.spec.js
+++ b/modules/supplier/back/methods/supplier/specs/newSupplier.spec.js
@@ -23,7 +23,7 @@ describe('Supplier newSupplier()', () => {
         expect(createdSupplier.phone).toBeNull();
         expect(createdSupplier.retAccount).toBeNull();
         expect(createdSupplier.commission).toBeFalse();
-        expect(createdSupplier.created).toBeLessThanOrEqual(new Date);
+        expect(createdSupplier.created).toBeDefined();
         expect(createdSupplier.postcodeFk).toBeNull();
         expect(createdSupplier.isActive).toBeTrue();
         expect(createdSupplier.isOfficial).toBeTrue();

From 1d8fb253254962613d1ac2e7f879a4e3ad74186e Mon Sep 17 00:00:00 2001
From: Pau Navarro <pau@verdnatura.es>
Date: Tue, 18 Oct 2022 10:25:54 +0200
Subject: [PATCH 067/151] Refactored according to the suggested changes

---
 .../methods/worker/workerDisableExcluded.js   | 30 -------------
 .../worker/workerExcludeFromDisable.js        | 45 -------------------
 modules/worker/back/models/worker.js          |  2 -
 modules/worker/front/descriptor/index.html    | 11 +++--
 modules/worker/front/descriptor/index.js      | 24 ++++++----
 modules/worker/front/locale/es.yml            |  5 ++-
 6 files changed, 24 insertions(+), 93 deletions(-)
 delete mode 100644 modules/worker/back/methods/worker/workerDisableExcluded.js
 delete mode 100644 modules/worker/back/methods/worker/workerExcludeFromDisable.js

diff --git a/modules/worker/back/methods/worker/workerDisableExcluded.js b/modules/worker/back/methods/worker/workerDisableExcluded.js
deleted file mode 100644
index 017e044c25..0000000000
--- a/modules/worker/back/methods/worker/workerDisableExcluded.js
+++ /dev/null
@@ -1,30 +0,0 @@
-
-module.exports = Self => {
-    Self.remoteMethod('workerDisableExcluded', {
-        description: 'Check if the worker can be disabled',
-        accessType: 'READ',
-        accepts: {
-            arg: 'id',
-            type: 'Number',
-            required: true,
-            description: `The worker id`,
-            http: {source: 'path'}
-        },
-        returns: {
-            type: 'boolean',
-            root: true
-        },
-        http: {
-            path: `/workerDisableExcluded/:id`,
-            verb: 'GET'
-        }
-    });
-
-    Self.workerDisableExcluded = async id => {
-        let result;
-        const query = `Select * from vn.workerDisableExcluded where workerFk like ${id}`;
-        let sqlResult = await Self.rawSql(query);
-        sqlResult.length == 0 ? result = false : result = true;
-        return result;
-    };
-};
diff --git a/modules/worker/back/methods/worker/workerExcludeFromDisable.js b/modules/worker/back/methods/worker/workerExcludeFromDisable.js
deleted file mode 100644
index 86d940862d..0000000000
--- a/modules/worker/back/methods/worker/workerExcludeFromDisable.js
+++ /dev/null
@@ -1,45 +0,0 @@
-module.exports = Self => {
-    Self.remoteMethod('workerExcludeFromDisable', {
-        description: 'Change the status of the worker between can be disabled and cant be disabled',
-        accessType: 'READ',
-        accepts: [{
-            arg: 'id',
-            type: 'Number',
-            required: true,
-            description: `The worker id`,
-            http: {source: 'path'}
-        },
-        {
-            arg: 'currValue',
-            type: 'Boolean',
-            required: true,
-            description: `The current value of workerDisableExcluded`,
-            http: {source: 'path'}
-        }],
-        returns: {
-            type: 'boolean',
-            root: true
-        },
-        http: {
-            path: `/workerExcludeFromDisable/:id/:currValue`,
-            verb: 'GET'
-        }
-    });
-
-    Self.workerExcludeFromDisable = async(id, currValue) => {
-        const models = Self.app.models;
-
-        if (!currValue) {
-            await models.WorkerDisableExcluded.create({
-                workerFk: id,
-                dated: new Date()
-            });
-        } else {
-            await models.WorkerDisableExcluded.remove({
-                workerFk: id
-            });
-        }
-
-        return false;
-    };
-};
diff --git a/modules/worker/back/models/worker.js b/modules/worker/back/models/worker.js
index c90729779a..ec6c4af282 100644
--- a/modules/worker/back/models/worker.js
+++ b/modules/worker/back/models/worker.js
@@ -13,6 +13,4 @@ module.exports = Self => {
     require('../methods/worker/contracts')(Self);
     require('../methods/worker/holidays')(Self);
     require('../methods/worker/activeContract')(Self);
-    require('../methods/worker/workerDisableExcluded')(Self);
-    require('../methods/worker/workerExcludeFromDisable')(Self);
 };
diff --git a/modules/worker/front/descriptor/index.html b/modules/worker/front/descriptor/index.html
index c60801bb98..58ac3d9e6e 100644
--- a/modules/worker/front/descriptor/index.html
+++ b/modules/worker/front/descriptor/index.html
@@ -15,18 +15,17 @@
         </div>
     </slot-before>
     <slot-menu>
-         <!--ng-if="!$ctrl.canBeExcluded"-->
          <vn-item
-            ng-click="$ctrl.setExcluded()"
+            ng-click="$ctrl.handleExcluded()"
             translate
             ng-if="!$ctrl.excluded">
-            Marcar para no deshabilitar
+            Click to exclude the user from getting disabled
         </vn-item>
         <vn-item
-            ng-click="$ctrl.setExcluded()"
+            ng-click="$ctrl.handleExcluded()"
             translate
             ng-if="$ctrl.excluded">
-            Marcar como deshabilitable
+            Click to allow the user to be disabled 
         </vn-item>
     </slot-menu>
     <slot-body>
@@ -54,7 +53,7 @@
         </div>
         <div class="icons">
             <vn-icon
-                vn-tooltip="Fijado para no deshabilitar"
+                vn-tooltip="This user can't be disabled"
                 icon="person"
                 ng-if="$ctrl.worker.excluded">
             </vn-icon>
diff --git a/modules/worker/front/descriptor/index.js b/modules/worker/front/descriptor/index.js
index 7a3922a089..2ff032def7 100644
--- a/modules/worker/front/descriptor/index.js
+++ b/modules/worker/front/descriptor/index.js
@@ -5,7 +5,6 @@ class Controller extends Descriptor {
     constructor($element, $, $rootScope) {
         super($element, $);
         this.$rootScope = $rootScope;
-        this.canBeExcluded();
     }
 
     get worker() {
@@ -14,6 +13,9 @@ class Controller extends Descriptor {
 
     set worker(value) {
         this.entity = value;
+
+        if (value)
+            this.getIsExcluded();
     }
 
     get excluded() {
@@ -22,18 +24,22 @@ class Controller extends Descriptor {
 
     set excluded(value) {
         this.entity.excluded = value;
-        this.$rootScope.$apply();
     }
 
-    async canBeExcluded() {
-        await new Promise(r => setTimeout(r, 500));
-        let data = await this.$http.get(`Workers/workerDisableExcluded/${this.entity.id}`);
-        this.excluded = data.data;
+    getIsExcluded() {
+        this.$http.get(`workerDisableExcludeds/${this.entity.id}/exists`).then(data => {
+            this.excluded = data.data.exists;
+        });
     }
 
-    async setExcluded() {
-        await this.$http.get(`Workers/workerExcludeFromDisable/${this.entity.id}/${this.entity.excluded}`);
-        this.excluded = !this.entity.excluded;
+    handleExcluded() {
+        if (this.excluded) {
+            this.$http.delete(`workerDisableExcludeds/${this.entity.id}`);
+            this.excluded = false;
+        } else {
+            this.$http.post(`workerDisableExcludeds`, {workerFk: this.entity.id, dated: new Date});
+            this.excluded = true;
+        }
     }
 
     loadData() {
diff --git a/modules/worker/front/locale/es.yml b/modules/worker/front/locale/es.yml
index 1414d089bc..672f4c52f9 100644
--- a/modules/worker/front/locale/es.yml
+++ b/modules/worker/front/locale/es.yml
@@ -20,4 +20,7 @@ View worker: Ver trabajador
 Worker id: Id trabajador
 Workers: Trabajadores
 worker: trabajador
-Go to the worker: Ir al trabajador
\ No newline at end of file
+Go to the worker: Ir al trabajador
+Click to exclude the user from getting disabled: Marcar para no deshabilitar
+Click to allow the user to be disabled: Marcar para deshabilitar
+This user can't be disabled: Fijado para no deshabilitar
\ No newline at end of file

From c9e9e3545d664104d415ffc34cee1d820bc48c6c Mon Sep 17 00:00:00 2001
From: Pau Navarro <pau@verdnatura.es>
Date: Tue, 18 Oct 2022 10:33:48 +0200
Subject: [PATCH 068/151] Added ACL

---
 .../00-ACL_workerDisableExcluded.sql          | 20 +++++++++++++++++++
 db/changes/10491-august/delete.keep           |  0
 2 files changed, 20 insertions(+)
 create mode 100644 db/changes/10491-august/00-ACL_workerDisableExcluded.sql
 delete mode 100644 db/changes/10491-august/delete.keep

diff --git a/db/changes/10491-august/00-ACL_workerDisableExcluded.sql b/db/changes/10491-august/00-ACL_workerDisableExcluded.sql
new file mode 100644
index 0000000000..48fb4bb35c
--- /dev/null
+++ b/db/changes/10491-august/00-ACL_workerDisableExcluded.sql
@@ -0,0 +1,20 @@
+INSERT INTO
+    salix.ACL (
+        id,
+        model,
+        property,
+        accessType,
+        permission,
+        principalType,
+        principalId
+    )
+VALUES
+(
+        344,
+        'workerDisableExcluded',
+        '*',
+        '*',
+        'ALLOW',
+        'ROLE',
+        'employee'
+    );
\ No newline at end of file
diff --git a/db/changes/10491-august/delete.keep b/db/changes/10491-august/delete.keep
deleted file mode 100644
index e69de29bb2..0000000000

From f481cc3c97f2cc68f480863a97be13a7240bddc8 Mon Sep 17 00:00:00 2001
From: Pau Navarro <pau@verdnatura.es>
Date: Tue, 18 Oct 2022 10:38:40 +0200
Subject: [PATCH 069/151] Capitalizar

---
 db/changes/10491-august/00-ACL_workerDisableExcluded.sql | 2 +-
 modules/worker/back/model-config.json                    | 2 +-
 modules/worker/back/models/workerDisableExcluded.json    | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/db/changes/10491-august/00-ACL_workerDisableExcluded.sql b/db/changes/10491-august/00-ACL_workerDisableExcluded.sql
index 48fb4bb35c..3d84c751c8 100644
--- a/db/changes/10491-august/00-ACL_workerDisableExcluded.sql
+++ b/db/changes/10491-august/00-ACL_workerDisableExcluded.sql
@@ -11,7 +11,7 @@ INSERT INTO
 VALUES
 (
         344,
-        'workerDisableExcluded',
+        'WorkerDisableExcluded',
         '*',
         '*',
         'ALLOW',
diff --git a/modules/worker/back/model-config.json b/modules/worker/back/model-config.json
index a41997908f..8c11c0d717 100644
--- a/modules/worker/back/model-config.json
+++ b/modules/worker/back/model-config.json
@@ -65,7 +65,7 @@
     "WorkerTimeControlMail": {
         "dataSource": "vn"
     },
-    "workerDisableExcluded": {
+    "WorkerDisableExcluded": {
         "dataSource": "vn"
     }
 }
diff --git a/modules/worker/back/models/workerDisableExcluded.json b/modules/worker/back/models/workerDisableExcluded.json
index cfa810e437..48083748d2 100644
--- a/modules/worker/back/models/workerDisableExcluded.json
+++ b/modules/worker/back/models/workerDisableExcluded.json
@@ -1,5 +1,5 @@
 {
-	"name": "workerDisableExcluded",
+	"name": "WorkerDisableExcluded",
 	"base": "VnModel",
 	"options": {
 		"mysql": {

From 81088bc4959c5173802416902847c118631a555d Mon Sep 17 00:00:00 2001
From: Pau Navarro <pau@verdnatura.es>
Date: Tue, 18 Oct 2022 10:46:14 +0200
Subject: [PATCH 070/151] Fixed ACL

---
 .../00-ACL_workerDisableExcluded.sql          | 22 ++-----------------
 1 file changed, 2 insertions(+), 20 deletions(-)

diff --git a/db/changes/10491-august/00-ACL_workerDisableExcluded.sql b/db/changes/10491-august/00-ACL_workerDisableExcluded.sql
index 3d84c751c8..7a23ca68a6 100644
--- a/db/changes/10491-august/00-ACL_workerDisableExcluded.sql
+++ b/db/changes/10491-august/00-ACL_workerDisableExcluded.sql
@@ -1,20 +1,2 @@
-INSERT INTO
-    salix.ACL (
-        id,
-        model,
-        property,
-        accessType,
-        permission,
-        principalType,
-        principalId
-    )
-VALUES
-(
-        344,
-        'WorkerDisableExcluded',
-        '*',
-        '*',
-        'ALLOW',
-        'ROLE',
-        'employee'
-    );
\ No newline at end of file
+INSERT INTO `salix`.`ACL` (model,property,accessType,permission,principalId)
+	VALUES ('WorkerDisableExcluded','*','*','ALLOW','employee');

From 423454d19ea755b1ebc1667c1ebbb6830a7bfb80 Mon Sep 17 00:00:00 2001
From: vicent <vicent@verdnatura.es>
Date: Tue, 18 Oct 2022 11:47:22 +0200
Subject: [PATCH 071/151] feat: add date-picker

---
 modules/ticket/front/expedition/index.html | 20 ++++++++++++--------
 modules/ticket/front/expedition/index.js   | 15 ++++++++++-----
 2 files changed, 22 insertions(+), 13 deletions(-)

diff --git a/modules/ticket/front/expedition/index.html b/modules/ticket/front/expedition/index.html
index 35f56872c2..f4b2615339 100644
--- a/modules/ticket/front/expedition/index.html
+++ b/modules/ticket/front/expedition/index.html
@@ -138,25 +138,29 @@
 
 <vn-menu vn-id="moreOptions">
     <vn-item translate
-        name="sms"
-        ng-click="$ctrl.createTicket()">
+        name="withoutRoute"
+        ng-click="selectLanded.show('withoutRoute')">
         New ticket without route
     </vn-item>
     <vn-item translate
-        name="calculatePrice"
-        ng-click="selectRoute.show()">
+        name="withRoute"
+        ng-click="selectLanded.show('withRoute')">
         New ticket with route
     </vn-item>
 </vn-menu>
 
 <vn-dialog 
-    vn-id="selectRoute"
-    on-accept="$ctrl.createTicket($ctrl.ticket.newRoute)">
+    vn-id="selectLanded"
+    on-accept="$ctrl.createTicket($ctrl.landed, $ctrl.newRoute)">
     <tpl-body>
+        <vn-date-picker
+            label="Landed" 
+            ng-model="$ctrl.landed">
+        </vn-date-picker>
         <vn-textfield
-            vn-one
+            ng-show="selectLanded.data == 'withRoute'"
             label="Id route"
-            ng-model="$ctrl.ticket.newRoute">
+            ng-model="$ctrl.newRoute">
         </vn-textfield>
     </tpl-body>
     <tpl-buttons>
diff --git a/modules/ticket/front/expedition/index.js b/modules/ticket/front/expedition/index.js
index f7674716b1..49ba3280d7 100644
--- a/modules/ticket/front/expedition/index.js
+++ b/modules/ticket/front/expedition/index.js
@@ -2,6 +2,12 @@ import ngModule from '../module';
 import Section from 'salix/components/section';
 
 class Controller extends Section {
+    constructor($element, $scope) {
+        super($element, $scope);
+        this.landed = new Date();
+        this.newRoute = null;
+    }
+
     get checked() {
         const rows = this.$.model.data || [];
         const checkedRows = [];
@@ -28,7 +34,7 @@ class Controller extends Section {
     }
 
     onRemove() {
-        const params = {expeditionsIds: this.checked};
+        const params = {expeditionIds: this.checked};
         const query = `Expeditions/deleteExpeditions`;
         this.$http.post(query, params)
             .then(() => {
@@ -37,11 +43,10 @@ class Controller extends Section {
             });
     }
 
-    createTicket(routeFk) {
-        const date = new Date(); // esta fecha hay que preguntarla a Fran Monsalvez
+    createTicket(landed, routeFk) {
         const ticketParams = {
             clientId: this.ticket.clientFk,
-            landed: date,
+            landed: landed,
             addressId: this.ticket.addressFk,
             agencyModeId: this.ticket.agencyModeFk,
             warehouseId: this.ticket.warehouseFk
@@ -50,7 +55,7 @@ class Controller extends Section {
         this.$http.post(query, ticketParams).then(res => {
             if (routeFk) this.$http.patch(`Tickets/${res.data.id}`, {routeFk: routeFk});
             const params = {
-                expeditionsIds: this.checked,
+                expeditionIds: this.checked,
                 ticketId: res.data.id
             };
             const query = `Expeditions/moveExpeditions`;

From 5fce93abd5bd36720eec2ffa6d7df0f0ec3cbcd4 Mon Sep 17 00:00:00 2001
From: vicent <vicent@verdnatura.es>
Date: Tue, 18 Oct 2022 11:47:37 +0200
Subject: [PATCH 072/151] refactor: change variables name

---
 modules/ticket/back/methods/expedition/deleteExpeditions.js | 6 +++---
 modules/ticket/back/methods/expedition/moveExpeditions.js   | 6 +++---
 modules/ticket/front/expedition/index.spec.js               | 4 ++--
 modules/ticket/front/expedition/locale/es.yml               | 3 ++-
 4 files changed, 10 insertions(+), 9 deletions(-)

diff --git a/modules/ticket/back/methods/expedition/deleteExpeditions.js b/modules/ticket/back/methods/expedition/deleteExpeditions.js
index b902b9f0c5..5b9d0daaa3 100644
--- a/modules/ticket/back/methods/expedition/deleteExpeditions.js
+++ b/modules/ticket/back/methods/expedition/deleteExpeditions.js
@@ -4,7 +4,7 @@ module.exports = Self => {
         description: 'Delete the selected expeditions',
         accessType: 'WRITE',
         accepts: [{
-            arg: 'expeditionsIds',
+            arg: 'expeditionIds',
             type: ['number'],
             required: true,
             description: 'The expeditions ids to delete'
@@ -19,7 +19,7 @@ module.exports = Self => {
         }
     });
 
-    Self.deleteExpeditions = async(expeditionsIds, options) => {
+    Self.deleteExpeditions = async(expeditionIds, options) => {
         const models = Self.app.models;
         const myOptions = {};
         let tx;
@@ -34,7 +34,7 @@ module.exports = Self => {
 
         try {
             const deletedExpeditions = await models.Expedition.destroyAll({
-                id: {inq: expeditionsIds}
+                id: {inq: expeditionIds}
             }, myOptions);
 
             if (tx) await tx.commit();
diff --git a/modules/ticket/back/methods/expedition/moveExpeditions.js b/modules/ticket/back/methods/expedition/moveExpeditions.js
index 2c521dda7c..338568fdb4 100644
--- a/modules/ticket/back/methods/expedition/moveExpeditions.js
+++ b/modules/ticket/back/methods/expedition/moveExpeditions.js
@@ -4,7 +4,7 @@ module.exports = Self => {
         description: 'Move the selected expeditions to another ticket',
         accessType: 'WRITE',
         accepts: [{
-            arg: 'expeditionsIds',
+            arg: 'expeditionIds',
             type: ['number'],
             required: true,
             description: 'The expeditions ids to nove'
@@ -25,7 +25,7 @@ module.exports = Self => {
         }
     });
 
-    Self.moveExpeditions = async(expeditionsIds, ticketId, options) => {
+    Self.moveExpeditions = async(expeditionIds, ticketId, options) => {
         const models = Self.app.models;
         const myOptions = {};
         let tx;
@@ -40,7 +40,7 @@ module.exports = Self => {
 
         try {
             const promises = [];
-            for (let expeditionsId of expeditionsIds) {
+            for (let expeditionsId of expeditionIds) {
                 const expeditionToUpdate = await models.Expedition.findById(expeditionsId);
                 const expeditionUpdated = expeditionToUpdate.updateAttribute('ticketFk', ticketId, myOptions);
                 promises.push(expeditionUpdated);
diff --git a/modules/ticket/front/expedition/index.spec.js b/modules/ticket/front/expedition/index.spec.js
index fe23046ce2..ad5dafbd7b 100644
--- a/modules/ticket/front/expedition/index.spec.js
+++ b/modules/ticket/front/expedition/index.spec.js
@@ -63,7 +63,7 @@ describe('Ticket', () => {
             it('should make a query and then call to the model refresh() method', () => {
                 jest.spyOn($scope.model, 'refresh');
 
-                const expectedParams = {expeditionsIds: [1, 2]};
+                const expectedParams = {expeditionIds: [1, 2]};
                 $httpBackend.expect('POST', 'Expeditions/deleteExpeditions', expectedParams).respond(200);
                 controller.onRemove();
                 $httpBackend.flush();
@@ -97,7 +97,7 @@ describe('Ticket', () => {
                 const expectedResponse = {id: ticketIdToTransfer};
 
                 const expectedParams = {
-                    expeditionsIds: [1, 2],
+                    expeditionIds: [1, 2],
                     ticketId: 28
                 };
                 $httpBackend.expect('POST', 'Tickets/new', expectedTicket).respond(expectedResponse);
diff --git a/modules/ticket/front/expedition/locale/es.yml b/modules/ticket/front/expedition/locale/es.yml
index bc3ec33455..68812f9850 100644
--- a/modules/ticket/front/expedition/locale/es.yml
+++ b/modules/ticket/front/expedition/locale/es.yml
@@ -2,4 +2,5 @@ Status log: Hitorial de estados
 Expedition removed: Expedición eliminada
 Move: Mover
 New ticket without route: Nuevo ticket sin ruta
-New ticket with route: Nuevo ticket con ruta
\ No newline at end of file
+New ticket with route: Nuevo ticket con ruta
+Id route: Id ruta
\ No newline at end of file

From a204c6e2b09738acbf01bc6fd0bd44a1f729ce88 Mon Sep 17 00:00:00 2001
From: Pau Navarro <pau@verdnatura.es>
Date: Tue, 18 Oct 2022 12:29:04 +0200
Subject: [PATCH 073/151] Fixed the suppliers not appearing

---
 .../10491-august/00-defaultPayDem_sameAs_production.sql  | 2 ++
 .../00-defaultSupplierActivityFk_to_Null.sql             | 1 +
 .../10491-august/00-newSupplier_Modify_supplier.sql      | 9 ---------
 db/changes/10491-august/00-payMethodFk_Allow_Null.sql    | 1 +
 .../10491-august/00-supplierActivityFk_Allow_Null.sql    | 1 +
 modules/supplier/back/methods/supplier/filter.js         | 4 ++--
 modules/supplier/back/methods/supplier/newSupplier.js    | 2 --
 .../back/methods/supplier/specs/newSupplier.spec.js      | 3 +--
 8 files changed, 8 insertions(+), 15 deletions(-)
 create mode 100644 db/changes/10491-august/00-defaultPayDem_sameAs_production.sql
 create mode 100644 db/changes/10491-august/00-defaultSupplierActivityFk_to_Null.sql
 delete mode 100644 db/changes/10491-august/00-newSupplier_Modify_supplier.sql
 create mode 100644 db/changes/10491-august/00-payMethodFk_Allow_Null.sql
 create mode 100644 db/changes/10491-august/00-supplierActivityFk_Allow_Null.sql

diff --git a/db/changes/10491-august/00-defaultPayDem_sameAs_production.sql b/db/changes/10491-august/00-defaultPayDem_sameAs_production.sql
new file mode 100644
index 0000000000..2a7f5c61f7
--- /dev/null
+++ b/db/changes/10491-august/00-defaultPayDem_sameAs_production.sql
@@ -0,0 +1,2 @@
+INSERT INTO vn.payDem (id,payDem)
+	VALUES (7,'0');
diff --git a/db/changes/10491-august/00-defaultSupplierActivityFk_to_Null.sql b/db/changes/10491-august/00-defaultSupplierActivityFk_to_Null.sql
new file mode 100644
index 0000000000..1fc4e29058
--- /dev/null
+++ b/db/changes/10491-august/00-defaultSupplierActivityFk_to_Null.sql
@@ -0,0 +1 @@
+ALTER TABLE vn.supplier MODIFY COLUMN supplierActivityFk varchar(45) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL NULL;
diff --git a/db/changes/10491-august/00-newSupplier_Modify_supplier.sql b/db/changes/10491-august/00-newSupplier_Modify_supplier.sql
deleted file mode 100644
index 29a1884809..0000000000
--- a/db/changes/10491-august/00-newSupplier_Modify_supplier.sql
+++ /dev/null
@@ -1,9 +0,0 @@
-ALTER TABLE `vn`.`supplier` MODIFY COLUMN payMethodFk tinyint(3) unsigned DEFAULT NULL NULL;
-
-/* ------------------------------------------------------------------------------------------- */
-
-ALTER TABLE `vn`.`supplier` MODIFY COLUMN supplierActivityFk varchar(45) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL NULL;
-
-/* ------------------------------------------------------------------------------------------- */
-
-ALTER TABLE `vn`.`supplierLog` MODIFY COLUMN userFk int(10) unsigned NULL;
diff --git a/db/changes/10491-august/00-payMethodFk_Allow_Null.sql b/db/changes/10491-august/00-payMethodFk_Allow_Null.sql
new file mode 100644
index 0000000000..6fd2fee6ed
--- /dev/null
+++ b/db/changes/10491-august/00-payMethodFk_Allow_Null.sql
@@ -0,0 +1 @@
+ALTER TABLE vn.supplier MODIFY COLUMN payMethodFk tinyint(3) unsigned NULL;
diff --git a/db/changes/10491-august/00-supplierActivityFk_Allow_Null.sql b/db/changes/10491-august/00-supplierActivityFk_Allow_Null.sql
new file mode 100644
index 0000000000..6f4cdcc398
--- /dev/null
+++ b/db/changes/10491-august/00-supplierActivityFk_Allow_Null.sql
@@ -0,0 +1 @@
+ALTER TABLE vn.supplier MODIFY COLUMN supplierActivityFk varchar(45) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT 'flowersPlants' NULL;
diff --git a/modules/supplier/back/methods/supplier/filter.js b/modules/supplier/back/methods/supplier/filter.js
index 3500afacd1..0b473f7df8 100644
--- a/modules/supplier/back/methods/supplier/filter.js
+++ b/modules/supplier/back/methods/supplier/filter.js
@@ -95,8 +95,8 @@ module.exports = Self => {
                     pm.name AS payMethod,
                     pd.payDem AS payDem
                 FROM vn.supplier s
-                    JOIN vn.payMethod pm ON pm.id = s.payMethodFk
-                    JOIN vn.payDem pd ON pd.id = s.payDemFk`
+                    LEFT JOIN vn.payMethod pm ON pm.id = s.payMethodFk
+                    LEFT JOIN vn.payDem pd ON pd.id = s.payDemFk`
         );
 
         stmt.merge(conn.makeSuffix(filter));
diff --git a/modules/supplier/back/methods/supplier/newSupplier.js b/modules/supplier/back/methods/supplier/newSupplier.js
index 748d7f5ee6..0395e982bf 100644
--- a/modules/supplier/back/methods/supplier/newSupplier.js
+++ b/modules/supplier/back/methods/supplier/newSupplier.js
@@ -24,7 +24,6 @@ module.exports = Self => {
         if (typeof(params) == 'string')
             params = JSON.parse(params);
 
-        params.payDemFk = 1;
         params.nickname = params.name;
 
         if (!myOptions.transaction) {
@@ -42,7 +41,6 @@ module.exports = Self => {
             };
         } catch (e) {
             if (tx) await tx.rollback();
-            return params;
         }
     };
 };
diff --git a/modules/supplier/back/methods/supplier/specs/newSupplier.spec.js b/modules/supplier/back/methods/supplier/specs/newSupplier.spec.js
index aacb2d42dd..b252c4d60e 100644
--- a/modules/supplier/back/methods/supplier/specs/newSupplier.spec.js
+++ b/modules/supplier/back/methods/supplier/specs/newSupplier.spec.js
@@ -11,7 +11,6 @@ describe('Supplier newSupplier()', () => {
         result = result.supplier;
 
         expect(result.name).toEqual('TestSupplier-1');
-        expect(result.payDemFk).toEqual(1);
         expect(result.id).toEqual(443);
 
         const createdSupplier = await app.models.Supplier.findById(result.id);
@@ -34,7 +33,7 @@ describe('Supplier newSupplier()', () => {
         expect(createdSupplier.provinceFk).toBeNull();
         expect(createdSupplier.postCode).toBeNull();
         expect(createdSupplier.payMethodFk).toBeNull();
-        expect(createdSupplier.payDemFk).toEqual(1);
+        expect(createdSupplier.payDemFk).toEqual(7);
         expect(createdSupplier.payDay).toBeNull();
         expect(createdSupplier.nickname).toEqual(result.name);
         expect(createdSupplier.workerFk).toBeNull();

From ae3e3c3c49c4dc474d96fbd510febaa03fb28f7c Mon Sep 17 00:00:00 2001
From: vicent <vicent@verdnatura.es>
Date: Tue, 18 Oct 2022 12:37:06 +0200
Subject: [PATCH 074/151] fix: id model duplicated

---
 modules/ticket/front/expedition/index.html | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/modules/ticket/front/expedition/index.html b/modules/ticket/front/expedition/index.html
index f4b2615339..0ebe388c12 100644
--- a/modules/ticket/front/expedition/index.html
+++ b/modules/ticket/front/expedition/index.html
@@ -98,16 +98,16 @@
  
 <vn-popup vn-id="statusLog">
     <vn-crud-model
-        vn-id="model"
+        vn-id="modelExpeditionStates"
         url="ExpeditionStates/filter"
         link="{expeditionFk: $ctrl.expedition.id}"
         data="expeditionStates"
         order="created DESC"
         auto-load="true">
     </vn-crud-model>
-    <vn-data-viewer model="model">
+    <vn-data-viewer model="modelExpeditionStates">
         <vn-card class="vn-w-md">
-        <vn-table model="model">
+        <vn-table model="modelExpeditionStates">
             <vn-thead>
                 <vn-tr>
                     <vn-th field="state">State</vn-th>

From 470b4485d59abf4ddcc216986ac233f97af5ebe8 Mon Sep 17 00:00:00 2001
From: Pau Navarro <pau@verdnatura.es>
Date: Tue, 18 Oct 2022 12:58:44 +0200
Subject: [PATCH 075/151] Fixed test and DB structure

---
 .../00-defaultSupplierActivityFk_to_Null.sql             | 1 -
 .../10491-august/00-supplierActivityFk_Allow_Null.sql    | 2 +-
 modules/supplier/back/methods/supplier/newSupplier.js    | 1 +
 .../back/methods/supplier/specs/newSupplier.spec.js      | 9 +++++++++
 4 files changed, 11 insertions(+), 2 deletions(-)
 delete mode 100644 db/changes/10491-august/00-defaultSupplierActivityFk_to_Null.sql

diff --git a/db/changes/10491-august/00-defaultSupplierActivityFk_to_Null.sql b/db/changes/10491-august/00-defaultSupplierActivityFk_to_Null.sql
deleted file mode 100644
index 1fc4e29058..0000000000
--- a/db/changes/10491-august/00-defaultSupplierActivityFk_to_Null.sql
+++ /dev/null
@@ -1 +0,0 @@
-ALTER TABLE vn.supplier MODIFY COLUMN supplierActivityFk varchar(45) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL NULL;
diff --git a/db/changes/10491-august/00-supplierActivityFk_Allow_Null.sql b/db/changes/10491-august/00-supplierActivityFk_Allow_Null.sql
index 6f4cdcc398..1fc4e29058 100644
--- a/db/changes/10491-august/00-supplierActivityFk_Allow_Null.sql
+++ b/db/changes/10491-august/00-supplierActivityFk_Allow_Null.sql
@@ -1 +1 @@
-ALTER TABLE vn.supplier MODIFY COLUMN supplierActivityFk varchar(45) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT 'flowersPlants' NULL;
+ALTER TABLE vn.supplier MODIFY COLUMN supplierActivityFk varchar(45) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL NULL;
diff --git a/modules/supplier/back/methods/supplier/newSupplier.js b/modules/supplier/back/methods/supplier/newSupplier.js
index 0395e982bf..6206eaf1c3 100644
--- a/modules/supplier/back/methods/supplier/newSupplier.js
+++ b/modules/supplier/back/methods/supplier/newSupplier.js
@@ -41,6 +41,7 @@ module.exports = Self => {
             };
         } catch (e) {
             if (tx) await tx.rollback();
+            return params;
         }
     };
 };
diff --git a/modules/supplier/back/methods/supplier/specs/newSupplier.spec.js b/modules/supplier/back/methods/supplier/specs/newSupplier.spec.js
index b252c4d60e..8bf2713487 100644
--- a/modules/supplier/back/methods/supplier/specs/newSupplier.spec.js
+++ b/modules/supplier/back/methods/supplier/specs/newSupplier.spec.js
@@ -1,11 +1,20 @@
 const app = require('vn-loopback/server/server');
+const LoopBackContext = require('loopback-context');
 
 describe('Supplier newSupplier()', () => {
     const newSupp = {
         name: 'TestSupplier-1'
     };
+    const administrativeId = 5;
 
     it('should create a new supplier containing only the name', async() => {
+        const activeCtx = {
+            accessToken: {userId: administrativeId},
+        };
+        spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
+            active: activeCtx
+        });
+
         let result = await app.models.Supplier.newSupplier(JSON.stringify(newSupp));
 
         result = result.supplier;

From db12ceb369556bd7b9652267900fa206354efc4e Mon Sep 17 00:00:00 2001
From: Pau Navarro <pau@verdnatura.es>
Date: Tue, 18 Oct 2022 13:07:10 +0200
Subject: [PATCH 076/151] removed async from the redirect function

---
 modules/supplier/front/create/index.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/modules/supplier/front/create/index.js b/modules/supplier/front/create/index.js
index bed14c8262..7c5a638bf5 100644
--- a/modules/supplier/front/create/index.js
+++ b/modules/supplier/front/create/index.js
@@ -13,7 +13,7 @@ class Controller extends Section {
 
                 redirect(this.$.$ctrl);
 
-                async function redirect(ctrl) {
+                function redirect(ctrl) {
                     window.location.href = `/#!/supplier/${ctrl.supplier.supplier.id}/fiscal-data`;
                 }
             }

From 9ea427dbfece8d68a6350e1f9861f2222c31f631 Mon Sep 17 00:00:00 2001
From: vicent <vicent@verdnatura.es>
Date: Tue, 18 Oct 2022 13:45:46 +0200
Subject: [PATCH 077/151] refactor: move front to back funcionality

---
 loopback/locale/es.json                       |  3 +-
 .../methods/expedition/moveExpeditions.js     | 60 +++++++++++++++----
 modules/ticket/front/expedition/index.js      | 17 ++----
 3 files changed, 55 insertions(+), 25 deletions(-)

diff --git a/loopback/locale/es.json b/loopback/locale/es.json
index 67370b3438..bd9de41c29 100644
--- a/loopback/locale/es.json
+++ b/loopback/locale/es.json
@@ -235,5 +235,6 @@
 	"Dirección incorrecta": "Dirección incorrecta",
 	"Modifiable user details only by an administrator": "Detalles de usuario modificables solo por un administrador",
 	"Modifiable password only via recovery or by an administrator": "Contraseña modificable solo a través de la recuperación o por un administrador",
-	"Not enough privileges to edit a client": "No tienes suficientes privilegios para editar un cliente"
+	"Not enough privileges to edit a client": "No tienes suficientes privilegios para editar un cliente",
+	"This route not exists": "Esta ruta no existe"
 }
\ No newline at end of file
diff --git a/modules/ticket/back/methods/expedition/moveExpeditions.js b/modules/ticket/back/methods/expedition/moveExpeditions.js
index 338568fdb4..d0f8aa8939 100644
--- a/modules/ticket/back/methods/expedition/moveExpeditions.js
+++ b/modules/ticket/back/methods/expedition/moveExpeditions.js
@@ -1,19 +1,47 @@
+const UserError = require('vn-loopback/util/user-error');
 
 module.exports = Self => {
-    Self.remoteMethod('moveExpeditions', {
+    Self.remoteMethodCtx('moveExpeditions', {
         description: 'Move the selected expeditions to another ticket',
         accessType: 'WRITE',
         accepts: [{
+            arg: 'clientId',
+            type: 'number',
+            description: `The client id`,
+            required: true
+        },
+        {
+            arg: 'landed',
+            type: 'date',
+            description: `The landing date`
+        },
+        {
+            arg: 'warehouseId',
+            type: 'number',
+            description: `The warehouse id`,
+            required: true
+        },
+        {
+            arg: 'addressId',
+            type: 'number',
+            description: `The address id`,
+            required: true
+        },
+        {
+            arg: 'agencyModeId',
+            type: 'any',
+            description: `The agencyMode id`
+        },
+        {
+            arg: 'routeId',
+            type: 'any',
+            description: `The route id`
+        },
+        {
             arg: 'expeditionIds',
             type: ['number'],
             required: true,
-            description: 'The expeditions ids to nove'
-        },
-        {
-            arg: 'ticketId',
-            type: 'number',
-            required: true,
-            description: 'the ticket id to which the expeditions are added'
+            description: 'The expeditions ids to move'
         }],
         returns: {
             type: 'object',
@@ -25,8 +53,9 @@ module.exports = Self => {
         }
     });
 
-    Self.moveExpeditions = async(expeditionIds, ticketId, options) => {
+    Self.moveExpeditions = async(ctx, options) => {
         const models = Self.app.models;
+        const args = ctx.args;
         const myOptions = {};
         let tx;
 
@@ -39,18 +68,23 @@ module.exports = Self => {
         }
 
         try {
+            if (args.routeId) {
+                const route = await models.Route.findById(args.routeId, null, myOptions);
+                if (!route) throw new UserError('This route not exists');
+            }
+            const ticket = await models.Ticket.new(ctx, myOptions);
             const promises = [];
-            for (let expeditionsId of expeditionIds) {
+            for (let expeditionsId of args.expeditionIds) {
                 const expeditionToUpdate = await models.Expedition.findById(expeditionsId);
-                const expeditionUpdated = expeditionToUpdate.updateAttribute('ticketFk', ticketId, myOptions);
+                const expeditionUpdated = expeditionToUpdate.updateAttribute('ticketFk', ticket.id, myOptions);
                 promises.push(expeditionUpdated);
             }
 
-            const updated = await Promise.all(promises);
+            await Promise.all(promises);
 
             if (tx) await tx.commit();
 
-            return updated;
+            return ticket;
         } catch (e) {
             if (tx) await tx.rollback();
             throw e;
diff --git a/modules/ticket/front/expedition/index.js b/modules/ticket/front/expedition/index.js
index 49ba3280d7..7ffe2fe5e6 100644
--- a/modules/ticket/front/expedition/index.js
+++ b/modules/ticket/front/expedition/index.js
@@ -44,22 +44,17 @@ class Controller extends Section {
     }
 
     createTicket(landed, routeFk) {
-        const ticketParams = {
+        const params = {
             clientId: this.ticket.clientFk,
             landed: landed,
+            warehouseId: this.ticket.warehouseFk,
             addressId: this.ticket.addressFk,
             agencyModeId: this.ticket.agencyModeFk,
-            warehouseId: this.ticket.warehouseFk
+            routeId: routeFk,
+            expeditionIds: this.checked
         };
-        const query = `Tickets/new`;
-        this.$http.post(query, ticketParams).then(res => {
-            if (routeFk) this.$http.patch(`Tickets/${res.data.id}`, {routeFk: routeFk});
-            const params = {
-                expeditionIds: this.checked,
-                ticketId: res.data.id
-            };
-            const query = `Expeditions/moveExpeditions`;
-            this.$http.post(query, params);
+        const query = `Expeditions/moveExpeditions`;
+        this.$http.post(query, params).then(res => {
             this.vnApp.showSuccess(this.$t('Data saved!'));
             this.$state.go('ticket.card.summary', {id: res.data.id});
         });

From c2fd1fa44d1b65087d68eea51dfa2fb3bf1cbba6 Mon Sep 17 00:00:00 2001
From: Pau Navarro <pau@verdnatura.es>
Date: Tue, 18 Oct 2022 14:22:54 +0200
Subject: [PATCH 078/151] fixed tests

---
 modules/supplier/back/methods/supplier/specs/filter.spec.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/modules/supplier/back/methods/supplier/specs/filter.spec.js b/modules/supplier/back/methods/supplier/specs/filter.spec.js
index 1f74b10ffc..2620bb687e 100644
--- a/modules/supplier/back/methods/supplier/specs/filter.spec.js
+++ b/modules/supplier/back/methods/supplier/specs/filter.spec.js
@@ -10,7 +10,7 @@ describe('Supplier filter()', () => {
 
         let result = await app.models.Supplier.filter(ctx);
 
-        expect(result.length).toEqual(1);
+        expect(result.length).toBeGreaterThanOrEqual(1);
         expect(result[0].id).toEqual(1);
     });
 

From c9073641aa89a0b299ccc11de59b5cef8c573748 Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Tue, 18 Oct 2022 14:58:38 +0200
Subject: [PATCH 079/151] feat(invoiceInPdf): content

---
 .../back/methods/invoice-in/invoiceInPdf.js   |   3 +-
 .../reports/invoiceIn/invoiceIn.html          | 135 +++++++++---------
 .../templates/reports/invoiceIn/invoiceIn.js  |  49 ++++++-
 .../templates/reports/invoiceIn/locale/es.yml |   8 +-
 print/templates/reports/invoiceIn/sql/buy.sql |  18 +++
 .../templates/reports/invoiceIn/sql/entry.sql |   8 ++
 .../reports/invoiceIn/sql/invoice.sql         |   9 +-
 .../templates/reports/invoiceIn/sql/taxes.sql |  13 ++
 8 files changed, 165 insertions(+), 78 deletions(-)
 create mode 100644 print/templates/reports/invoiceIn/sql/buy.sql
 create mode 100644 print/templates/reports/invoiceIn/sql/entry.sql
 create mode 100644 print/templates/reports/invoiceIn/sql/taxes.sql

diff --git a/modules/invoiceIn/back/methods/invoice-in/invoiceInPdf.js b/modules/invoiceIn/back/methods/invoice-in/invoiceInPdf.js
index 71ba5710e6..1b7ca9c686 100644
--- a/modules/invoiceIn/back/methods/invoice-in/invoiceInPdf.js
+++ b/modules/invoiceIn/back/methods/invoice-in/invoiceInPdf.js
@@ -35,10 +35,11 @@ module.exports = Self => {
     });
 
     Self.invoiceInPdf = async(ctx, id) => {
+        console.log(id);
         const args = Object.assign({}, ctx.args);
         const params = {lang: ctx.req.getLocale()};
-
         delete args.ctx;
+        console.log(args);
         for (const param in args)
             params[param] = args[param];
 
diff --git a/print/templates/reports/invoiceIn/invoiceIn.html b/print/templates/reports/invoiceIn/invoiceIn.html
index 1d646a0db9..a1d488560c 100644
--- a/print/templates/reports/invoiceIn/invoiceIn.html
+++ b/print/templates/reports/invoiceIn/invoiceIn.html
@@ -6,12 +6,6 @@
                 <tr>
                     <td>
 
-                        <!-- Incoterms block -->
-                        <invoice-incoterms 
-                            v-if="hasIncoterms"
-                            v-bind="$props">
-                        </invoice-incoterms>
-
                         <!-- Header block -->
                         <report-header v-bind="$props"
                             v-bind:company-code="invoice.companyCode">
@@ -26,16 +20,16 @@
                                             <table class="row-oriented ticket-info">
                                                 <tbody>
                                                     <tr>
-                                                        <td class="font gray uppercase">{{$t('clientId')}}</td>
-                                                        <th>{{client.id}}</th>
+                                                        <td class="font gray uppercase">{{$t('supplierId')}}</td>
+                                                        <th>{{invoice.supplierId}}</th>
                                                     </tr>
                                                     <tr>
-                                                        <td class="font gray uppercase">{{$t('invoice')}}</td>
-                                                        <th>{{invoice.ref}}</th>
+                                                        <td class="font gray uppercase">{{$t('invoiceId')}}</td>
+                                                        <th>{{invoice.id}}</th>
                                                     </tr>
                                                     <tr>
                                                         <td class="font gray uppercase">{{$t('date')}}</td>
-                                                        <th>{{invoice.issued | date('%d-%m-%Y')}}</th>
+                                                        <th>{{invoice.created | date('%d-%m-%Y')}}</th>
                                                     </tr>
                                                 </tbody>
                                             </table>
@@ -45,22 +39,25 @@
                                         <div class="panel">
                                             <div class="header">{{$t('invoiceData')}}</div>
                                             <div class="body">
-                                                <h3 class="uppercase">{{client.socialName}}</h3>
+                                                <h3 class="uppercase">{{invoice.name}}</h3>
                                                 <div>
-                                                    {{client.postalAddress}}
+                                                    {{invoice.postalAddress}}
                                                 </div>
                                                 <div>
-                                                    {{client.postcodeCity}}
+                                                    {{invoice.postcodeCity}}
                                                 </div>
                                                 <div>
-                                                    {{$t('fiscalId')}}: {{client.fi}}
+                                                    {{$t('fiscalId')}}: {{invoice.nif}}
+                                                </div>
+                                                <div>
+                                                    {{$t('phone')}}: {{invoice.phone}}
                                                 </div>
                                             </div>
                                         </div>
                                     </div>
                                 </div>
-
-                                <!-- Rectified invoices block -->
+                                <!--
+                                 Rectified invoices block
                                 <div class="size100 no-page-break" v-if="rectified.length > 0">
                                     <h2>{{$t('rectifiedInvoices')}}</h2>
                                     <table class="column-oriented">
@@ -82,81 +79,81 @@
                                         </tbody>
                                     </table>
                                 </div>
-                                <!-- End of rectified invoices block -->
-                
-                                <!-- Sales block -->
-                                <div class="vn-mt-lg" v-for="ticket in tickets">
+                                 End of rectified invoices block-->
+
+                                <div class="vn-mt-lg" v-for="entry in entries">
                                     <div class="table-title clearfix">
                                         <div class="pull-left">
-                                            <h2>{{$t('deliveryNote')}}</strong>
+                                            <h2>{{$t('invoiceIn')}}</strong>
                                         </div>
                                         <div class="pull-left vn-mr-md">
                                             <div class="field rectangle">
-                                                <span>{{ticket.id}}</span>
+                                                <span>{{entry.id}}</span>
                                             </div>
                                         </div>
                                         <div class="pull-left">
-                                            <h2>{{$t('shipped')}}</h2>
+                                            <h2>{{$t('date')}}</h2>
                                         </div>
                                         <div class="pull-left">
                                             <div class="field rectangle">
-                                                <span>{{ticket.shipped | date}}</span>
+                                                <span>{{entry.landed | date}}</span>
                                             </div>
                                         </div>
                                         <span id="nickname" class="pull-right">
-                                            <h2>{{ticket.nickname}}</h2>
+                                            <div class="pull-left">
+                                                <h2>{{$t('reference')}}</h2>
+                                            </div>
+                                            <div class="pull-left">
+                                                <div class="field rectangle">
+                                                    <span>{{entry.ref}}</span>
+                                                </div>
+                                            </div>
                                         </span>
                                     </div>
                                     <table class="column-oriented">
                                         <thead>
                                             <tr>
-                                                <th width="5%">{{$t('reference')}}</th>
+                                                <th width="50%">{{$t('item')}}</th>
                                                 <th class="number">{{$t('quantity')}}</th>
-                                                <th width="50%">{{$t('concept')}}</th>
-                                                <th class="number">{{$t('price')}}</th>
-                                                <th class="centered" width="5%">{{$t('discount')}}</th>
-                                                <th class="centered">{{$t('vat')}}</th>
+                                                <th class="number">{{$t('buyingValue')}}</th>
                                                 <th class="number">{{$t('amount')}}</th>
                                             </tr>
                                         </thead>
-                                        <tbody v-for="sale in ticket.sales" class="no-page-break">
+                                        <tbody v-for="buy in entry.buys" class="no-page-break">
                                             <tr>
-                                                <td width="5%">{{sale.itemFk | zerofill('000000')}}</td>
-                                                <td class="number">{{sale.quantity}}</td>
-                                                <td width="50%">{{sale.concept}}</td>
-                                                <td class="number">{{sale.price | currency('EUR', $i18n.locale)}}</td>
-                                                <td class="centered" width="5%">{{(sale.discount / 100) | percentage}}</td>
-                                                <td class="centered">{{sale.vatType}}</td>
-                                                <td class="number">{{saleImport(sale) | currency('EUR', $i18n.locale)}}</td>
+                                                <td width="50%">{{buy.name}}</td>
+                                                <td class="number">{{buy.quantity}}</td>
+                                                <td class="number">{{buy.buyingValue}}</td>
+                                                <td class="number">{{buyImport(buy) | currency('EUR', $i18n.locale)}}</td>
                                             </tr>
                                             <tr class="description font light-gray">
-                                                <td colspan="7">
-                                                    <span v-if="sale.value5">
-                                                        <strong>{{sale.tag5}}</strong> {{sale.value5}}
-                                                    </span> 
-                                                    <span v-if="sale.value6">
-                                                        <strong>{{sale.tag6}}</strong> {{sale.value6}}
-                                                    </span> 
-                                                    <span v-if="sale.value7">
-                                                        <strong>{{sale.tag7}}</strong> {{sale.value7}}
-                                                    </span> 
+                                                <td colspan="4">
+                                                    <span v-if="buy.value5">
+                                                        <strong>{{buy.tag5}}</strong> {{buy.value5}}
+                                                    </span>
+                                                    <span v-if="buy.value6">
+                                                        <strong>{{buy.tag6}}</strong> {{buy.value6}}
+                                                    </span>
+                                                    <span v-if="buy.value7">
+                                                        <strong>{{buy.tag7}}</strong> {{buy.value7}}
+                                                    </span>
                                                 </td>
                                             </tr>
                                         </tbody>
                                         <tfoot>
                                             <tr>
-                                                <td colspan="6" class="font bold">
+                                                <td colspan="3" class="font bold">
                                                     <span class="pull-right">{{$t('subtotal')}}</span>
                                                 </td>
-                                                <td class="number">{{ticketSubtotal(ticket) | currency('EUR', $i18n.locale)}}</td>
+                                                <td class="number">{{entrySubtotal(entry) | currency('EUR', $i18n.locale)}}</td>
                                             </tr>
                                         </tfoot>
                                     </table>
                                 </div>
                                 <!-- End of sales block -->
-                
+
                                 <div class="columns vn-mt-xl">
-                                    <!-- Taxes block -->
+                                    Taxes block
                                     <div id="taxes" class="size50 pull-right no-page-break" v-if="taxes">
                                         <table class="column-oriented">
                                             <thead>
@@ -208,8 +205,8 @@
                                         </div>
                                     </div>
                                     <!-- End of taxes block -->
-
-                                    <!-- Phytosanitary block -->
+                                    <!--
+                                     Phytosanitary block
                                     <div id="phytosanitary" class="size50 pull-left no-page-break">
                                         <div class="panel">
                                             <div class="body">
@@ -225,16 +222,16 @@
                                                 </div>
                                                 <div class="phytosanitary-info">
                                                     <div>
-                                                        <strong>A</strong> 
+                                                        <strong>A</strong>
                                                         <span>{{botanical}}</span>
                                                     </div>
                                                     <div>
-                                                        <strong>B</strong> 
-                                                        <span>ES17462130</span>                                                        
+                                                        <strong>B</strong>
+                                                        <span>ES17462130</span>
                                                     </div>
                                                     <div>
-                                                        <strong>C</strong> 
-                                                        <span>{{ticketsId}}</span>                                                        
+                                                        <strong>C</strong>
+                                                        <span>{{ticketsId}}</span>
                                                     </div>
                                                     <div>
                                                         <strong>D</strong>
@@ -244,11 +241,11 @@
                                             </div>
                                         </div>
                                     </div>
-                                    <!-- End of phytosanitary block -->
+                                     End of phytosanitary block
                                 </div>
 
-                                
-                                <!-- Intrastat block -->
+
+                                 Intrastat block
                                 <div class="size100 no-page-break" v-if="intrastat.length > 0">
                                     <h2>{{$t('intrastat')}}</h2>
                                     <table class="column-oriented">
@@ -286,9 +283,9 @@
                                         </tfoot>
                                     </table>
                                 </div>
-                                <!-- End of intrastat block -->
+                                 End of intrastat block
 
-                                <!-- Observations block -->
+                                 Observations block
                                 <div class="columns vn-mt-xl" v-if="invoice.payMethodCode == 'wireTransfer'">
                                     <div class="size50 pull-left no-page-break" >
                                         <div class="panel" >
@@ -300,20 +297,20 @@
                                         </div>
                                     </div>
                                 </div>
-                                <!-- End of observations block -->
+                                 End of observations block
 
                             </div>
                         </div>
-                        <!-- Footer block -->
+                         Footer block
                         <report-footer id="pageFooter"
                             v-bind:company-code="invoice.companyCode"
                             v-bind:left-text="$t('invoiceRef', [invoice.ref])"
                             v-bind:center-text="client.socialName"
                             v-bind="$props">
-                        </report-footer>
+                        </report-footer> -->
                     </td>
                 </tr>
             </tbody>
         </table>
     </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/print/templates/reports/invoiceIn/invoiceIn.js b/print/templates/reports/invoiceIn/invoiceIn.js
index 3fed1b867e..103f36d1cc 100755
--- a/print/templates/reports/invoiceIn/invoiceIn.js
+++ b/print/templates/reports/invoiceIn/invoiceIn.js
@@ -1,28 +1,71 @@
 const Component = require(`vn-print/core/component`);
-const Report = require(`vn-print/core/report`);
 const reportHeader = new Component('report-header');
 const reportFooter = new Component('report-footer');
-const invoiceIncoterms = new Report('invoice-incoterms');
 
 module.exports = {
     name: 'invoiceIn',
     async serverPrefetch() {
         this.invoice = await this.fetchInvoice(this.id);
+        this.taxes = await this.fetchTaxes(this.id);
 
         if (!this.invoice)
             throw new Error('Something went wrong');
+
+        const entries = await this.fetchEntry(this.id);
+        const buys = await this.fetchBuy(this.id);
+
+        const map = new Map();
+
+        for (let entry of entries) {
+            entry.buys = [];
+
+            map.set(entry.id, entry);
+        }
+
+        for (let buy of buys) {
+            const entry = map.get(buy.entryFk);
+
+            if (entry) entry.buys.push(buy);
+        }
+
+        this.entries = entries;
     },
     computed: {
     },
     methods: {
         fetchInvoice(id) {
             return this.findOneFromDef('invoice', [id]);
+        },
+        fetchEntry(id) {
+            return this.rawSqlFromDef('entry', [id]);
+        },
+        fetchBuy(id) {
+            return this.rawSqlFromDef('buy', [id]);
+        },
+        fetchTaxes(id) {
+            return this.rawSqlFromDef(`taxes`, [id]);
+        },
+        buyImport(buy) {
+            return buy.quantity * buy.buyingValue;
+        },
+        entrySubtotal(entry) {
+            let subTotal = 0.00;
+            for (let buy of entry.buys)
+                subTotal += this.buyImport(buy);
+
+            return subTotal;
+        },
+        sumTotal(rows, prop) {
+            let total = 0.00;
+            for (let row of rows)
+                total += parseFloat(row[prop]);
+
+            return total;
         }
     },
     components: {
         'report-header': reportHeader.build(),
         'report-footer': reportFooter.build(),
-        'invoice-incoterms': invoiceIncoterms.build()
     },
     props: {
         id: {
diff --git a/print/templates/reports/invoiceIn/locale/es.yml b/print/templates/reports/invoiceIn/locale/es.yml
index d37e77943f..6386c611aa 100644
--- a/print/templates/reports/invoiceIn/locale/es.yml
+++ b/print/templates/reports/invoiceIn/locale/es.yml
@@ -1,7 +1,7 @@
 reportName: factura
-title: Factura
-invoice: Factura
-clientId: Cliente
+title: Factura Agrícola
+invoiceId: Factura Agrícola
+supplierId: Proveedor
 invoiceData: Datos de facturación
 fiscalId: CIF / NIF
 invoiceRef: Factura {0}
@@ -33,4 +33,4 @@ issued: F. emisión
 plantPassport: Pasaporte fitosanitario
 observations: Observaciones
 wireTransfer: "Forma de pago: Transferencia"
-accountNumber: "Número de cuenta: {0}"
\ No newline at end of file
+accountNumber: "Número de cuenta: {0}"
diff --git a/print/templates/reports/invoiceIn/sql/buy.sql b/print/templates/reports/invoiceIn/sql/buy.sql
new file mode 100644
index 0000000000..28a80ff9cf
--- /dev/null
+++ b/print/templates/reports/invoiceIn/sql/buy.sql
@@ -0,0 +1,18 @@
+SELECT
+        b.id,
+		e.id entryFk,
+		it.name,
+		b.quantity,
+		b.buyingValue,
+		(b.quantity * b.buyingValue) total,
+		it.tag5,
+		it.value5,
+		it.tag6,
+		it.value6,
+		it.tag7,
+		it.value7
+	FROM entry e
+        JOIN invoiceIn i ON i.id = e.invoiceInFk
+        JOIN buy b ON b.entryFk = e.id
+        JOIN item it ON it.id = b.itemFk
+    WHERE i.id = ?
diff --git a/print/templates/reports/invoiceIn/sql/entry.sql b/print/templates/reports/invoiceIn/sql/entry.sql
new file mode 100644
index 0000000000..0b29cd81cd
--- /dev/null
+++ b/print/templates/reports/invoiceIn/sql/entry.sql
@@ -0,0 +1,8 @@
+SELECT
+		e.id,
+		t.landed,
+		e.ref
+	FROM entry e
+        JOIN invoiceIn i ON i.id = e.invoiceInFk
+        JOIN travel t ON t.id = e.travelFk
+    WHERE i.id = ?
diff --git a/print/templates/reports/invoiceIn/sql/invoice.sql b/print/templates/reports/invoiceIn/sql/invoice.sql
index e6b1eb9956..8913a833b8 100644
--- a/print/templates/reports/invoiceIn/sql/invoice.sql
+++ b/print/templates/reports/invoiceIn/sql/invoice.sql
@@ -1,4 +1,11 @@
-SELECT *
+SELECT
+        i.id,
+        s.id supplierId,
+        i.created,
+        s.name,
+        s.street AS postalAddress,
+        s.nif,
+        s.phone
 	FROM invoiceIn i
 		JOIN supplier s ON s.id = i.supplierFk
 		JOIN company c ON c.id = i.companyFk
diff --git a/print/templates/reports/invoiceIn/sql/taxes.sql b/print/templates/reports/invoiceIn/sql/taxes.sql
new file mode 100644
index 0000000000..18ca6db093
--- /dev/null
+++ b/print/templates/reports/invoiceIn/sql/taxes.sql
@@ -0,0 +1,13 @@
+SELECT
+        id,
+        invoiceInFk,
+        taxableBase,
+        expenseFk,
+        taxTypeSageFk,
+        transactionTypeSageFk,
+        foreignValue
+    FROM invoiceInTax iit
+        JOIN transactionTypeSage ts ON iit.transactionTypeSageFk = ts.id
+        JOIN taxTypeSage tts ON tts.id =
+    WHERE io.ref = ?
+    ORDER BY iot.id

From 6f7ec12cb2119ce6584811d7d4228bdd8df499fb Mon Sep 17 00:00:00 2001
From: vicent <vicent@verdnatura.es>
Date: Wed, 19 Oct 2022 10:35:41 +0200
Subject: [PATCH 080/151] feat: response as 'reply' and not as 'internNote'

---
 back/methods/osticket/closeTicket.js          | 48 ++++++++++++++-----
 back/models/osticket-config.json              | 12 +++--
 db/changes/10481-june/00-osTicketConfig.sql   |  6 +--
 db/changes/10491-august/00-osTicketConfig.sql |  8 ++++
 db/dump/fixtures.sql                          |  4 ++
 package.json                                  |  1 +
 6 files changed, 58 insertions(+), 21 deletions(-)
 create mode 100644 db/changes/10491-august/00-osTicketConfig.sql

diff --git a/back/methods/osticket/closeTicket.js b/back/methods/osticket/closeTicket.js
index 87d54d3b86..33fe5958b0 100644
--- a/back/methods/osticket/closeTicket.js
+++ b/back/methods/osticket/closeTicket.js
@@ -1,12 +1,13 @@
 const jsdom = require('jsdom');
 const mysql = require('mysql');
+const FormData = require('form-data');
 
 module.exports = Self => {
     Self.remoteMethodCtx('closeTicket', {
         description: 'Close tickets without response from the user',
         accessType: 'READ',
         returns: {
-            type: 'Object',
+            type: 'object',
             root: true
         },
         http: {
@@ -54,9 +55,9 @@ module.exports = Self => {
             });
         });
 
-        await requestToken();
+        await getRequestToken();
 
-        async function requestToken() {
+        async function getRequestToken() {
             const response = await fetch(ostUri);
 
             const result = response.headers.get('set-cookie');
@@ -93,24 +94,45 @@ module.exports = Self => {
             await close(token, secondCookie);
         }
 
+        async function getLockCode(token, secondCookie, ticketId) {
+            const ostUri = `${config.host}/ajax.php/lock/ticket/${ticketId}`;
+            const params = {
+                method: 'POST',
+                headers: {
+                    'X-CSRFToken': token,
+                    'Cookie': secondCookie
+                }
+            };
+            const response = await fetch(ostUri, params);
+            const body = await response.text();
+            const json = JSON.parse(body);
+
+            return json.code;
+        }
+
         async function close(token, secondCookie) {
             for (const ticketId of ticketsId) {
-                const ostUri = `${config.host}/ajax.php/tickets/${ticketId}/status`;
-                const data = {
-                    status_id: config.newStatusId,
-                    comments: config.comment,
-                    undefined: config.action
-                };
+                const lockCode = await getLockCode(token, secondCookie, ticketId);
+                let form = new FormData();
+                form.append('__CSRFToken__', token);
+                form.append('id', ticketId);
+                form.append('a', config.responseType);
+                form.append('lockCode', lockCode);
+                form.append('from_email_id', config.fromEmailId);
+                form.append('reply-to', config.replyTo);
+                form.append('cannedResp', 0);
+                form.append('response', config.comment);
+                form.append('signature', 'none');
+                form.append('reply_status_id', config.newStatusId);
+
+                const ostUri = `${config.host}/tickets.php?id=${ticketId}`;
                 const params = {
                     method: 'POST',
-                    body: new URLSearchParams(data),
+                    body: form,
                     headers: {
-                        'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
-                        'X-CSRFToken': token,
                         'Cookie': secondCookie
                     }
                 };
-
                 return fetch(ostUri, params);
             }
         }
diff --git a/back/models/osticket-config.json b/back/models/osticket-config.json
index d42632c6a5..5a863e7bc7 100644
--- a/back/models/osticket-config.json
+++ b/back/models/osticket-config.json
@@ -27,9 +27,6 @@
         "newStatusId": {
             "type": "number"
         },
-        "action": {
-            "type": "string"
-        },
         "day": {
             "type": "number"
         },
@@ -47,6 +44,15 @@
         },
         "portDb": {
             "type": "number"
+        },
+        "responseType": {
+            "type": "string"
+        },
+        "fromEmailId": {
+            "type": "number"
+        },
+        "replyTo": {
+            "type": "string"
         }
     }
 }
\ No newline at end of file
diff --git a/db/changes/10481-june/00-osTicketConfig.sql b/db/changes/10481-june/00-osTicketConfig.sql
index ad66627153..8727c816dd 100644
--- a/db/changes/10481-june/00-osTicketConfig.sql
+++ b/db/changes/10481-june/00-osTicketConfig.sql
@@ -13,8 +13,4 @@ CREATE TABLE `vn`.`osTicketConfig` (
   `passwordDb` varchar(100) COLLATE utf8mb3_unicode_ci DEFAULT NULL,
   `portDb` int(11) DEFAULT NULL,
   PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
-
-INSERT INTO `vn`.`osTicketConfig`(`id`, `host`, `user`, `password`, `oldStatus`, `newStatusId`, `action`, `day`, `comment`, `hostDb`, `userDb`, `passwordDb`, `portDb`)
-      VALUES
-      (0, 'https://cau.verdnatura.es/scp', NULL, NULL, 'open', 3, 'Cerrar', 60, 'Este CAU se ha cerrado automáticamente', NULL, NULL, NULL, NULL);
\ No newline at end of file
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
\ No newline at end of file
diff --git a/db/changes/10491-august/00-osTicketConfig.sql b/db/changes/10491-august/00-osTicketConfig.sql
new file mode 100644
index 0000000000..10a58b6c82
--- /dev/null
+++ b/db/changes/10491-august/00-osTicketConfig.sql
@@ -0,0 +1,8 @@
+ALTER TABLE `vn`.`osTicketConfig` DROP COLUMN `action`;
+ALTER TABLE `vn`.`osTicketConfig` ADD responseType varchar(100) NULL;
+ALTER TABLE `vn`.`osTicketConfig` ADD fromEmailId INT NULL;
+ALTER TABLE `vn`.`osTicketConfig` ADD replyTo varchar(100) NULL;
+
+UPDATE `vn`.`osTicketConfig`
+    SET responseType='reply', fromEmailId=5, replyTo='all'
+WHERE id=0;
\ No newline at end of file
diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql
index 7e59c1a54a..b3f2d9c262 100644
--- a/db/dump/fixtures.sql
+++ b/db/dump/fixtures.sql
@@ -2667,3 +2667,7 @@ INSERT INTO `vn`.`ticketCollection` (`ticketFk`, `collectionFk`, `created`, `lev
 UPDATE `account`.`user`
     SET `hasGrant` = 1
         WHERE `id` = 66;
+
+INSERT INTO `vn`.`osTicketConfig` (`id`, `host`, `user`, `password`, `oldStatus`, `newStatusId`, `day`, `comment`, `hostDb`, `userDb`, `passwordDb`, `portDb`, `responseType`, `fromEmailId`, `replyTo`)
+    VALUES
+        (0, 'http://localhost:56596/scp', 'ostadmin', 'Admin1', 'open', 3, 60, 'Este CAU se ha cerrado automáticamente. Si el problema persiste responda a este mensaje.', 'localhost', 'osticket', 'osticket', 40003, 'reply', 1, 'all');
\ No newline at end of file
diff --git a/package.json b/package.json
index 26c164832a..5ab329875a 100644
--- a/package.json
+++ b/package.json
@@ -16,6 +16,7 @@
         "bcrypt": "^5.0.1",
         "bmp-js": "^0.1.0",
         "compression": "^1.7.3",
+        "form-data": "^4.0.0",
         "fs-extra": "^5.0.0",
         "ftps": "^1.2.0",
         "got": "^10.7.0",

From dcd858c7d54de077801b93b3838c83ab5be2590c Mon Sep 17 00:00:00 2001
From: joan <joan@verdnatura.es>
Date: Wed, 19 Oct 2022 14:30:36 +0200
Subject: [PATCH 081/151] feat(print): 4690 - Puppeteer cluster

---
 print/boot.js           |  54 --------
 print/core/cluster.js   |  42 ++++++
 print/core/database.js  |   1 -
 print/core/report.js    |  57 ++++----
 print/index.js          |   1 +
 print/package-lock.json | 290 +++++++++++++++++++++++++++++++++++-----
 print/package.json      |   3 +-
 7 files changed, 323 insertions(+), 125 deletions(-)
 delete mode 100644 print/boot.js
 create mode 100644 print/core/cluster.js

diff --git a/print/boot.js b/print/boot.js
deleted file mode 100644
index d5c06264ca..0000000000
--- a/print/boot.js
+++ /dev/null
@@ -1,54 +0,0 @@
-const express = require('express');
-const path = require('path');
-const fs = require('fs');
-
-const templatesPath = path.resolve(__dirname, './templates');
-const componentsPath = path.resolve(__dirname, './core/components');
-
-module.exports = async app => {
-    global.appPath = __dirname;
-
-    process.env.OPENSSL_CONF = '/etc/ssl/';
-
-    // Extended locale intl polyfill
-    const IntlPolyfill = require('intl');
-    Intl.NumberFormat = IntlPolyfill.NumberFormat;
-    Intl.DateTimeFormat = IntlPolyfill.DateTimeFormat;
-
-    // Init database instance
-    require('./core/database').init();
-    // Init SMTP Instance
-    require('./core/smtp').init();
-    require('./core/mixins');
-    require('./core/filters');
-    require('./core/directives');
-    // Init router
-    require('./core/router')(app);
-
-    /**
-     * Serve component static files
-     */
-    const componentsDir = fs.readdirSync(componentsPath);
-    componentsDir.forEach(componentName => {
-        const componentDir = path.join(componentsPath, '/', componentName);
-        const assetsDir = `${componentDir}/assets`;
-
-        app.use(`/api/${componentName}/assets`, express.static(assetsDir));
-    });
-
-    /**
-     * Serve static files
-     */
-    const templatesDir = fs.readdirSync(templatesPath);
-    templatesDir.forEach(directory => {
-        const templateTypeDir = path.join(templatesPath, '/', directory);
-        const templates = fs.readdirSync(templateTypeDir);
-
-        templates.forEach(templateName => {
-            const templateDir = path.join(templatesPath, '/', directory, '/', templateName);
-            const assetsDir = `${templateDir}/assets`;
-
-            app.use(`/api/${templateName}/assets`, express.static(assetsDir));
-        });
-    });
-};
diff --git a/print/core/cluster.js b/print/core/cluster.js
new file mode 100644
index 0000000000..7a1a665d0e
--- /dev/null
+++ b/print/core/cluster.js
@@ -0,0 +1,42 @@
+const {Cluster} = require('puppeteer-cluster');
+const log4js = require('log4js');
+const {cpus} = require('os');
+
+module.exports = {
+    init() {
+        if (!this.pool) {
+            Cluster.launch({
+                concurrency: Cluster.CONCURRENCY_CONTEXT,
+                maxConcurrency: cpus().length,
+                puppeteerOptions: {
+                    args: [
+                        '--no-sandbox',
+                        '--disable-setuid-sandbox',
+                        '--no-zygote'
+                    ]
+                }
+            })
+                .then(cluster => {
+                    this.pool = cluster;
+
+                    log4js.configure({
+                        appenders: {
+                            out: {type: 'stdout'}
+                        },
+                        categories: {default: {appenders: ['out'], level: 'info'}},
+                    });
+
+                    const logger = log4js.getLogger();
+
+                    cluster.on('taskerror', (err, data, willRetry) => {
+                        if (willRetry)
+                            logger.warn(`[Print] => ${err.message}\nThis job will be retried`);
+                        else
+                            logger.error(`[Print] => ${err.message}`);
+                    });
+
+                    cluster.on('queue', () => logger.info('Printing task initialized by pool'));
+                });
+        }
+    }
+};
diff --git a/print/core/database.js b/print/core/database.js
index 0e81806f2b..ddc0153bda 100644
--- a/print/core/database.js
+++ b/print/core/database.js
@@ -1,5 +1,4 @@
 const mysql = require('mysql2');
-const config = require('./config.js');
 const fs = require('fs-extra');
 
 module.exports = {
diff --git a/print/core/report.js b/print/core/report.js
index 4dad566f3b..c5182d1a81 100644
--- a/print/core/report.js
+++ b/print/core/report.js
@@ -2,7 +2,7 @@ const fs = require('fs');
 const path = require('path');
 const config = require('./config');
 const Component = require('./component');
-const puppeteer = require('puppeteer');
+const Cluster = require('./cluster');
 
 if (!process.env.OPENSSL_CONF)
     process.env.OPENSSL_CONF = '/etc/ssl/';
@@ -32,39 +32,30 @@ class Report extends Component {
         if (fs.existsSync(fullPath))
             options = require(optionsPath);
 
-        const browser = await puppeteer.launch({
-            headless: true,
-            args: [
-                '--no-sandbox',
-                '--disable-setuid-sandbox',
-                '--single-process',
-                '--no-zygote'
-            ]
+        return new Promise(resolve => {
+            Cluster.pool.queue({}, async({page}) => {
+                await page.emulateMediaType('screen');
+                await page.setContent(template);
+
+                const element = await page.$('#pageFooter');
+
+                let footer = '\n';
+                if (element) {
+                    footer = await page.evaluate(el => {
+                        const html = el.innerHTML;
+                        el.remove();
+                        return html;
+                    }, element);
+                }
+
+                options.headerTemplate = '\n';
+                options.footerTemplate = footer;
+
+                const stream = await page.pdf(options);
+
+                resolve(stream);
+            });
         });
-
-        const page = (await browser.pages())[0];
-        await page.emulateMediaType('screen');
-        await page.setContent(template);
-
-        const element = await page.$('#pageFooter');
-
-        let footer = '\n';
-        if (element) {
-            footer = await page.evaluate(el => {
-                const html = el.innerHTML;
-                el.remove();
-                return html;
-            }, element);
-        }
-
-        options.headerTemplate = '\n';
-        options.footerTemplate = footer;
-
-        const buffer = await page.pdf(options);
-
-        await browser.close();
-
-        return buffer;
     }
 
     /**
diff --git a/print/index.js b/print/index.js
index 484aba00eb..7ba3586ebd 100644
--- a/print/index.js
+++ b/print/index.js
@@ -11,6 +11,7 @@ module.exports = {
 
         require('./core/database').init(app.dataSources);
         require('./core/smtp').init();
+        require('./core/cluster').init();
         require('./core/mixins');
         require('./core/filters');
 
diff --git a/print/package-lock.json b/print/package-lock.json
index 8e55f5c1e4..02c5fa77d4 100644
--- a/print/package-lock.json
+++ b/print/package-lock.json
@@ -14,9 +14,10 @@
         "js-yaml": "^3.13.1",
         "jsonexport": "^3.2.0",
         "juice": "^5.2.0",
+        "log4js": "^6.7.0",
         "mysql2": "^1.7.0",
         "nodemailer": "^4.7.0",
-        "puppeteer": "^18.0.5",
+        "puppeteer-cluster": "^0.23.0",
         "qrcode": "^1.4.2",
         "strftime": "^0.10.0",
         "vue": "^2.6.10",
@@ -37,12 +38,14 @@
     "node_modules/@types/node": {
       "version": "18.8.2",
       "license": "MIT",
-      "optional": true
+      "optional": true,
+      "peer": true
     },
     "node_modules/@types/yauzl": {
       "version": "2.10.0",
       "license": "MIT",
       "optional": true,
+      "peer": true,
       "dependencies": {
         "@types/node": "*"
       }
@@ -58,6 +61,7 @@
     "node_modules/agent-base": {
       "version": "6.0.2",
       "license": "MIT",
+      "peer": true,
       "dependencies": {
         "debug": "4"
       },
@@ -138,7 +142,8 @@
     },
     "node_modules/balanced-match": {
       "version": "1.0.2",
-      "license": "MIT"
+      "license": "MIT",
+      "peer": true
     },
     "node_modules/base64-js": {
       "version": "1.5.1",
@@ -156,7 +161,8 @@
           "url": "https://feross.org/support"
         }
       ],
-      "license": "MIT"
+      "license": "MIT",
+      "peer": true
     },
     "node_modules/bcrypt-pbkdf": {
       "version": "1.0.2",
@@ -168,6 +174,7 @@
     "node_modules/bl": {
       "version": "4.1.0",
       "license": "MIT",
+      "peer": true,
       "dependencies": {
         "buffer": "^5.5.0",
         "inherits": "^2.0.4",
@@ -181,6 +188,7 @@
     "node_modules/brace-expansion": {
       "version": "1.1.11",
       "license": "MIT",
+      "peer": true,
       "dependencies": {
         "balanced-match": "^1.0.0",
         "concat-map": "0.0.1"
@@ -203,6 +211,7 @@
         }
       ],
       "license": "MIT",
+      "peer": true,
       "dependencies": {
         "base64-js": "^1.3.1",
         "ieee754": "^1.1.13"
@@ -211,6 +220,7 @@
     "node_modules/buffer-crc32": {
       "version": "0.2.13",
       "license": "MIT",
+      "peer": true,
       "engines": {
         "node": "*"
       }
@@ -265,7 +275,8 @@
     },
     "node_modules/chownr": {
       "version": "1.1.4",
-      "license": "ISC"
+      "license": "ISC",
+      "peer": true
     },
     "node_modules/cliui": {
       "version": "6.0.0",
@@ -303,7 +314,8 @@
     },
     "node_modules/concat-map": {
       "version": "0.0.1",
-      "license": "MIT"
+      "license": "MIT",
+      "peer": true
     },
     "node_modules/core-util-is": {
       "version": "1.0.2",
@@ -312,6 +324,7 @@
     "node_modules/cross-fetch": {
       "version": "3.1.5",
       "license": "MIT",
+      "peer": true,
       "dependencies": {
         "node-fetch": "2.6.7"
       }
@@ -372,6 +385,14 @@
         "node": ">= 4"
       }
     },
+    "node_modules/date-format": {
+      "version": "4.0.14",
+      "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.14.tgz",
+      "integrity": "sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==",
+      "engines": {
+        "node": ">=4.0"
+      }
+    },
     "node_modules/debug": {
       "version": "4.3.4",
       "license": "MIT",
@@ -417,7 +438,8 @@
     },
     "node_modules/devtools-protocol": {
       "version": "0.0.1045489",
-      "license": "BSD-3-Clause"
+      "license": "BSD-3-Clause",
+      "peer": true
     },
     "node_modules/dijkstrajs": {
       "version": "1.0.2",
@@ -468,6 +490,7 @@
     "node_modules/end-of-stream": {
       "version": "1.4.4",
       "license": "MIT",
+      "peer": true,
       "dependencies": {
         "once": "^1.4.0"
       }
@@ -501,6 +524,7 @@
     "node_modules/extract-zip": {
       "version": "2.0.1",
       "license": "BSD-2-Clause",
+      "peer": true,
       "dependencies": {
         "debug": "^4.1.1",
         "get-stream": "^5.1.0",
@@ -534,6 +558,7 @@
     "node_modules/fd-slicer": {
       "version": "1.1.0",
       "license": "MIT",
+      "peer": true,
       "dependencies": {
         "pend": "~1.2.0"
       }
@@ -549,6 +574,11 @@
         "node": ">=8"
       }
     },
+    "node_modules/flatted": {
+      "version": "3.2.7",
+      "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz",
+      "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ=="
+    },
     "node_modules/forever-agent": {
       "version": "0.6.1",
       "license": "Apache-2.0",
@@ -570,7 +600,8 @@
     },
     "node_modules/fs-constants": {
       "version": "1.0.0",
-      "license": "MIT"
+      "license": "MIT",
+      "peer": true
     },
     "node_modules/fs-extra": {
       "version": "7.0.1",
@@ -586,7 +617,8 @@
     },
     "node_modules/fs.realpath": {
       "version": "1.0.0",
-      "license": "ISC"
+      "license": "ISC",
+      "peer": true
     },
     "node_modules/function-bind": {
       "version": "1.1.1",
@@ -609,6 +641,7 @@
     "node_modules/get-stream": {
       "version": "5.2.0",
       "license": "MIT",
+      "peer": true,
       "dependencies": {
         "pump": "^3.0.0"
       },
@@ -629,6 +662,7 @@
     "node_modules/glob": {
       "version": "7.2.3",
       "license": "ISC",
+      "peer": true,
       "dependencies": {
         "fs.realpath": "^1.0.0",
         "inflight": "^1.0.4",
@@ -723,6 +757,7 @@
     "node_modules/https-proxy-agent": {
       "version": "5.0.1",
       "license": "MIT",
+      "peer": true,
       "dependencies": {
         "agent-base": "6",
         "debug": "4"
@@ -757,7 +792,8 @@
           "url": "https://feross.org/support"
         }
       ],
-      "license": "BSD-3-Clause"
+      "license": "BSD-3-Clause",
+      "peer": true
     },
     "node_modules/image-size": {
       "version": "0.7.5",
@@ -772,6 +808,7 @@
     "node_modules/inflight": {
       "version": "1.0.6",
       "license": "ISC",
+      "peer": true,
       "dependencies": {
         "once": "^1.3.0",
         "wrappy": "1"
@@ -976,6 +1013,21 @@
       "version": "4.5.0",
       "license": "MIT"
     },
+    "node_modules/log4js": {
+      "version": "6.7.0",
+      "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.7.0.tgz",
+      "integrity": "sha512-KA0W9ffgNBLDj6fZCq/lRbgR6ABAodRIDHrZnS48vOtfKa4PzWImb0Md1lmGCdO3n3sbCm/n1/WmrNlZ8kCI3Q==",
+      "dependencies": {
+        "date-format": "^4.0.14",
+        "debug": "^4.3.4",
+        "flatted": "^3.2.7",
+        "rfdc": "^1.3.0",
+        "streamroller": "^3.1.3"
+      },
+      "engines": {
+        "node": ">=8.0"
+      }
+    },
     "node_modules/long": {
       "version": "4.0.0",
       "license": "Apache-2.0"
@@ -1021,6 +1073,7 @@
     "node_modules/minimatch": {
       "version": "3.1.2",
       "license": "ISC",
+      "peer": true,
       "dependencies": {
         "brace-expansion": "^1.1.7"
       },
@@ -1030,7 +1083,8 @@
     },
     "node_modules/mkdirp-classic": {
       "version": "0.5.3",
-      "license": "MIT"
+      "license": "MIT",
+      "peer": true
     },
     "node_modules/ms": {
       "version": "2.1.2",
@@ -1092,6 +1146,7 @@
     "node_modules/node-fetch": {
       "version": "2.6.7",
       "license": "MIT",
+      "peer": true,
       "dependencies": {
         "whatwg-url": "^5.0.0"
       },
@@ -1131,6 +1186,7 @@
     "node_modules/once": {
       "version": "1.4.0",
       "license": "ISC",
+      "peer": true,
       "dependencies": {
         "wrappy": "1"
       }
@@ -1175,6 +1231,7 @@
     "node_modules/path-is-absolute": {
       "version": "1.0.1",
       "license": "MIT",
+      "peer": true,
       "engines": {
         "node": ">=0.10.0"
       }
@@ -1192,7 +1249,8 @@
     },
     "node_modules/pend": {
       "version": "1.2.0",
-      "license": "MIT"
+      "license": "MIT",
+      "peer": true
     },
     "node_modules/performance-now": {
       "version": "2.1.0",
@@ -1234,13 +1292,15 @@
     "node_modules/progress": {
       "version": "2.0.3",
       "license": "MIT",
+      "peer": true,
       "engines": {
         "node": ">=0.4.0"
       }
     },
     "node_modules/proxy-from-env": {
       "version": "1.1.0",
-      "license": "MIT"
+      "license": "MIT",
+      "peer": true
     },
     "node_modules/pseudomap": {
       "version": "1.0.2",
@@ -1253,6 +1313,7 @@
     "node_modules/pump": {
       "version": "3.0.0",
       "license": "MIT",
+      "peer": true,
       "dependencies": {
         "end-of-stream": "^1.1.0",
         "once": "^1.3.1"
@@ -1269,6 +1330,7 @@
       "version": "18.2.0",
       "hasInstallScript": true,
       "license": "Apache-2.0",
+      "peer": true,
       "dependencies": {
         "https-proxy-agent": "5.0.1",
         "progress": "2.0.3",
@@ -1279,9 +1341,21 @@
         "node": ">=14.1.0"
       }
     },
+    "node_modules/puppeteer-cluster": {
+      "version": "0.23.0",
+      "resolved": "https://registry.npmjs.org/puppeteer-cluster/-/puppeteer-cluster-0.23.0.tgz",
+      "integrity": "sha512-108terIWDzPrQopmoYSPd5yDoy3FGJ2dNnoGMkGYPs6xtkdhgaECwpfZkzaRToMQPZibUOz0/dSSGgPEdXEhkQ==",
+      "dependencies": {
+        "debug": "^4.3.3"
+      },
+      "peerDependencies": {
+        "puppeteer": ">=1.5.0"
+      }
+    },
     "node_modules/puppeteer-core": {
       "version": "18.2.0",
       "license": "Apache-2.0",
+      "peer": true,
       "dependencies": {
         "cross-fetch": "3.1.5",
         "debug": "4.3.4",
@@ -1396,9 +1470,15 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/rfdc": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz",
+      "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA=="
+    },
     "node_modules/rimraf": {
       "version": "3.0.2",
       "license": "ISC",
+      "peer": true,
       "dependencies": {
         "glob": "^7.1.3"
       },
@@ -1524,6 +1604,32 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/streamroller": {
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.1.3.tgz",
+      "integrity": "sha512-CphIJyFx2SALGHeINanjFRKQ4l7x2c+rXYJ4BMq0gd+ZK0gi4VT8b+eHe2wi58x4UayBAKx4xtHpXT/ea1cz8w==",
+      "dependencies": {
+        "date-format": "^4.0.14",
+        "debug": "^4.3.4",
+        "fs-extra": "^8.1.0"
+      },
+      "engines": {
+        "node": ">=8.0"
+      }
+    },
+    "node_modules/streamroller/node_modules/fs-extra": {
+      "version": "8.1.0",
+      "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
+      "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
+      "dependencies": {
+        "graceful-fs": "^4.2.0",
+        "jsonfile": "^4.0.0",
+        "universalify": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=6 <7 || >=8"
+      }
+    },
     "node_modules/strftime": {
       "version": "0.10.1",
       "license": "MIT",
@@ -1583,6 +1689,7 @@
     "node_modules/tar-fs": {
       "version": "2.1.1",
       "license": "MIT",
+      "peer": true,
       "dependencies": {
         "chownr": "^1.1.1",
         "mkdirp-classic": "^0.5.2",
@@ -1593,6 +1700,7 @@
     "node_modules/tar-stream": {
       "version": "2.2.0",
       "license": "MIT",
+      "peer": true,
       "dependencies": {
         "bl": "^4.0.3",
         "end-of-stream": "^1.4.1",
@@ -1606,7 +1714,8 @@
     },
     "node_modules/through": {
       "version": "2.3.8",
-      "license": "MIT"
+      "license": "MIT",
+      "peer": true
     },
     "node_modules/tough-cookie": {
       "version": "2.5.0",
@@ -1621,7 +1730,8 @@
     },
     "node_modules/tr46": {
       "version": "0.0.3",
-      "license": "MIT"
+      "license": "MIT",
+      "peer": true
     },
     "node_modules/tunnel-agent": {
       "version": "0.6.0",
@@ -1640,6 +1750,7 @@
     "node_modules/unbzip2-stream": {
       "version": "1.4.3",
       "license": "MIT",
+      "peer": true,
       "dependencies": {
         "buffer": "^5.2.1",
         "through": "^2.3.8"
@@ -1891,11 +2002,13 @@
     },
     "node_modules/webidl-conversions": {
       "version": "3.0.1",
-      "license": "BSD-2-Clause"
+      "license": "BSD-2-Clause",
+      "peer": true
     },
     "node_modules/whatwg-url": {
       "version": "5.0.0",
       "license": "MIT",
+      "peer": true,
       "dependencies": {
         "tr46": "~0.0.3",
         "webidl-conversions": "^3.0.0"
@@ -1956,11 +2069,13 @@
     },
     "node_modules/wrappy": {
       "version": "1.0.2",
-      "license": "ISC"
+      "license": "ISC",
+      "peer": true
     },
     "node_modules/ws": {
       "version": "8.9.0",
       "license": "MIT",
+      "peer": true,
       "engines": {
         "node": ">=10.0.0"
       },
@@ -2026,6 +2141,7 @@
     "node_modules/yauzl": {
       "version": "2.10.0",
       "license": "MIT",
+      "peer": true,
       "dependencies": {
         "buffer-crc32": "~0.2.3",
         "fd-slicer": "~1.1.0"
@@ -2038,11 +2154,13 @@
     },
     "@types/node": {
       "version": "18.8.2",
-      "optional": true
+      "optional": true,
+      "peer": true
     },
     "@types/yauzl": {
       "version": "2.10.0",
       "optional": true,
+      "peer": true,
       "requires": {
         "@types/node": "*"
       }
@@ -2057,6 +2175,7 @@
     },
     "agent-base": {
       "version": "6.0.2",
+      "peer": true,
       "requires": {
         "debug": "4"
       }
@@ -2107,10 +2226,12 @@
       "version": "1.11.0"
     },
     "balanced-match": {
-      "version": "1.0.2"
+      "version": "1.0.2",
+      "peer": true
     },
     "base64-js": {
-      "version": "1.5.1"
+      "version": "1.5.1",
+      "peer": true
     },
     "bcrypt-pbkdf": {
       "version": "1.0.2",
@@ -2120,6 +2241,7 @@
     },
     "bl": {
       "version": "4.1.0",
+      "peer": true,
       "requires": {
         "buffer": "^5.5.0",
         "inherits": "^2.0.4",
@@ -2131,6 +2253,7 @@
     },
     "brace-expansion": {
       "version": "1.1.11",
+      "peer": true,
       "requires": {
         "balanced-match": "^1.0.0",
         "concat-map": "0.0.1"
@@ -2138,13 +2261,15 @@
     },
     "buffer": {
       "version": "5.7.1",
+      "peer": true,
       "requires": {
         "base64-js": "^1.3.1",
         "ieee754": "^1.1.13"
       }
     },
     "buffer-crc32": {
-      "version": "0.2.13"
+      "version": "0.2.13",
+      "peer": true
     },
     "camelcase": {
       "version": "5.3.1"
@@ -2182,7 +2307,8 @@
       }
     },
     "chownr": {
-      "version": "1.1.4"
+      "version": "1.1.4",
+      "peer": true
     },
     "cliui": {
       "version": "6.0.0",
@@ -2211,13 +2337,15 @@
       "version": "2.20.3"
     },
     "concat-map": {
-      "version": "0.0.1"
+      "version": "0.0.1",
+      "peer": true
     },
     "core-util-is": {
       "version": "1.0.2"
     },
     "cross-fetch": {
       "version": "3.1.5",
+      "peer": true,
       "requires": {
         "node-fetch": "2.6.7"
       }
@@ -2260,6 +2388,11 @@
         "mimer": "^1.0.0"
       }
     },
+    "date-format": {
+      "version": "4.0.14",
+      "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.14.tgz",
+      "integrity": "sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg=="
+    },
     "debug": {
       "version": "4.3.4",
       "requires": {
@@ -2279,7 +2412,8 @@
       "version": "1.5.1"
     },
     "devtools-protocol": {
-      "version": "0.0.1045489"
+      "version": "0.0.1045489",
+      "peer": true
     },
     "dijkstrajs": {
       "version": "1.0.2"
@@ -2322,6 +2456,7 @@
     },
     "end-of-stream": {
       "version": "1.4.4",
+      "peer": true,
       "requires": {
         "once": "^1.4.0"
       }
@@ -2340,6 +2475,7 @@
     },
     "extract-zip": {
       "version": "2.0.1",
+      "peer": true,
       "requires": {
         "@types/yauzl": "^2.9.1",
         "debug": "^4.1.1",
@@ -2358,6 +2494,7 @@
     },
     "fd-slicer": {
       "version": "1.1.0",
+      "peer": true,
       "requires": {
         "pend": "~1.2.0"
       }
@@ -2369,6 +2506,11 @@
         "path-exists": "^4.0.0"
       }
     },
+    "flatted": {
+      "version": "3.2.7",
+      "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz",
+      "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ=="
+    },
     "forever-agent": {
       "version": "0.6.1"
     },
@@ -2381,7 +2523,8 @@
       }
     },
     "fs-constants": {
-      "version": "1.0.0"
+      "version": "1.0.0",
+      "peer": true
     },
     "fs-extra": {
       "version": "7.0.1",
@@ -2392,7 +2535,8 @@
       }
     },
     "fs.realpath": {
-      "version": "1.0.0"
+      "version": "1.0.0",
+      "peer": true
     },
     "function-bind": {
       "version": "1.1.1"
@@ -2408,6 +2552,7 @@
     },
     "get-stream": {
       "version": "5.2.0",
+      "peer": true,
       "requires": {
         "pump": "^3.0.0"
       }
@@ -2420,6 +2565,7 @@
     },
     "glob": {
       "version": "7.2.3",
+      "peer": true,
       "requires": {
         "fs.realpath": "^1.0.0",
         "inflight": "^1.0.4",
@@ -2478,6 +2624,7 @@
     },
     "https-proxy-agent": {
       "version": "5.0.1",
+      "peer": true,
       "requires": {
         "agent-base": "6",
         "debug": "4"
@@ -2490,13 +2637,15 @@
       }
     },
     "ieee754": {
-      "version": "1.2.1"
+      "version": "1.2.1",
+      "peer": true
     },
     "image-size": {
       "version": "0.7.5"
     },
     "inflight": {
       "version": "1.0.6",
+      "peer": true,
       "requires": {
         "once": "^1.3.0",
         "wrappy": "1"
@@ -2642,6 +2791,18 @@
     "lodash.uniq": {
       "version": "4.5.0"
     },
+    "log4js": {
+      "version": "6.7.0",
+      "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.7.0.tgz",
+      "integrity": "sha512-KA0W9ffgNBLDj6fZCq/lRbgR6ABAodRIDHrZnS48vOtfKa4PzWImb0Md1lmGCdO3n3sbCm/n1/WmrNlZ8kCI3Q==",
+      "requires": {
+        "date-format": "^4.0.14",
+        "debug": "^4.3.4",
+        "flatted": "^3.2.7",
+        "rfdc": "^1.3.0",
+        "streamroller": "^3.1.3"
+      }
+    },
     "long": {
       "version": "4.0.0"
     },
@@ -2668,12 +2829,14 @@
     },
     "minimatch": {
       "version": "3.1.2",
+      "peer": true,
       "requires": {
         "brace-expansion": "^1.1.7"
       }
     },
     "mkdirp-classic": {
-      "version": "0.5.3"
+      "version": "0.5.3",
+      "peer": true
     },
     "ms": {
       "version": "2.1.2"
@@ -2717,6 +2880,7 @@
     },
     "node-fetch": {
       "version": "2.6.7",
+      "peer": true,
       "requires": {
         "whatwg-url": "^5.0.0"
       }
@@ -2735,6 +2899,7 @@
     },
     "once": {
       "version": "1.4.0",
+      "peer": true,
       "requires": {
         "wrappy": "1"
       }
@@ -2758,7 +2923,8 @@
       "version": "4.0.0"
     },
     "path-is-absolute": {
-      "version": "1.0.1"
+      "version": "1.0.1",
+      "peer": true
     },
     "path-key": {
       "version": "2.0.1"
@@ -2767,7 +2933,8 @@
       "version": "1.0.7"
     },
     "pend": {
-      "version": "1.2.0"
+      "version": "1.2.0",
+      "peer": true
     },
     "performance-now": {
       "version": "2.1.0"
@@ -2787,10 +2954,12 @@
       }
     },
     "progress": {
-      "version": "2.0.3"
+      "version": "2.0.3",
+      "peer": true
     },
     "proxy-from-env": {
-      "version": "1.1.0"
+      "version": "1.1.0",
+      "peer": true
     },
     "pseudomap": {
       "version": "1.0.2"
@@ -2800,6 +2969,7 @@
     },
     "pump": {
       "version": "3.0.0",
+      "peer": true,
       "requires": {
         "end-of-stream": "^1.1.0",
         "once": "^1.3.1"
@@ -2810,6 +2980,7 @@
     },
     "puppeteer": {
       "version": "18.2.0",
+      "peer": true,
       "requires": {
         "https-proxy-agent": "5.0.1",
         "progress": "2.0.3",
@@ -2817,8 +2988,17 @@
         "puppeteer-core": "18.2.0"
       }
     },
+    "puppeteer-cluster": {
+      "version": "0.23.0",
+      "resolved": "https://registry.npmjs.org/puppeteer-cluster/-/puppeteer-cluster-0.23.0.tgz",
+      "integrity": "sha512-108terIWDzPrQopmoYSPd5yDoy3FGJ2dNnoGMkGYPs6xtkdhgaECwpfZkzaRToMQPZibUOz0/dSSGgPEdXEhkQ==",
+      "requires": {
+        "debug": "^4.3.3"
+      }
+    },
     "puppeteer-core": {
       "version": "18.2.0",
+      "peer": true,
       "requires": {
         "cross-fetch": "3.1.5",
         "debug": "4.3.4",
@@ -2897,8 +3077,14 @@
         "supports-preserve-symlinks-flag": "^1.0.0"
       }
     },
+    "rfdc": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz",
+      "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA=="
+    },
     "rimraf": {
       "version": "3.0.2",
+      "peer": true,
       "requires": {
         "glob": "^7.1.3"
       }
@@ -2962,6 +3148,28 @@
         "tweetnacl": "~0.14.0"
       }
     },
+    "streamroller": {
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.1.3.tgz",
+      "integrity": "sha512-CphIJyFx2SALGHeINanjFRKQ4l7x2c+rXYJ4BMq0gd+ZK0gi4VT8b+eHe2wi58x4UayBAKx4xtHpXT/ea1cz8w==",
+      "requires": {
+        "date-format": "^4.0.14",
+        "debug": "^4.3.4",
+        "fs-extra": "^8.1.0"
+      },
+      "dependencies": {
+        "fs-extra": {
+          "version": "8.1.0",
+          "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
+          "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
+          "requires": {
+            "graceful-fs": "^4.2.0",
+            "jsonfile": "^4.0.0",
+            "universalify": "^0.1.0"
+          }
+        }
+      }
+    },
     "strftime": {
       "version": "0.10.1"
     },
@@ -2996,6 +3204,7 @@
     },
     "tar-fs": {
       "version": "2.1.1",
+      "peer": true,
       "requires": {
         "chownr": "^1.1.1",
         "mkdirp-classic": "^0.5.2",
@@ -3005,6 +3214,7 @@
     },
     "tar-stream": {
       "version": "2.2.0",
+      "peer": true,
       "requires": {
         "bl": "^4.0.3",
         "end-of-stream": "^1.4.1",
@@ -3014,7 +3224,8 @@
       }
     },
     "through": {
-      "version": "2.3.8"
+      "version": "2.3.8",
+      "peer": true
     },
     "tough-cookie": {
       "version": "2.5.0",
@@ -3024,7 +3235,8 @@
       }
     },
     "tr46": {
-      "version": "0.0.3"
+      "version": "0.0.3",
+      "peer": true
     },
     "tunnel-agent": {
       "version": "0.6.0",
@@ -3037,6 +3249,7 @@
     },
     "unbzip2-stream": {
       "version": "1.4.3",
+      "peer": true,
       "requires": {
         "buffer": "^5.2.1",
         "through": "^2.3.8"
@@ -3197,10 +3410,12 @@
       }
     },
     "webidl-conversions": {
-      "version": "3.0.1"
+      "version": "3.0.1",
+      "peer": true
     },
     "whatwg-url": {
       "version": "5.0.0",
+      "peer": true,
       "requires": {
         "tr46": "~0.0.3",
         "webidl-conversions": "^3.0.0"
@@ -3241,10 +3456,12 @@
       }
     },
     "wrappy": {
-      "version": "1.0.2"
+      "version": "1.0.2",
+      "peer": true
     },
     "ws": {
       "version": "8.9.0",
+      "peer": true,
       "requires": {}
     },
     "xtend": {
@@ -3281,6 +3498,7 @@
     },
     "yauzl": {
       "version": "2.10.0",
+      "peer": true,
       "requires": {
         "buffer-crc32": "~0.2.3",
         "fd-slicer": "~1.1.0"
diff --git a/print/package.json b/print/package.json
index ed1df5037e..a6c53a28f9 100755
--- a/print/package.json
+++ b/print/package.json
@@ -18,9 +18,10 @@
     "js-yaml": "^3.13.1",
     "jsonexport": "^3.2.0",
     "juice": "^5.2.0",
+    "log4js": "^6.7.0",
     "mysql2": "^1.7.0",
     "nodemailer": "^4.7.0",
-    "puppeteer": "^18.0.5",
+    "puppeteer-cluster": "^0.23.0",
     "qrcode": "^1.4.2",
     "strftime": "^0.10.0",
     "vue": "^2.6.10",

From 192e61a70d51f416048c441d0d819a4566224416 Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Wed, 19 Oct 2022 14:54:13 +0200
Subject: [PATCH 082/151] hotFix(route_index): fix driverRoutePdf

---
 modules/route/back/methods/route/driverRoutePdf.js   | 4 ++--
 modules/route/front/index/index.js                   | 5 +----
 modules/route/front/index/index.spec.js              | 8 +++-----
 print/templates/reports/driver-route/driver-route.js | 3 +++
 print/templates/reports/driver-route/locale/es.yml   | 5 +++--
 5 files changed, 12 insertions(+), 13 deletions(-)

diff --git a/modules/route/back/methods/route/driverRoutePdf.js b/modules/route/back/methods/route/driverRoutePdf.js
index 161eb71afa..65748afad3 100644
--- a/modules/route/back/methods/route/driverRoutePdf.js
+++ b/modules/route/back/methods/route/driverRoutePdf.js
@@ -6,9 +6,9 @@ module.exports = Self => {
         accepts: [
             {
                 arg: 'id',
-                type: 'number',
+                type: 'string',
                 required: true,
-                description: 'The client id',
+                description: 'The route id',
                 http: {source: 'path'}
             },
             {
diff --git a/modules/route/front/index/index.js b/modules/route/front/index/index.js
index 6845bf73fa..9258c8fac4 100644
--- a/modules/route/front/index/index.js
+++ b/modules/route/front/index/index.js
@@ -39,10 +39,7 @@ export default class Controller extends Section {
             routes.push(route.id);
         const routesId = routes.join(',');
 
-        this.vnReport.show('driver-route', {
-            authorization: this.vnToken.token,
-            routeId: routesId
-        });
+        this.vnReport.show(`Routes/${routesId}/driver-route-pdf`);
     }
 
     openClonationDialog() {
diff --git a/modules/route/front/index/index.spec.js b/modules/route/front/index/index.spec.js
index 37386bc384..05dd564336 100644
--- a/modules/route/front/index/index.spec.js
+++ b/modules/route/front/index/index.spec.js
@@ -49,14 +49,12 @@ describe('Component vnRouteIndex', () => {
             const data = controller.$.model.data;
             data[0].checked = true;
             data[2].checked = true;
-            const expectedParams = {
-                authorization: null,
-                routeId: '1,3'
-            };
+
+            const routeIds = '1,3';
 
             controller.showRouteReport();
 
-            expect(controller.vnReport.show).toHaveBeenCalledWith('driver-route', expectedParams);
+            expect(controller.vnReport.show).toHaveBeenCalledWith(`Routes/${routeIds}/driver-route-pdf`);
         });
     });
 
diff --git a/print/templates/reports/driver-route/driver-route.js b/print/templates/reports/driver-route/driver-route.js
index 2de3d51924..b142a446e9 100755
--- a/print/templates/reports/driver-route/driver-route.js
+++ b/print/templates/reports/driver-route/driver-route.js
@@ -14,6 +14,9 @@ module.exports = {
         const routes = await this.fetchRoutes(ids);
         const tickets = await this.fetchTickets(ids);
 
+        if (!tickets || !tickets.id)
+            throw new Error('This route(s) not have ticket(s)');
+
         const map = new Map();
 
         for (let route of routes)
diff --git a/print/templates/reports/driver-route/locale/es.yml b/print/templates/reports/driver-route/locale/es.yml
index 3fb6b68859..d065d62e05 100644
--- a/print/templates/reports/driver-route/locale/es.yml
+++ b/print/templates/reports/driver-route/locale/es.yml
@@ -20,6 +20,7 @@ phone: Teléfono
 warehouse: Almacén
 salesPerson: Comercial
 import: Importe
-route: Ruta 
+route: Ruta
 routeId: Ruta {0}
-ticket: Ticket
\ No newline at end of file
+ticket: Ticket
+This route(s) not have ticket(s): Esta ruta(s) no tiene ticket(s)

From 4b124055869e955f3eb29285674585006c2187de Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Wed, 19 Oct 2022 15:15:54 +0200
Subject: [PATCH 083/151] feat: report invoiceInPdf

---
 db/dump/fixtures.sql                          |   6 +-
 .../reports/invoiceIn/invoiceIn.html          | 143 +++---------------
 .../templates/reports/invoiceIn/invoiceIn.js  |  22 ++-
 .../templates/reports/invoiceIn/locale/en.yml |  27 +---
 .../templates/reports/invoiceIn/locale/es.yml |  21 +--
 .../reports/invoiceIn/sql/invoice.sql         |   4 +-
 .../templates/reports/invoiceIn/sql/taxes.sql |  19 +--
 7 files changed, 66 insertions(+), 176 deletions(-)

diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql
index 7e59c1a54a..8e11137814 100644
--- a/db/dump/fixtures.sql
+++ b/db/dump/fixtures.sql
@@ -14,10 +14,10 @@ INSERT INTO `salix`.`AccessToken` (`id`, `ttl`, `created`, `userId`)
         ('DEFAULT_TOKEN', '1209600', util.VN_CURDATE(), 66);
 
 INSERT INTO `salix`.`printConfig` (`id`, `itRecipient`, `incidencesEmail`)
-    VALUES 
+    VALUES
         (1, 'it@gotamcity.com', 'incidences@gotamcity.com');
 
-INSERT INTO `vn`.`ticketConfig` (`id`, `scopeDays`) 
+INSERT INTO `vn`.`ticketConfig` (`id`, `scopeDays`)
     VALUES
         ('1', '6');
 
@@ -349,7 +349,7 @@ INSERT INTO `vn`.`clientManaCache`(`clientFk`, `mana`, `dated`)
 
 INSERT INTO `vn`.`clientConfig`(`riskTolerance`, `maxCreditRows`)
     VALUES
-        (200, 10);
+        (200, null);
 
 INSERT INTO `vn`.`address`(`id`, `nickname`, `street`, `city`, `postalCode`, `provinceFk`, `phone`, `mobile`, `isActive`, `clientFk`, `agencyModeFk`, `longitude`, `latitude`, `isEqualizated`, `isDefaultAddress`)
     VALUES
diff --git a/print/templates/reports/invoiceIn/invoiceIn.html b/print/templates/reports/invoiceIn/invoiceIn.html
index a1d488560c..4bc6d8ee0e 100644
--- a/print/templates/reports/invoiceIn/invoiceIn.html
+++ b/print/templates/reports/invoiceIn/invoiceIn.html
@@ -46,45 +46,21 @@
                                                 <div>
                                                     {{invoice.postcodeCity}}
                                                 </div>
-                                                <div>
+                                                <div v-if="invoice.nif">
                                                     {{$t('fiscalId')}}: {{invoice.nif}}
                                                 </div>
-                                                <div>
+                                                <div v-if="invoice.phone">
                                                     {{$t('phone')}}: {{invoice.phone}}
                                                 </div>
                                             </div>
                                         </div>
                                     </div>
                                 </div>
-                                <!--
-                                 Rectified invoices block
-                                <div class="size100 no-page-break" v-if="rectified.length > 0">
-                                    <h2>{{$t('rectifiedInvoices')}}</h2>
-                                    <table class="column-oriented">
-                                        <thead>
-                                            <tr>
-                                                <th>{{$t('invoice')}}</th>
-                                                <th>{{$t('issued')}}</th>
-                                                <th class="number">{{$t('amount')}}</th>
-                                                <th width="50%">{{$t('description')}}</th>
-                                            </tr>
-                                        </thead>
-                                        <tbody>
-                                            <tr v-for="row in rectified">
-                                                <td>{{row.ref}}</td>
-                                                <td>{{row.issued | date}}</td>
-                                                <td class="number">{{row.amount | currency('EUR', $i18n.locale)}}</td>
-                                                <td width="50%">{{row.description}}</td>
-                                            </tr>
-                                        </tbody>
-                                    </table>
-                                </div>
-                                 End of rectified invoices block-->
 
                                 <div class="vn-mt-lg" v-for="entry in entries">
                                     <div class="table-title clearfix">
                                         <div class="pull-left">
-                                            <h2>{{$t('invoiceIn')}}</strong>
+                                            <h2>{{$t('invoiceId')}}</strong>
                                         </div>
                                         <div class="pull-left vn-mr-md">
                                             <div class="field rectangle">
@@ -153,7 +129,7 @@
                                 <!-- End of sales block -->
 
                                 <div class="columns vn-mt-xl">
-                                    Taxes block
+                                    <!-- Taxes block -->
                                     <div id="taxes" class="size50 pull-right no-page-break" v-if="taxes">
                                         <table class="column-oriented">
                                             <thead>
@@ -175,9 +151,9 @@
                                                 <tr v-for="tax in taxes">
                                                     <td width="45%">{{tax.name}}</td>
                                                     <td width="25%" class="number">
-                                                        {{tax.base | currency('EUR', $i18n.locale)}}
+                                                        {{tax.taxableBase | currency('EUR', $i18n.locale)}}
                                                     </td>
-                                                    <td>{{tax.vatPercent | percentage}}</td>
+                                                    <td>{{tax.rate | percentage}}</td>
                                                     <td class="number">{{tax.vat | currency('EUR', $i18n.locale)}}</td>
                                                 </tr>
                                             </tbody>
@@ -185,14 +161,14 @@
                                                 <tr class="font bold">
                                                     <td width="45%">{{$t('subtotal')}}</td>
                                                     <td width="20%" class="number">
-                                                        {{sumTotal(taxes, 'base') | currency('EUR', $i18n.locale)}}
+                                                        {{sumTotal(taxes, 'taxableBase') | currency('EUR', $i18n.locale)}}
                                                     </td>
                                                     <td></td>
                                                     <td class="number">{{sumTotal(taxes, 'vat') | currency('EUR', $i18n.locale)}}</td>
                                                 </tr>
                                                 <tr class="font bold">
                                                     <td colspan="2">{{$t('total')}}</td>
-                                                    <td colspan="2" class="number">{{taxTotal | currency('EUR', $i18n.locale)}}</td>
+                                                    <td colspan="2" class="number">{{taxTotal() | currency('EUR', $i18n.locale)}}</td>
                                                 </tr>
                                             </tfoot>
                                         </table>
@@ -205,109 +181,30 @@
                                         </div>
                                     </div>
                                     <!-- End of taxes block -->
-                                    <!--
-                                     Phytosanitary block
-                                    <div id="phytosanitary" class="size50 pull-left no-page-break">
-                                        <div class="panel">
-                                            <div class="body">
-                                                <div class="flag">
-                                                    <div class="columns">
-                                                        <div class="size25">
-                                                            <img v-bind:src="getReportSrc('europe.png')"/>
-                                                        </div>
-                                                        <div class="size75 flag-text">
-                                                            <strong>{{$t('plantPassport')}}</strong><br/>
-                                                        </div>
-                                                    </div>
-                                                </div>
-                                                <div class="phytosanitary-info">
-                                                    <div>
-                                                        <strong>A</strong>
-                                                        <span>{{botanical}}</span>
-                                                    </div>
-                                                    <div>
-                                                        <strong>B</strong>
-                                                        <span>ES17462130</span>
-                                                    </div>
-                                                    <div>
-                                                        <strong>C</strong>
-                                                        <span>{{ticketsId}}</span>
-                                                    </div>
-                                                    <div>
-                                                        <strong>D</strong>
-                                                        <span>ES</span>
-                                                    </div>
-                                                </div>
-                                            </div>
-                                        </div>
-                                    </div>
-                                     End of phytosanitary block
-                                </div>
 
-
-                                 Intrastat block
-                                <div class="size100 no-page-break" v-if="intrastat.length > 0">
-                                    <h2>{{$t('intrastat')}}</h2>
-                                    <table class="column-oriented">
-                                        <thead>
-                                            <tr>
-                                                <th>{{$t('code')}}</th>
-                                                <th width="50%">{{$t('description')}}</th>
-                                                <th class="number">{{$t('stems')}}</th>
-                                                <th class="number">{{$t('netKg')}}</th>
-                                                <th class="number">{{$t('amount')}}</th>
-                                            </tr>
-                                        </thead>
-                                        <tbody>
-                                            <tr v-for="row in intrastat">
-                                                <td>{{row.code}}</td>
-                                                <td width="50%">{{row.description}}</td>
-                                                <td class="number">{{row.stems | number($i18n.locale)}}</td>
-                                                <td class="number">{{row.netKg | number($i18n.locale)}}</td>
-                                                <td class="number">{{row.subtotal | currency('EUR', $i18n.locale)}}</td>
-                                            </tr>
-                                        </tbody>
-                                        <tfoot>
-                                            <tr>
-                                                <td colspan="2"></td>
-                                                <td class="number">
-                                                    <strong>{{sumTotal(intrastat, 'stems') | number($i18n.locale)}}</strong>
-                                                </td>
-                                                <td class="number">
-                                                    <strong>{{sumTotal(intrastat, 'netKg') | number($i18n.locale)}}</strong>
-                                                </td>
-                                                <td class="number">
-                                                    <strong>{{sumTotal(intrastat, 'subtotal') | currency('EUR', $i18n.locale)}}</strong>
-                                                </td>
-                                            </tr>
-                                        </tfoot>
-                                    </table>
-                                </div>
-                                 End of intrastat block
-
-                                 Observations block
-                                <div class="columns vn-mt-xl" v-if="invoice.payMethodCode == 'wireTransfer'">
+                                <!-- Observations block -->
+                                <div class="columns vn-mt-xl">
                                     <div class="size50 pull-left no-page-break" >
                                         <div class="panel" >
                                             <div class="header">{{$t('observations')}}</div>
                                             <div class="body">
-                                                <div>{{$t('wireTransfer')}}</div>
-                                                <div>{{$t('accountNumber', [invoice.iban])}}</div>
+                                                <div>{{$t('payMethod')}}</div>
+                                                <div>{{invoice.payMethod}}</div>
                                             </div>
                                         </div>
                                     </div>
                                 </div>
-                                 End of observations block
+                                <!-- End of observations block -->
 
                             </div>
                         </div>
-                         Footer block
-                        <report-footer id="pageFooter"
-                            v-bind:company-code="invoice.companyCode"
-                            v-bind:left-text="$t('invoiceRef', [invoice.ref])"
-                            v-bind:center-text="client.socialName"
-                            v-bind="$props">
-                        </report-footer> -->
+                    </div>
+                    <!-- Footer block -->
+                    <report-footer id="pageFooter"
+                        v-bind:left-text="$t('invoice', [invoice.id])"
+                        v-bind:center-text="invoice.name"
+                        v-bind="$props">
+                    </report-footer>
                     </td>
                 </tr>
             </tbody>
diff --git a/print/templates/reports/invoiceIn/invoiceIn.js b/print/templates/reports/invoiceIn/invoiceIn.js
index 103f36d1cc..cfad062ed9 100755
--- a/print/templates/reports/invoiceIn/invoiceIn.js
+++ b/print/templates/reports/invoiceIn/invoiceIn.js
@@ -42,8 +42,9 @@ module.exports = {
         fetchBuy(id) {
             return this.rawSqlFromDef('buy', [id]);
         },
-        fetchTaxes(id) {
-            return this.rawSqlFromDef(`taxes`, [id]);
+        async fetchTaxes(id) {
+            const taxes = await this.rawSqlFromDef(`taxes`, [id]);
+            return this.taxVat(taxes);
         },
         buyImport(buy) {
             return buy.quantity * buy.buyingValue;
@@ -61,6 +62,23 @@ module.exports = {
                 total += parseFloat(row[prop]);
 
             return total;
+        },
+        taxVat(taxes) {
+            for (tax of taxes) {
+                let vat = 0;
+                if (tax.rate && tax.taxableBase)
+                    vat = (tax.rate / 100) * tax.taxableBase;
+
+                tax.vat = vat;
+            }
+
+            return taxes;
+        },
+        taxTotal() {
+            const base = this.sumTotal(this.taxes, 'taxableBase');
+            const vat = this.sumTotal(this.taxes, 'vat');
+
+            return base + vat;
         }
     },
     components: {
diff --git a/print/templates/reports/invoiceIn/locale/en.yml b/print/templates/reports/invoiceIn/locale/en.yml
index 4e4688b554..7a8767ad32 100644
--- a/print/templates/reports/invoiceIn/locale/en.yml
+++ b/print/templates/reports/invoiceIn/locale/en.yml
@@ -1,17 +1,16 @@
 reportName: invoice
-title: Invoice
-invoice: Invoice
-clientId: Client
+title: Agrobusiness invoice
+invoiceId: Agrobusiness invoice
+supplierId: Proveedor
 invoiceData: Invoice data
+reference: Reference
 fiscalId: FI / NIF
-invoiceRef: Invoice {0}
-deliveryNote: Delivery note
-shipped: Shipped
+phone: Phone
 date: Date
-reference: Ref.
+item: Item
 quantity: Qty.
 concept: Concept
-price: PSP/u
+buyingValue: PSP/u
 discount: Disc.
 vat: VAT
 amount: Amount
@@ -22,15 +21,5 @@ fee: Fee
 total: Total
 subtotal: Subtotal
 taxBreakdown: Tax breakdown
-notes: Notes
-intrastat: Intrastat
-code: Code
-description: Description
-stems: Stems
-netKg: Net kg
-rectifiedInvoices: Rectified invoices
-issued: Issued
-plantPassport: Plant passport
 observations: Observations
-wireTransfer: "Pay method: Transferencia"
-accountNumber: "Account number: {0}"
\ No newline at end of file
+payMethod: Pay method
diff --git a/print/templates/reports/invoiceIn/locale/es.yml b/print/templates/reports/invoiceIn/locale/es.yml
index 6386c611aa..f2fb28e644 100644
--- a/print/templates/reports/invoiceIn/locale/es.yml
+++ b/print/templates/reports/invoiceIn/locale/es.yml
@@ -3,15 +3,14 @@ title: Factura Agrícola
 invoiceId: Factura Agrícola
 supplierId: Proveedor
 invoiceData: Datos de facturación
+reference: Referencia
 fiscalId: CIF / NIF
-invoiceRef: Factura {0}
-deliveryNote: Albarán
-shipped: F. envío
+phone: Tlf
 date: Fecha
-reference: Ref.
+item: Artículo
 quantity: Cant.
 concept: Concepto
-price: PVP/u
+buyingValue: PVP/u
 discount: Dto.
 vat: IVA
 amount: Importe
@@ -22,15 +21,5 @@ fee: Cuota
 total: Total
 subtotal: Subtotal
 taxBreakdown: Desglose impositivo
-notes: Notas
-intrastat: Intrastat
-code: Código
-description: Descripción
-stems: Tallos
-netKg: KG Neto
-rectifiedInvoices: Facturas rectificadas
-issued: F. emisión
-plantPassport: Pasaporte fitosanitario
 observations: Observaciones
-wireTransfer: "Forma de pago: Transferencia"
-accountNumber: "Número de cuenta: {0}"
+payMethod: Método de pago
diff --git a/print/templates/reports/invoiceIn/sql/invoice.sql b/print/templates/reports/invoiceIn/sql/invoice.sql
index 8913a833b8..fe9ef1e9e0 100644
--- a/print/templates/reports/invoiceIn/sql/invoice.sql
+++ b/print/templates/reports/invoiceIn/sql/invoice.sql
@@ -5,8 +5,10 @@ SELECT
         s.name,
         s.street AS postalAddress,
         s.nif,
-        s.phone
+        s.phone,
+        p.name payMethod
 	FROM invoiceIn i
 		JOIN supplier s ON s.id = i.supplierFk
 		JOIN company c ON c.id = i.companyFk
+        JOIN payMethod p ON p.id = s.payMethodFk
     WHERE i.id = ?
diff --git a/print/templates/reports/invoiceIn/sql/taxes.sql b/print/templates/reports/invoiceIn/sql/taxes.sql
index 18ca6db093..20df33f83a 100644
--- a/print/templates/reports/invoiceIn/sql/taxes.sql
+++ b/print/templates/reports/invoiceIn/sql/taxes.sql
@@ -1,13 +1,8 @@
 SELECT
-        id,
-        invoiceInFk,
-        taxableBase,
-        expenseFk,
-        taxTypeSageFk,
-        transactionTypeSageFk,
-        foreignValue
-    FROM invoiceInTax iit
-        JOIN transactionTypeSage ts ON iit.transactionTypeSageFk = ts.id
-        JOIN taxTypeSage tts ON tts.id =
-    WHERE io.ref = ?
-    ORDER BY iot.id
+	ti.iva as name,
+	ti.PorcentajeIva as rate,
+	iit.taxableBase
+        FROM invoiceIn ii
+            JOIN invoiceInTax iit ON ii.id = iit.invoiceInFk
+            JOIN sage.TiposIva ti ON ti.CodigoIva = iit.taxTypeSageFk
+        WHERE ii.id = ?;

From 0b4df19c43a66fdeedbe35aed77d806979ff82a5 Mon Sep 17 00:00:00 2001
From: Pau Navarro <pau@verdnatura.es>
Date: Thu, 20 Oct 2022 08:00:46 +0200
Subject: [PATCH 084/151] Fixed E2E tests

---
 e2e/paths/13-supplier/03_fiscal_data.spec.js | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/e2e/paths/13-supplier/03_fiscal_data.spec.js b/e2e/paths/13-supplier/03_fiscal_data.spec.js
index 0238c8704a..4f9581e327 100644
--- a/e2e/paths/13-supplier/03_fiscal_data.spec.js
+++ b/e2e/paths/13-supplier/03_fiscal_data.spec.js
@@ -31,7 +31,7 @@ describe('Supplier fiscal data path', () => {
         await page.clearInput(selectors.supplierFiscalData.taxNumber);
         await page.write(selectors.supplierFiscalData.taxNumber, 'Wrong tax number');
         await page.clearInput(selectors.supplierFiscalData.account);
-        await page.write(selectors.supplierFiscalData.account, 'edited account number');
+        await page.write(selectors.supplierFiscalData.account, '0123456789');
         await page.autocompleteSearch(selectors.supplierFiscalData.sageWihholding, 'retencion estimacion objetiva');
         await page.autocompleteSearch(selectors.supplierFiscalData.sageTaxType, 'operaciones no sujetas');
 
@@ -70,7 +70,7 @@ describe('Supplier fiscal data path', () => {
     it('should check the account was edited', async() => {
         const result = await page.waitToGetProperty(selectors.supplierFiscalData.account, 'value');
 
-        expect(result).toEqual('edited account number');
+        expect(result).toEqual('0123456789');
     });
 
     it('should check the sageWihholding was edited', async() => {

From 51cad752984fb2d13f804772aa8bec233430e4f7 Mon Sep 17 00:00:00 2001
From: vicent <vicent@verdnatura.es>
Date: Thu, 20 Oct 2022 08:17:15 +0200
Subject: [PATCH 085/151] fix: testFront

---
 modules/ticket/front/expedition/index.spec.js | 28 ++++++++-----------
 1 file changed, 12 insertions(+), 16 deletions(-)

diff --git a/modules/ticket/front/expedition/index.spec.js b/modules/ticket/front/expedition/index.spec.js
index ad5dafbd7b..b95d64fa34 100644
--- a/modules/ticket/front/expedition/index.spec.js
+++ b/modules/ticket/front/expedition/index.spec.js
@@ -83,29 +83,25 @@ describe('Ticket', () => {
                     agencyModeFk: 1,
                     warehouseFk: 1
                 };
+                const routeId = null;
                 controller.ticket = ticket;
 
-                const expectedTicket = {
-                    clientId: 1101,
-                    landed: new Date(),
-                    addressId: 121,
-                    agencyModeId: 1,
-                    warehouseId: 1
-                };
-
-                const ticketIdToTransfer = 28;
-                const expectedResponse = {id: ticketIdToTransfer};
+                const ticketToTransfer = {id: 28};
 
                 const expectedParams = {
-                    expeditionIds: [1, 2],
-                    ticketId: 28
+                    clientId: 1101,
+                    landed: new Date(),
+                    warehouseId: 1,
+                    addressId: 121,
+                    agencyModeId: 1,
+                    routeId: null,
+                    expeditionIds: [1, 2]
                 };
-                $httpBackend.expect('POST', 'Tickets/new', expectedTicket).respond(expectedResponse);
-                $httpBackend.expect('POST', 'Expeditions/moveExpeditions', expectedParams).respond(200);
-                controller.createTicket();
+                $httpBackend.expect('POST', 'Expeditions/moveExpeditions', expectedParams).respond(ticketToTransfer);
+                controller.createTicket(ticket.landed, routeId);
                 $httpBackend.flush();
 
-                expect(controller.$state.go).toHaveBeenCalledWith('ticket.card.summary', {id: ticketIdToTransfer});
+                expect(controller.$state.go).toHaveBeenCalledWith('ticket.card.summary', {id: ticketToTransfer.id});
             });
         });
     });

From bcc9acac0ac997d9c54df4e12efc830dc50c1331 Mon Sep 17 00:00:00 2001
From: vicent <vicent@verdnatura.es>
Date: Thu, 20 Oct 2022 08:41:00 +0200
Subject: [PATCH 086/151] fix: tBack

---
 .../expedition/specs/moveExpeditions.spec.js  | 26 +++++++++++++++----
 1 file changed, 21 insertions(+), 5 deletions(-)

diff --git a/modules/ticket/back/methods/expedition/specs/moveExpeditions.spec.js b/modules/ticket/back/methods/expedition/specs/moveExpeditions.spec.js
index 0bb402a558..67919e76c0 100644
--- a/modules/ticket/back/methods/expedition/specs/moveExpeditions.spec.js
+++ b/modules/ticket/back/methods/expedition/specs/moveExpeditions.spec.js
@@ -1,17 +1,33 @@
 const models = require('vn-loopback/server/server').models;
 
 describe('ticket moveExpeditions()', () => {
-    it('should delete the selected expeditions', async() => {
+    it('should move the selected expeditions to new ticket', async() => {
         const tx = await models.Expedition.beginTransaction({});
+        const ctx = {
+            req: {accessToken: {userId: 9}},
+            args: {},
+            params: {}
+        };
+        const myCtx = Object.assign({}, ctx);
 
         try {
             const options = {transaction: tx};
+            myCtx.args = {
+                clientId: 1101,
+                landed: new Date(),
+                warehouseId: 1,
+                addressId: 121,
+                agencyModeId: 1,
+                routeId: null,
+                expeditionIds: [1, 2]
 
-            const expeditionIds = [12, 13];
-            const ticketId = 1;
-            const result = await models.Expedition.moveExpeditions(expeditionIds, ticketId, options);
+            };
 
-            expect(result.length).toEqual(2);
+            const ticket = await models.Expedition.moveExpeditions(myCtx, options);
+
+            const newestTicketIdInFixtures = 27;
+
+            expect(ticket.id).toBeGreaterThan(newestTicketIdInFixtures);
 
             await tx.rollback();
         } catch (e) {

From 2da34d0850de92ee8684fb9d339b59a4ff2cc852 Mon Sep 17 00:00:00 2001
From: vicent <vicent@verdnatura.es>
Date: Thu, 20 Oct 2022 09:40:11 +0200
Subject: [PATCH 087/151] feat: add e2e

---
 e2e/helpers/selectors.js | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/e2e/helpers/selectors.js b/e2e/helpers/selectors.js
index 74dabc31ad..dabb4c0cdc 100644
--- a/e2e/helpers/selectors.js
+++ b/e2e/helpers/selectors.js
@@ -596,8 +596,14 @@ export default {
         submitNotesButton: 'button[type=submit]'
     },
     ticketExpedition: {
+        firstSaleCheckbox: 'vn-ticket-expedition vn-tr:nth-child(1) vn-check[ng-model="expedition.checked"]',
         thirdSaleCheckbox: 'vn-ticket-expedition vn-tr:nth-child(3) vn-check[ng-model="expedition.checked"]',
         deleteExpeditionButton: 'vn-ticket-expedition vn-tool-bar > vn-button[icon="delete"]',
+        moveExpeditionButton: 'vn-ticket-expedition vn-tool-bar > vn-button[icon="keyboard_arrow_down"]',
+        moreMenuWithoutRoute: 'vn-item[name="withoutRoute"]',
+        moreMenuWithRoute: 'vn-item[name="withRoute"]',
+        newRouteId: '.vn-dialog.shown vn-textfield[ng-model="$ctrl.newRoute"]',
+        saveButton: '.vn-dialog.shown [response="accept"]',
         expeditionRow: 'vn-ticket-expedition vn-table vn-tbody > vn-tr'
     },
     ticketPackages: {

From 5824fee213055de7401a1ebd3e63f7879199315a Mon Sep 17 00:00:00 2001
From: vicent <vicent@verdnatura.es>
Date: Thu, 20 Oct 2022 09:40:23 +0200
Subject: [PATCH 088/151] feat: add e2e

---
 e2e/paths/05-ticket/20_moveExpedition.spec.js | 50 +++++++++++++++++++
 1 file changed, 50 insertions(+)
 create mode 100644 e2e/paths/05-ticket/20_moveExpedition.spec.js

diff --git a/e2e/paths/05-ticket/20_moveExpedition.spec.js b/e2e/paths/05-ticket/20_moveExpedition.spec.js
new file mode 100644
index 0000000000..9673c70717
--- /dev/null
+++ b/e2e/paths/05-ticket/20_moveExpedition.spec.js
@@ -0,0 +1,50 @@
+import selectors from '../../helpers/selectors.js';
+import getBrowser from '../../helpers/puppeteer';
+
+fdescribe('Ticket expeditions', () => {
+    let browser;
+    let page;
+
+    beforeAll(async() => {
+        browser = await getBrowser();
+        page = browser.page;
+        await page.loginAndModule('production', 'ticket');
+        await page.accessToSearchResult('1');
+        await page.accessToSection('ticket.card.expedition');
+    });
+
+    afterAll(async() => {
+        await browser.close();
+    });
+
+    it(`should move one expedition to new ticket withoute route`, async() => {
+        await page.waitToClick(selectors.ticketExpedition.thirdSaleCheckbox);
+        await page.waitToClick(selectors.ticketExpedition.moveExpeditionButton);
+        await page.waitToClick(selectors.ticketExpedition.moreMenuWithoutRoute);
+        await page.waitToClick(selectors.ticketExpedition.saveButton);
+        await page.waitForState('ticket.card.summary');
+        await page.accessToSection('ticket.card.expedition');
+
+        await page.waitForSelector(selectors.ticketExpedition.expeditionRow, {});
+        const result = await page
+            .countElement(selectors.ticketExpedition.expeditionRow);
+
+        expect(result).toEqual(1);
+    });
+
+    it(`should move one expedition to new ticket with route`, async() => {
+        await page.waitToClick(selectors.ticketExpedition.firstSaleCheckbox);
+        await page.waitToClick(selectors.ticketExpedition.moveExpeditionButton);
+        await page.waitToClick(selectors.ticketExpedition.moreMenuWithRoute);
+        await page.write(selectors.ticketExpedition.newRouteId, '1');
+        await page.waitToClick(selectors.ticketExpedition.saveButton);
+        await page.waitForState('ticket.card.summary');
+        await page.accessToSection('ticket.card.expedition');
+
+        await page.waitForSelector(selectors.ticketExpedition.expeditionRow, {});
+        const result = await page
+            .countElement(selectors.ticketExpedition.expeditionRow);
+
+        expect(result).toEqual(1);
+    });
+});

From dd15d06f5edfb7c439482764551175e7fe225b70 Mon Sep 17 00:00:00 2001
From: vicent <vicent@verdnatura.es>
Date: Thu, 20 Oct 2022 10:21:44 +0200
Subject: [PATCH 089/151] delete focus test

---
 e2e/paths/05-ticket/20_moveExpedition.spec.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/e2e/paths/05-ticket/20_moveExpedition.spec.js b/e2e/paths/05-ticket/20_moveExpedition.spec.js
index 9673c70717..cf1c5ded32 100644
--- a/e2e/paths/05-ticket/20_moveExpedition.spec.js
+++ b/e2e/paths/05-ticket/20_moveExpedition.spec.js
@@ -1,7 +1,7 @@
 import selectors from '../../helpers/selectors.js';
 import getBrowser from '../../helpers/puppeteer';
 
-fdescribe('Ticket expeditions', () => {
+describe('Ticket expeditions', () => {
     let browser;
     let page;
 

From c23d58da69eff1cadcb82221ed5b51b310ace1d4 Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Thu, 20 Oct 2022 14:21:36 +0200
Subject: [PATCH 090/151] fix if not ticket

---
 print/templates/reports/driver-route/driver-route.js | 3 ---
 print/templates/reports/driver-route/locale/es.yml   | 1 -
 2 files changed, 4 deletions(-)

diff --git a/print/templates/reports/driver-route/driver-route.js b/print/templates/reports/driver-route/driver-route.js
index b142a446e9..2de3d51924 100755
--- a/print/templates/reports/driver-route/driver-route.js
+++ b/print/templates/reports/driver-route/driver-route.js
@@ -14,9 +14,6 @@ module.exports = {
         const routes = await this.fetchRoutes(ids);
         const tickets = await this.fetchTickets(ids);
 
-        if (!tickets || !tickets.id)
-            throw new Error('This route(s) not have ticket(s)');
-
         const map = new Map();
 
         for (let route of routes)
diff --git a/print/templates/reports/driver-route/locale/es.yml b/print/templates/reports/driver-route/locale/es.yml
index d065d62e05..8f986b0d23 100644
--- a/print/templates/reports/driver-route/locale/es.yml
+++ b/print/templates/reports/driver-route/locale/es.yml
@@ -23,4 +23,3 @@ import: Importe
 route: Ruta
 routeId: Ruta {0}
 ticket: Ticket
-This route(s) not have ticket(s): Esta ruta(s) no tiene ticket(s)

From 29093d7d30e98083c36ee81bebb5c5ed95453020 Mon Sep 17 00:00:00 2001
From: vicent <vicent@verdnatura.es>
Date: Thu, 20 Oct 2022 14:25:55 +0200
Subject: [PATCH 091/151] =?UTF-8?q?feat:=20en=20vez=20de=20consultar=20si?=
 =?UTF-8?q?=20el=20usuario=20est=C3=A1=20en=20la=20tabla=20workerMana,=20c?=
 =?UTF-8?q?onsultar=20es=20si=20el=20usuario=20est=C3=A1=20en=20un=20depar?=
 =?UTF-8?q?tamento=20que=20cuelga=20de=20ventas?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../back/methods/sale/specs/updatePrice.spec.js       | 11 ++++++++++-
 modules/ticket/back/methods/sale/updatePrice.js       |  8 ++++++--
 2 files changed, 16 insertions(+), 3 deletions(-)

diff --git a/modules/ticket/back/methods/sale/specs/updatePrice.spec.js b/modules/ticket/back/methods/sale/specs/updatePrice.spec.js
index e76511421e..75be665fb3 100644
--- a/modules/ticket/back/methods/sale/specs/updatePrice.spec.js
+++ b/modules/ticket/back/methods/sale/specs/updatePrice.spec.js
@@ -79,10 +79,19 @@ describe('sale updatePrice()', () => {
             const price = 5.4;
             const originalSalesPersonMana = await models.WorkerMana.findById(18, null, options);
             const manaComponent = await models.Component.findOne({where: {code: 'mana'}}, options);
+            const teamCLopez = 96;
+            const userId = 18;
+            await models.Sale.rawSql(`UPDATE vn.business b
+                                            JOIN vn.department d ON d.id = b.departmentFk 
+                                            SET b.departmentFk = ?
+                                        WHERE b.id = ?`, [teamCLopez, userId]);
 
             await models.Sale.updatePrice(ctx, saleId, price, options);
             const updatedSale = await models.Sale.findById(saleId, null, options);
-            createdSaleComponent = await models.SaleComponent.findOne({where: {saleFk: saleId, componentFk: manaComponent.id}}, options);
+            const createdSaleComponent = await models.SaleComponent.findOne({
+                where: {
+                    saleFk: saleId, componentFk: manaComponent.id
+                }}, options);
 
             expect(updatedSale.price).toBe(price);
             expect(createdSaleComponent.value).toEqual(-2.04);
diff --git a/modules/ticket/back/methods/sale/updatePrice.js b/modules/ticket/back/methods/sale/updatePrice.js
index bbd9d154db..dbd4ed091a 100644
--- a/modules/ticket/back/methods/sale/updatePrice.js
+++ b/modules/ticket/back/methods/sale/updatePrice.js
@@ -77,7 +77,12 @@ module.exports = Self => {
 
             const oldPrice = sale.price;
             const userId = ctx.req.accessToken.userId;
-            const usesMana = await models.WorkerMana.findOne({where: {workerFk: userId}, fields: 'amount'}, myOptions);
+
+            const salesDepartment = await models.Department.findOne({where: {code: 'VT'}, fields: 'id'}, myOptions);
+            const departments = await models.Department.getLeaves(salesDepartment.id, null, myOptions);
+            const workerDepartment = await models.WorkerDepartment.findById(userId);
+            const usesMana = departments.find(department => department.id == workerDepartment.departmentFk);
+
             const componentCode = usesMana ? 'mana' : 'buyerDiscount';
             const discount = await models.Component.findOne({where: {code: componentCode}}, myOptions);
             const componentId = discount.id;
@@ -88,7 +93,6 @@ module.exports = Self => {
                 saleFk: id
             };
             const saleComponent = await models.SaleComponent.findOne({where}, myOptions);
-
             if (saleComponent) {
                 await models.SaleComponent.updateAll(where, {
                     value: saleComponent.value + componentValue

From 6891190c72e019cb8c2c2232a028e27a47a1ea56 Mon Sep 17 00:00:00 2001
From: vicent <vicent@verdnatura.es>
Date: Thu, 20 Oct 2022 15:05:46 +0200
Subject: [PATCH 092/151] refactor: create endpoint to unify code

---
 db/changes/10491-august/00-aclUsesMana.sql    |  3 ++
 .../ticket/back/methods/sale/updatePrice.js   | 10 +++---
 modules/ticket/back/methods/sale/usesMana.js  | 31 +++++++++++++++++++
 modules/ticket/back/models/sale.js            |  1 +
 4 files changed, 41 insertions(+), 4 deletions(-)
 create mode 100644 db/changes/10491-august/00-aclUsesMana.sql
 create mode 100644 modules/ticket/back/methods/sale/usesMana.js

diff --git a/db/changes/10491-august/00-aclUsesMana.sql b/db/changes/10491-august/00-aclUsesMana.sql
new file mode 100644
index 0000000000..5bb7178dd4
--- /dev/null
+++ b/db/changes/10491-august/00-aclUsesMana.sql
@@ -0,0 +1,3 @@
+INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
+    VALUES
+        ('Sale', 'usesMana', '*', 'ALLOW', 'ROLE', 'employee');
\ No newline at end of file
diff --git a/modules/ticket/back/methods/sale/updatePrice.js b/modules/ticket/back/methods/sale/updatePrice.js
index dbd4ed091a..d325d6eaa4 100644
--- a/modules/ticket/back/methods/sale/updatePrice.js
+++ b/modules/ticket/back/methods/sale/updatePrice.js
@@ -78,11 +78,13 @@ module.exports = Self => {
             const oldPrice = sale.price;
             const userId = ctx.req.accessToken.userId;
 
-            const salesDepartment = await models.Department.findOne({where: {code: 'VT'}, fields: 'id'}, myOptions);
-            const departments = await models.Department.getLeaves(salesDepartment.id, null, myOptions);
-            const workerDepartment = await models.WorkerDepartment.findById(userId);
-            const usesMana = departments.find(department => department.id == workerDepartment.departmentFk);
+            // const salesDepartment = await models.Department.findOne({where: {code: 'VT'}, fields: 'id'}, myOptions);
+            // const departments = await models.Department.getLeaves(salesDepartment.id, null, myOptions);
+            // const workerDepartment = await models.WorkerDepartment.findById(userId);
+            // const usesMana = departments.find(department => department.id == workerDepartment.departmentFk);
 
+            const usesMana = await models.Sale.usesMana();
+            console.log(usesMana ? 'mana' : 'buyerDiscount');
             const componentCode = usesMana ? 'mana' : 'buyerDiscount';
             const discount = await models.Component.findOne({where: {code: componentCode}}, myOptions);
             const componentId = discount.id;
diff --git a/modules/ticket/back/methods/sale/usesMana.js b/modules/ticket/back/methods/sale/usesMana.js
new file mode 100644
index 0000000000..7ff2a5e2a6
--- /dev/null
+++ b/modules/ticket/back/methods/sale/usesMana.js
@@ -0,0 +1,31 @@
+module.exports = Self => {
+    Self.remoteMethodCtx('usesMana', {
+        description: 'Returns if the worker uses mana',
+        accessType: 'WRITE',
+        accepts: [],
+        returns: {
+            type: 'boolean',
+            root: true
+        },
+        http: {
+            path: `/usesMana`,
+            verb: 'POST'
+        }
+    });
+
+    Self.usesMana = async(ctx, options) => {
+        const models = Self.app.models;
+        const userId = ctx.req.accessToken.userId;
+        const myOptions = {};
+
+        if (typeof options == 'object')
+            Object.assign(myOptions, options);
+
+        const salesDepartment = await models.Department.findOne({where: {code: 'VT'}, fields: 'id'}, myOptions);
+        const departments = await models.Department.getLeaves(salesDepartment.id, null, myOptions);
+        const workerDepartment = await models.WorkerDepartment.findById(userId);
+        const usesMana = departments.find(department => department.id == workerDepartment.departmentFk);
+
+        return usesMana ? true : false;
+    };
+};
diff --git a/modules/ticket/back/models/sale.js b/modules/ticket/back/models/sale.js
index 2a4457263d..ae247fc242 100644
--- a/modules/ticket/back/models/sale.js
+++ b/modules/ticket/back/models/sale.js
@@ -8,6 +8,7 @@ module.exports = Self => {
     require('../methods/sale/recalculatePrice')(Self);
     require('../methods/sale/refund')(Self);
     require('../methods/sale/canEdit')(Self);
+    require('../methods/sale/usesMana')(Self);
 
     Self.validatesPresenceOf('concept', {
         message: `Concept cannot be blank`

From 066cf6f69bd3f036edd86caf47f414b1cd9990cf Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Thu, 20 Oct 2022 15:11:56 +0200
Subject: [PATCH 093/151] add show dialog

---
 modules/invoiceIn/front/descriptor/index.html | 23 ++++++++++++++++---
 modules/invoiceIn/front/locale/es.yml         |  2 ++
 2 files changed, 22 insertions(+), 3 deletions(-)

diff --git a/modules/invoiceIn/front/descriptor/index.html b/modules/invoiceIn/front/descriptor/index.html
index c23a14ffc5..faff5b9765 100644
--- a/modules/invoiceIn/front/descriptor/index.html
+++ b/modules/invoiceIn/front/descriptor/index.html
@@ -26,14 +26,12 @@
             Clone Invoice
         </vn-item>
         <vn-item
-            ng-if="!$ctrl.hasDocuwareFile"
             ng-click="$ctrl.showPdfInvoice()"
             translate>
             Show Invoice as PDF
         </vn-item>
         <vn-item
-            ng-if="!$ctrl.hasDocuwareFile"
-            ng-click="$ctrl.showPdfInvoice()"
+            ng-click="sendPdfConfirmation.show({email: $ctrl.entity})"
             translate>
             Send Invoice as PDF
         </vn-item>
@@ -94,3 +92,22 @@
 <vn-popup vn-id="summary">
     <vn-invoice-in-summary invoice-in="$ctrl.invoiceIn"></vn-invoice-in-summary>
 </vn-popup>
+
+<!-- Send PDF invoice confirmation popup -->
+<vn-dialog
+    vn-id="sendPdfConfirmation"
+    on-accept="$ctrl.sendPdfInvoice($data)"
+    message="Send PDF invoice">
+    <tpl-body>
+        {{sendPdfConfirmation.data.email}}
+        <span translate>Are you sure you want to send it?</span>
+        <vn-textfield vn-one
+            label="Email"
+            ng-model="sendPdfConfirmation.data.email">
+        </vn-textfield>
+    </tpl-body>
+    <tpl-buttons>
+        <input type="button" response="cancel" translate-attr="{value: 'Cancel'}"/>
+        <button response="accept" translate>Confirm</button>
+    </tpl-buttons>
+</vn-dialog>
diff --git a/modules/invoiceIn/front/locale/es.yml b/modules/invoiceIn/front/locale/es.yml
index 4f36b33fa8..8cdea3323a 100644
--- a/modules/invoiceIn/front/locale/es.yml
+++ b/modules/invoiceIn/front/locale/es.yml
@@ -19,3 +19,5 @@ To book: Contabilizar
 Total amount: Total importe
 Total net: Total neto
 Total stems: Total tallos
+Show Invoice as PDF: Ver Factura Agrícola como PDF
+Send Invoice as PDF: Enviar Factura Agrícola como PDF

From 5da29fe38158e71d3d8fab36fd2fb9deab0bf137 Mon Sep 17 00:00:00 2001
From: vicent <vicent@verdnatura.es>
Date: Fri, 21 Oct 2022 08:00:24 +0200
Subject: [PATCH 094/151] refactor: unify duplicated code

---
 modules/ticket/back/methods/sale/updatePrice.js      | 8 +-------
 modules/ticket/back/methods/sale/usesMana.js         | 6 +++---
 modules/ticket/back/methods/ticket/updateDiscount.js | 7 +------
 3 files changed, 5 insertions(+), 16 deletions(-)

diff --git a/modules/ticket/back/methods/sale/updatePrice.js b/modules/ticket/back/methods/sale/updatePrice.js
index d325d6eaa4..302522cfbc 100644
--- a/modules/ticket/back/methods/sale/updatePrice.js
+++ b/modules/ticket/back/methods/sale/updatePrice.js
@@ -78,13 +78,7 @@ module.exports = Self => {
             const oldPrice = sale.price;
             const userId = ctx.req.accessToken.userId;
 
-            // const salesDepartment = await models.Department.findOne({where: {code: 'VT'}, fields: 'id'}, myOptions);
-            // const departments = await models.Department.getLeaves(salesDepartment.id, null, myOptions);
-            // const workerDepartment = await models.WorkerDepartment.findById(userId);
-            // const usesMana = departments.find(department => department.id == workerDepartment.departmentFk);
-
-            const usesMana = await models.Sale.usesMana();
-            console.log(usesMana ? 'mana' : 'buyerDiscount');
+            const usesMana = await models.Sale.usesMana(ctx, myOptions);
             const componentCode = usesMana ? 'mana' : 'buyerDiscount';
             const discount = await models.Component.findOne({where: {code: componentCode}}, myOptions);
             const componentId = discount.id;
diff --git a/modules/ticket/back/methods/sale/usesMana.js b/modules/ticket/back/methods/sale/usesMana.js
index 7ff2a5e2a6..093057dca4 100644
--- a/modules/ticket/back/methods/sale/usesMana.js
+++ b/modules/ticket/back/methods/sale/usesMana.js
@@ -1,7 +1,7 @@
 module.exports = Self => {
     Self.remoteMethodCtx('usesMana', {
         description: 'Returns if the worker uses mana',
-        accessType: 'WRITE',
+        accessType: 'READ',
         accepts: [],
         returns: {
             type: 'boolean',
@@ -9,7 +9,7 @@ module.exports = Self => {
         },
         http: {
             path: `/usesMana`,
-            verb: 'POST'
+            verb: 'GET'
         }
     });
 
@@ -23,7 +23,7 @@ module.exports = Self => {
 
         const salesDepartment = await models.Department.findOne({where: {code: 'VT'}, fields: 'id'}, myOptions);
         const departments = await models.Department.getLeaves(salesDepartment.id, null, myOptions);
-        const workerDepartment = await models.WorkerDepartment.findById(userId);
+        const workerDepartment = await models.WorkerDepartment.findById(userId, null, myOptions);
         const usesMana = departments.find(department => department.id == workerDepartment.departmentFk);
 
         return usesMana ? true : false;
diff --git a/modules/ticket/back/methods/ticket/updateDiscount.js b/modules/ticket/back/methods/ticket/updateDiscount.js
index b1291a45bf..9419b9a40b 100644
--- a/modules/ticket/back/methods/ticket/updateDiscount.js
+++ b/modules/ticket/back/methods/ticket/updateDiscount.js
@@ -98,12 +98,7 @@ module.exports = Self => {
             if (isLocked || (!hasAllowedRoles && alertLevel > 0))
                 throw new UserError(`The sales of this ticket can't be modified`);
 
-            const usesMana = await models.WorkerMana.findOne({
-                where: {
-                    workerFk: userId
-                },
-                fields: 'amount'}, myOptions);
-
+            const usesMana = await models.Sale.usesMana(ctx);
             const componentCode = usesMana ? manaCode : 'buyerDiscount';
             const discountComponent = await models.Component.findOne({
                 where: {code: componentCode}}, myOptions);

From 6f31bea21f50306ef47133afeacb447b2fb709a0 Mon Sep 17 00:00:00 2001
From: vicent <vicent@verdnatura.es>
Date: Fri, 21 Oct 2022 08:00:48 +0200
Subject: [PATCH 095/151] feat: update testBack

---
 db/changes/10491-august/00-aclBusiness.sql    |  3 ++
 modules/client/back/model-config.json         |  3 ++
 modules/client/back/models/business.json      | 27 +++++++++++
 .../methods/sale/specs/updatePrice.spec.js    | 11 ++---
 .../back/methods/sale/specs/usesMana.spec.js  | 48 +++++++++++++++++++
 5 files changed, 86 insertions(+), 6 deletions(-)
 create mode 100644 db/changes/10491-august/00-aclBusiness.sql
 create mode 100644 modules/client/back/models/business.json
 create mode 100644 modules/ticket/back/methods/sale/specs/usesMana.spec.js

diff --git a/db/changes/10491-august/00-aclBusiness.sql b/db/changes/10491-august/00-aclBusiness.sql
new file mode 100644
index 0000000000..f1f7a36323
--- /dev/null
+++ b/db/changes/10491-august/00-aclBusiness.sql
@@ -0,0 +1,3 @@
+INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
+    VALUES
+        ('Business', '*', '*', 'ALLOW', 'ROLE', 'employee');
\ No newline at end of file
diff --git a/modules/client/back/model-config.json b/modules/client/back/model-config.json
index b2e600610e..4ef34ca3a6 100644
--- a/modules/client/back/model-config.json
+++ b/modules/client/back/model-config.json
@@ -8,6 +8,9 @@
     "BankEntity": {
         "dataSource": "vn"
     },
+    "Business": {
+        "dataSource": "vn"
+    },
     "BusinessType": {
         "dataSource": "vn"
     },
diff --git a/modules/client/back/models/business.json b/modules/client/back/models/business.json
new file mode 100644
index 0000000000..7ad2d307ff
--- /dev/null
+++ b/modules/client/back/models/business.json
@@ -0,0 +1,27 @@
+{
+    "name": "Business",
+    "base": "VnModel",
+    "options": {
+        "mysql": {
+            "table": "business"
+        }
+    },
+    "properties": {
+        "id": {
+            "type": "number",
+            "id": true
+        }
+    },
+    "relations": {
+        "worker": {
+            "type": "belongsTo",
+            "model": "Worker",
+            "foreignKey": "workerFk"
+        },
+        "department": {
+            "type": "belongsTo",
+            "model": "Department",
+            "foreignKey": "departmentFk"
+        }
+    }
+}
\ No newline at end of file
diff --git a/modules/ticket/back/methods/sale/specs/updatePrice.spec.js b/modules/ticket/back/methods/sale/specs/updatePrice.spec.js
index 75be665fb3..f8cb5a4ecd 100644
--- a/modules/ticket/back/methods/sale/specs/updatePrice.spec.js
+++ b/modules/ticket/back/methods/sale/specs/updatePrice.spec.js
@@ -1,6 +1,6 @@
 const models = require('vn-loopback/server/server').models;
 
-describe('sale updatePrice()', () => {
+fdescribe('sale updatePrice()', () => {
     const ctx = {
         req: {
             accessToken: {userId: 18},
@@ -80,11 +80,10 @@ describe('sale updatePrice()', () => {
             const originalSalesPersonMana = await models.WorkerMana.findById(18, null, options);
             const manaComponent = await models.Component.findOne({where: {code: 'mana'}}, options);
             const teamCLopez = 96;
-            const userId = 18;
-            await models.Sale.rawSql(`UPDATE vn.business b
-                                            JOIN vn.department d ON d.id = b.departmentFk 
-                                            SET b.departmentFk = ?
-                                        WHERE b.id = ?`, [teamCLopez, userId]);
+            const userId = ctx.req.accessToken.userId;
+
+            const business = await models.Business.findOne({where: {workerFk: userId}}, options);
+            await business.updateAttribute('departmentFk', teamCLopez, options);
 
             await models.Sale.updatePrice(ctx, saleId, price, options);
             const updatedSale = await models.Sale.findById(saleId, null, options);
diff --git a/modules/ticket/back/methods/sale/specs/usesMana.spec.js b/modules/ticket/back/methods/sale/specs/usesMana.spec.js
new file mode 100644
index 0000000000..4e14ed2c96
--- /dev/null
+++ b/modules/ticket/back/methods/sale/specs/usesMana.spec.js
@@ -0,0 +1,48 @@
+const models = require('vn-loopback/server/server').models;
+
+describe('sale usesMana()', () => {
+    const ctx = {
+        req: {
+            accessToken: {userId: 18}
+        }
+    };
+
+    it('should return that the worker uses mana', async() => {
+        const tx = await models.Sale.beginTransaction({});
+
+        try {
+            const options = {transaction: tx};
+            const teamCLopez = 96;
+            const userId = ctx.req.accessToken.userId;
+
+            const business = await models.Business.findOne({where: {workerFk: userId}}, options);
+            await business.updateAttribute('departmentFk', teamCLopez, options);
+
+            const usesMana = await models.Sale.usesMana(ctx, options);
+
+            expect(usesMana).toBe(true);
+
+            await tx.rollback();
+        } catch (e) {
+            await tx.rollback();
+            throw e;
+        }
+    });
+
+    it('should return that the worker not uses mana', async() => {
+        const tx = await models.Sale.beginTransaction({});
+
+        try {
+            const options = {transaction: tx};
+
+            const usesMana = await models.Sale.usesMana(ctx, options);
+
+            expect(usesMana).toBe(false);
+
+            await tx.rollback();
+        } catch (e) {
+            await tx.rollback();
+            throw e;
+        }
+    });
+});

From e7261573d7954cd9ce129efc0dd945e1114febfe Mon Sep 17 00:00:00 2001
From: vicent <vicent@verdnatura.es>
Date: Fri, 21 Oct 2022 08:01:22 +0200
Subject: [PATCH 096/151] delete focus

---
 modules/ticket/back/methods/sale/specs/updatePrice.spec.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/modules/ticket/back/methods/sale/specs/updatePrice.spec.js b/modules/ticket/back/methods/sale/specs/updatePrice.spec.js
index f8cb5a4ecd..15b00a7329 100644
--- a/modules/ticket/back/methods/sale/specs/updatePrice.spec.js
+++ b/modules/ticket/back/methods/sale/specs/updatePrice.spec.js
@@ -1,6 +1,6 @@
 const models = require('vn-loopback/server/server').models;
 
-fdescribe('sale updatePrice()', () => {
+describe('sale updatePrice()', () => {
     const ctx = {
         req: {
             accessToken: {userId: 18},

From 2d0cb60b50825144113edde29f97f084240002ac Mon Sep 17 00:00:00 2001
From: vicent <vicent@verdnatura.es>
Date: Fri, 21 Oct 2022 08:55:05 +0200
Subject: [PATCH 097/151] feat: check if uses mana

---
 modules/ticket/front/sale/index.html | 14 ++++++++++++--
 modules/ticket/front/sale/index.js   |  8 ++++++++
 2 files changed, 20 insertions(+), 2 deletions(-)

diff --git a/modules/ticket/front/sale/index.html b/modules/ticket/front/sale/index.html
index 42eb10cb06..35e45a8120 100644
--- a/modules/ticket/front/sale/index.html
+++ b/modules/ticket/front/sale/index.html
@@ -264,6 +264,16 @@
                 </div>
             </div>
         </div>
+        <vn-horizontal >
+            <vn-button
+                label="Cancel"
+                ng-click="$ctrl.cancel()">
+            </vn-button>
+            <vn-button
+                label="Save"
+                ng-click="$ctrl.save()">
+            </vn-button>
+        </vn-horizontal>
     </div>
 </vn-popover>
 
@@ -278,7 +288,7 @@
         </vn-spinner>
         <div ng-if="$ctrl.edit.mana != null">
             <section class="header vn-pa-md">
-                <h5>Mana: {{::$ctrl.edit.mana | currency: 'EUR':0}}</h5>
+                <h5>MANÁ: {{::$ctrl.edit.mana | currency: 'EUR': 0}}</h5>
             </section>
             <div class="vn-pa-md">
                 <vn-input-number
@@ -288,7 +298,7 @@
                     clear-disabled="true"
                     suffix="%">
                 </vn-input-number>
-                <vn-vertical ng-if="$ctrl.currentWorkerMana != 0">
+                <vn-vertical ng-if="$ctrl.usesMana && $ctrl.currentWorkerMana != 0">
                     <vn-radio
                         label="Promotion mana"
                         val="mana"
diff --git a/modules/ticket/front/sale/index.js b/modules/ticket/front/sale/index.js
index 2724bb97d9..e67f675907 100644
--- a/modules/ticket/front/sale/index.js
+++ b/modules/ticket/front/sale/index.js
@@ -75,6 +75,7 @@ class Controller extends Section {
                     this.$.editPricePopover.relocate();
                 });
             });
+        this.getUsesMana();
         this.getCurrentWorkerMana();
     }
 
@@ -85,6 +86,13 @@ class Controller extends Section {
             });
     }
 
+    getUsesMana() {
+        this.$http.get(`Sales/usesMana`)
+            .then(res => {
+                this.useMana = res.data;
+            });
+    }
+
     /**
      * Returns checked instances
      *

From c33cab7b10b94be095f0b96e4c2860e68e3fcf36 Mon Sep 17 00:00:00 2001
From: vicent <vicent@verdnatura.es>
Date: Fri, 21 Oct 2022 09:01:08 +0200
Subject: [PATCH 098/151] fix: test back

---
 .../back/methods/ticket/specs/updateDiscount.spec.js   | 10 ++++++++++
 modules/ticket/back/methods/ticket/updateDiscount.js   |  2 +-
 2 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/modules/ticket/back/methods/ticket/specs/updateDiscount.spec.js b/modules/ticket/back/methods/ticket/specs/updateDiscount.spec.js
index 1873207aad..5249fe5d88 100644
--- a/modules/ticket/back/methods/ticket/specs/updateDiscount.spec.js
+++ b/modules/ticket/back/methods/ticket/specs/updateDiscount.spec.js
@@ -110,6 +110,11 @@ describe('sale updateDiscount()', () => {
             const componentId = manaDiscount.id;
             const manaCode = 'mana';
 
+            const teamCLopez = 96;
+            const userId = ctx.req.accessToken.userId;
+            const business = await models.Business.findOne({where: {workerFk: userId}}, options);
+            await business.updateAttribute('departmentFk', teamCLopez, options);
+
             await models.Ticket.updateDiscount(ctx, ticketId, sales, newDiscount, manaCode, options);
 
             const updatedSale = await models.Sale.findById(originalSaleId, null, options);
@@ -150,6 +155,11 @@ describe('sale updateDiscount()', () => {
             const componentId = manaDiscount.id;
             const manaCode = 'manaClaim';
 
+            const teamCLopez = 96;
+            const userId = ctx.req.accessToken.userId;
+            const business = await models.Business.findOne({where: {workerFk: userId}}, options);
+            await business.updateAttribute('departmentFk', teamCLopez, options);
+
             await models.Ticket.updateDiscount(ctx, ticketId, sales, newDiscount, manaCode, options);
 
             const updatedSale = await models.Sale.findById(originalSaleId, null, options);
diff --git a/modules/ticket/back/methods/ticket/updateDiscount.js b/modules/ticket/back/methods/ticket/updateDiscount.js
index 9419b9a40b..8bc79ca9c3 100644
--- a/modules/ticket/back/methods/ticket/updateDiscount.js
+++ b/modules/ticket/back/methods/ticket/updateDiscount.js
@@ -98,7 +98,7 @@ module.exports = Self => {
             if (isLocked || (!hasAllowedRoles && alertLevel > 0))
                 throw new UserError(`The sales of this ticket can't be modified`);
 
-            const usesMana = await models.Sale.usesMana(ctx);
+            const usesMana = await models.Sale.usesMana(ctx, myOptions);
             const componentCode = usesMana ? manaCode : 'buyerDiscount';
             const discountComponent = await models.Component.findOne({
                 where: {code: componentCode}}, myOptions);

From f968b19d1e2603036050fbc2b5b17680f5b05d13 Mon Sep 17 00:00:00 2001
From: vicent <vicent@verdnatura.es>
Date: Fri, 21 Oct 2022 09:08:17 +0200
Subject: [PATCH 099/151] fix: testFront

---
 modules/ticket/front/sale/index.spec.js | 1 +
 1 file changed, 1 insertion(+)

diff --git a/modules/ticket/front/sale/index.spec.js b/modules/ticket/front/sale/index.spec.js
index 28d8749328..a7260a3ec4 100644
--- a/modules/ticket/front/sale/index.spec.js
+++ b/modules/ticket/front/sale/index.spec.js
@@ -115,6 +115,7 @@ describe('Ticket', () => {
                 const expectedAmount = 250;
 
                 $httpBackend.expect('GET', 'Tickets/1/getSalesPersonMana').respond(200, expectedAmount);
+                $httpBackend.expect('GET', 'Sales/usesMana').respond(200);
                 $httpBackend.expect('GET', 'WorkerManas/getCurrentWorkerMana').respond(200, expectedAmount);
                 controller.getMana();
                 $httpBackend.flush();

From 18c119c62a88a0e1959d1af2e00d22f9a91e37b1 Mon Sep 17 00:00:00 2001
From: vicent <vicent@verdnatura.es>
Date: Fri, 21 Oct 2022 09:20:27 +0200
Subject: [PATCH 100/151] change acl

---
 db/changes/10491-august/00-aclBusiness.sql | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/db/changes/10491-august/00-aclBusiness.sql b/db/changes/10491-august/00-aclBusiness.sql
index f1f7a36323..8ea2c6d83b 100644
--- a/db/changes/10491-august/00-aclBusiness.sql
+++ b/db/changes/10491-august/00-aclBusiness.sql
@@ -1,3 +1,3 @@
 INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
     VALUES
-        ('Business', '*', '*', 'ALLOW', 'ROLE', 'employee');
\ No newline at end of file
+        ('Business', '*', '*', 'ALLOW', 'ROLE', 'hr');
\ No newline at end of file

From 6a17a634d41a62e5ce3b8fa733736ef407bf315f Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Mon, 24 Oct 2022 09:49:51 +0200
Subject: [PATCH 101/151] hotFix(receipt): add receiptPdf

---
 .../client/back/methods/receipt/receiptPdf.js | 55 +++++++++++++++++++
 modules/client/back/models/receipt.js         |  1 +
 modules/client/front/balance/create/index.js  |  8 +--
 .../client/front/balance/create/index.spec.js |  8 +--
 4 files changed, 62 insertions(+), 10 deletions(-)
 create mode 100644 modules/client/back/methods/receipt/receiptPdf.js

diff --git a/modules/client/back/methods/receipt/receiptPdf.js b/modules/client/back/methods/receipt/receiptPdf.js
new file mode 100644
index 0000000000..f55e050403
--- /dev/null
+++ b/modules/client/back/methods/receipt/receiptPdf.js
@@ -0,0 +1,55 @@
+const {Report} = require('vn-print');
+
+module.exports = Self => {
+    Self.remoteMethodCtx('receiptPdf', {
+        description: 'Returns the receipt pdf',
+        accepts: [
+            {
+                arg: 'id',
+                type: 'number',
+                required: true,
+                description: 'The claim id',
+                http: {source: 'path'}
+            },
+            {
+                arg: 'recipientId',
+                type: 'number',
+                description: 'The recipient id',
+                required: false
+            }
+        ],
+        returns: [
+            {
+                arg: 'body',
+                type: 'file',
+                root: true
+            }, {
+                arg: 'Content-Type',
+                type: 'String',
+                http: {target: 'header'}
+            }, {
+                arg: 'Content-Disposition',
+                type: 'String',
+                http: {target: 'header'}
+            }
+        ],
+        http: {
+            path: '/:id/receipt-pdf',
+            verb: 'GET'
+        }
+    });
+
+    Self.receiptPdf = async(ctx, id) => {
+        const args = Object.assign({}, ctx.args);
+        const params = {lang: ctx.req.getLocale()};
+
+        delete args.ctx;
+        for (const param in args)
+            params[param] = args[param];
+
+        const report = new Report('receipt', params);
+        const stream = await report.toPdfStream();
+
+        return [stream, 'application/pdf', `filename="doc-${id}.pdf"`];
+    };
+};
diff --git a/modules/client/back/models/receipt.js b/modules/client/back/models/receipt.js
index 36a4a8952a..b79102e6b8 100644
--- a/modules/client/back/models/receipt.js
+++ b/modules/client/back/models/receipt.js
@@ -2,6 +2,7 @@ const LoopBackContext = require('loopback-context');
 
 module.exports = function(Self) {
     require('../methods/receipt/filter')(Self);
+    require('../methods/receipt/receiptPdf')(Self);
 
     Self.validateBinded('amountPaid', isNotZero, {
         message: 'Amount cannot be zero',
diff --git a/modules/client/front/balance/create/index.js b/modules/client/front/balance/create/index.js
index c6a6e7ff97..935129574e 100644
--- a/modules/client/front/balance/create/index.js
+++ b/modules/client/front/balance/create/index.js
@@ -144,12 +144,8 @@ class Controller extends Dialog {
             })
             .then(() => this.vnApp.showSuccess(this.$t('Data saved!')))
             .then(() => {
-                if (this.viewReceipt) {
-                    this.vnReport.show('receipt', {
-                        receiptId: receiptId,
-                        companyId: this.companyFk
-                    });
-                }
+                if (this.viewReceipt)
+                    this.vnReport.show(`Receipts/${receiptId}/receipt-pdf`);
             });
     }
 
diff --git a/modules/client/front/balance/create/index.spec.js b/modules/client/front/balance/create/index.spec.js
index 77fe32e0f4..fa6b48ea42 100644
--- a/modules/client/front/balance/create/index.spec.js
+++ b/modules/client/front/balance/create/index.spec.js
@@ -85,6 +85,8 @@ describe('Client', () => {
             });
 
             it('should make an http POST query and then call to the report show() method', () => {
+                const receiptId = 1;
+
                 jest.spyOn(controller.vnApp, 'showSuccess');
                 jest.spyOn(controller.vnReport, 'show');
                 window.open = jest.fn();
@@ -92,14 +94,12 @@ describe('Client', () => {
                 controller.$params = {id: 1101};
                 controller.viewReceipt = true;
 
-                $httpBackend.expect('POST', `Clients/1101/createReceipt`).respond({id: 1});
+                $httpBackend.expect('POST', `Clients/1101/createReceipt`).respond({id: receiptId});
                 controller.responseHandler('accept');
                 $httpBackend.flush();
 
-                const expectedParams = {receiptId: 1, companyId: 442};
-
                 expect(controller.vnApp.showSuccess).toHaveBeenCalled();
-                expect(controller.vnReport.show).toHaveBeenCalledWith('receipt', expectedParams);
+                expect(controller.vnReport.show).toHaveBeenCalledWith(`Receipts/${receiptId}/receipt-pdf`);
             });
         });
 

From a66c5e67984950e8f6fcb11a424af51694ec6f9d Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Mon, 24 Oct 2022 11:30:17 +0200
Subject: [PATCH 102/151] acl

---
 db/changes/10490-august/00-acl_receiptPdf.sql | 3 +++
 1 file changed, 3 insertions(+)
 create mode 100644 db/changes/10490-august/00-acl_receiptPdf.sql

diff --git a/db/changes/10490-august/00-acl_receiptPdf.sql b/db/changes/10490-august/00-acl_receiptPdf.sql
new file mode 100644
index 0000000000..42f84b87d2
--- /dev/null
+++ b/db/changes/10490-august/00-acl_receiptPdf.sql
@@ -0,0 +1,3 @@
+INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
+    VALUES
+        ('Receipt', 'receiptPdf', '*', 'ALLOW', 'ROLE', 'salesAssistant');

From 9e0eab5a77dab1f8aa66ccb940cd6b69be041d95 Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Mon, 24 Oct 2022 15:15:23 +0200
Subject: [PATCH 103/151] feat(invoiceIn): email

---
 db/changes/10491-august/00-invoiceInPdf.sql   |  4 ++
 db/changes/10491-august/delete.keep           |  0
 .../back/methods/invoice-in/invoiceInEmail.js | 56 +++++++++++++++++++
 .../back/methods/invoice-in/invoiceInPdf.js   |  5 +-
 modules/invoiceIn/back/models/invoice-in.js   |  1 +
 modules/invoiceIn/back/models/invoice-in.json |  5 ++
 modules/invoiceIn/front/card/index.js         |  8 +++
 modules/invoiceIn/front/descriptor/index.html |  3 +-
 modules/invoiceIn/front/descriptor/index.js   | 14 ++++-
 .../email/delivery-note-link/locale/pt.yml    |  2 +-
 .../email/invoiceIn/assets/css/import.js      | 11 ++++
 .../email/invoiceIn/attachments.json          |  6 ++
 .../templates/email/invoiceIn/invoiceIn.html  | 47 ++++++++++++++++
 print/templates/email/invoiceIn/invoiceIn.js  | 19 +++++++
 print/templates/email/invoiceIn/locale/en.yml |  5 ++
 print/templates/email/invoiceIn/locale/es.yml |  5 ++
 print/templates/email/invoiceIn/locale/fr.yml |  5 ++
 print/templates/email/invoiceIn/locale/pt.yml |  5 ++
 .../reports/invoiceIn/invoiceIn.html          |  1 +
 .../templates/reports/invoiceIn/locale/en.yml |  4 +-
 .../reports/invoiceIn/sql/invoice.sql         |  3 +-
 21 files changed, 199 insertions(+), 10 deletions(-)
 create mode 100644 db/changes/10491-august/00-invoiceInPdf.sql
 delete mode 100644 db/changes/10491-august/delete.keep
 create mode 100644 modules/invoiceIn/back/methods/invoice-in/invoiceInEmail.js
 create mode 100644 print/templates/email/invoiceIn/assets/css/import.js
 create mode 100644 print/templates/email/invoiceIn/attachments.json
 create mode 100644 print/templates/email/invoiceIn/invoiceIn.html
 create mode 100755 print/templates/email/invoiceIn/invoiceIn.js
 create mode 100644 print/templates/email/invoiceIn/locale/en.yml
 create mode 100644 print/templates/email/invoiceIn/locale/es.yml
 create mode 100644 print/templates/email/invoiceIn/locale/fr.yml
 create mode 100644 print/templates/email/invoiceIn/locale/pt.yml

diff --git a/db/changes/10491-august/00-invoiceInPdf.sql b/db/changes/10491-august/00-invoiceInPdf.sql
new file mode 100644
index 0000000000..d7dc038aa2
--- /dev/null
+++ b/db/changes/10491-august/00-invoiceInPdf.sql
@@ -0,0 +1,4 @@
+INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
+    VALUES
+        ('InvoiceIn', 'invoiceInPdf', 'READ', 'ALLOW', 'ROLE', 'administrative'),
+        ('InvoiceIn', 'invoiceInEmail', 'WRITE', 'ALLOW', 'ROLE', 'administrative'),
diff --git a/db/changes/10491-august/delete.keep b/db/changes/10491-august/delete.keep
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/modules/invoiceIn/back/methods/invoice-in/invoiceInEmail.js b/modules/invoiceIn/back/methods/invoice-in/invoiceInEmail.js
new file mode 100644
index 0000000000..b04108bd7e
--- /dev/null
+++ b/modules/invoiceIn/back/methods/invoice-in/invoiceInEmail.js
@@ -0,0 +1,56 @@
+const {Email} = require('vn-print');
+
+module.exports = Self => {
+    Self.remoteMethodCtx('invoiceInEmail', {
+        description: 'Sends the invoice in email with an attached PDF',
+        accessType: 'WRITE',
+        accepts: [
+            {
+                arg: 'id',
+                type: 'number',
+                required: true,
+                description: 'The invoice id',
+                http: {source: 'path'}
+            },
+            {
+                arg: 'recipient',
+                type: 'string',
+                description: 'The recipient email',
+                required: true,
+            },
+            {
+                arg: 'recipientId',
+                type: 'number',
+                description: 'The recipient id to send to the recipient preferred language',
+                required: false
+            }
+        ],
+        returns: {
+            type: ['object'],
+            root: true
+        },
+        http: {
+            path: '/:id/invoice-in-email',
+            verb: 'POST'
+        }
+    });
+
+    Self.invoiceInEmail = async(ctx, id) => {
+        const args = Object.assign({}, ctx.args);
+        const params = {
+            recipient: 'alexm@verdnatura.es', // args.recipient,
+            lang: ctx.req.getLocale()
+        };
+
+        console.log(id);
+
+        delete args.ctx;
+        for (const param in args)
+            params[param] = args[param];
+        console.log(params);
+
+        const email = new Email('invoiceIn', params);
+
+        return email.send();
+    };
+};
diff --git a/modules/invoiceIn/back/methods/invoice-in/invoiceInPdf.js b/modules/invoiceIn/back/methods/invoice-in/invoiceInPdf.js
index 1b7ca9c686..f1d17dce76 100644
--- a/modules/invoiceIn/back/methods/invoice-in/invoiceInPdf.js
+++ b/modules/invoiceIn/back/methods/invoice-in/invoiceInPdf.js
@@ -29,17 +29,16 @@ module.exports = Self => {
             }
         ],
         http: {
-            path: '/:id/invoiceInPdf',
+            path: '/:id/invoice-in-pdf',
             verb: 'GET'
         }
     });
 
     Self.invoiceInPdf = async(ctx, id) => {
-        console.log(id);
         const args = Object.assign({}, ctx.args);
         const params = {lang: ctx.req.getLocale()};
         delete args.ctx;
-        console.log(args);
+
         for (const param in args)
             params[param] = args[param];
 
diff --git a/modules/invoiceIn/back/models/invoice-in.js b/modules/invoiceIn/back/models/invoice-in.js
index e2c1326714..95ccc7b205 100644
--- a/modules/invoiceIn/back/models/invoice-in.js
+++ b/modules/invoiceIn/back/models/invoice-in.js
@@ -5,4 +5,5 @@ module.exports = Self => {
     require('../methods/invoice-in/toBook')(Self);
     require('../methods/invoice-in/getTotals')(Self);
     require('../methods/invoice-in/invoiceInPdf')(Self);
+    require('../methods/invoice-in/invoiceInEmail')(Self);
 };
diff --git a/modules/invoiceIn/back/models/invoice-in.json b/modules/invoiceIn/back/models/invoice-in.json
index c6a736b06a..fa8a1d8f84 100644
--- a/modules/invoiceIn/back/models/invoice-in.json
+++ b/modules/invoiceIn/back/models/invoice-in.json
@@ -94,6 +94,11 @@
             "model": "Supplier",
             "foreignKey": "supplierFk"
         },
+        "supplierContact": {
+            "type": "hasMany",
+            "model": "SupplierContact",
+            "foreignKey": "supplierFk"
+        },
         "currency": {
             "type": "belongsTo",
             "model": "Currency",
diff --git a/modules/invoiceIn/front/card/index.js b/modules/invoiceIn/front/card/index.js
index 582c2abb8c..c7ac08cc7e 100644
--- a/modules/invoiceIn/front/card/index.js
+++ b/modules/invoiceIn/front/card/index.js
@@ -8,6 +8,14 @@ class Controller extends ModuleCard {
                 {
                     relation: 'supplier'
                 },
+                {
+                    relation: 'supplierContact',
+                    scope: {
+                        where: {
+                            email: {neq: null}
+                        }
+                    }
+                },
                 {
                     relation: 'invoiceInDueDay'
                 },
diff --git a/modules/invoiceIn/front/descriptor/index.html b/modules/invoiceIn/front/descriptor/index.html
index faff5b9765..095bbd8e71 100644
--- a/modules/invoiceIn/front/descriptor/index.html
+++ b/modules/invoiceIn/front/descriptor/index.html
@@ -31,7 +31,7 @@
             Show Invoice as PDF
         </vn-item>
         <vn-item
-            ng-click="sendPdfConfirmation.show({email: $ctrl.entity})"
+            ng-click="sendPdfConfirmation.show({email: $ctrl.entity.supplierContact[0].email})"
             translate>
             Send Invoice as PDF
         </vn-item>
@@ -99,7 +99,6 @@
     on-accept="$ctrl.sendPdfInvoice($data)"
     message="Send PDF invoice">
     <tpl-body>
-        {{sendPdfConfirmation.data.email}}
         <span translate>Are you sure you want to send it?</span>
         <vn-textfield vn-one
             label="Email"
diff --git a/modules/invoiceIn/front/descriptor/index.js b/modules/invoiceIn/front/descriptor/index.js
index 0198e868f2..6c844a2337 100644
--- a/modules/invoiceIn/front/descriptor/index.js
+++ b/modules/invoiceIn/front/descriptor/index.js
@@ -8,6 +8,7 @@ class Controller extends Descriptor {
 
     set invoiceIn(value) {
         this.entity = value;
+        console.log(value);
     }
 
     get entryFilter() {
@@ -96,8 +97,19 @@ class Controller extends Descriptor {
             .then(() => this.$state.reload())
             .then(() => this.vnApp.showSuccess(this.$t('InvoiceIn booked')));
     }
+
     showPdfInvoice() {
-        this.vnReport.show(`InvoiceIns/${this.id}/invoiceInPdf`);
+        this.vnReport.show(`InvoiceIns/${this.id}/invoice-in-pdf`);
+    }
+
+    sendPdfInvoice($data) {
+        if (!$data.email)
+            return this.vnApp.showError(this.$t(`The email can't be empty`));
+
+        return this.vnEmail.send(`InvoiceIns/${this.entity.id}/invoice-in-email`, {
+            recipient: $data.email,
+            recipientId: this.entity.supplier.id
+        });
     }
 }
 
diff --git a/print/templates/email/delivery-note-link/locale/pt.yml b/print/templates/email/delivery-note-link/locale/pt.yml
index 1aab4b6d8a..9a70fc4cda 100644
--- a/print/templates/email/delivery-note-link/locale/pt.yml
+++ b/print/templates/email/delivery-note-link/locale/pt.yml
@@ -7,4 +7,4 @@ copyLink: 'Como alternativa, podes copiar o siguinte link no teu navegador:'
 poll: Si o deseja, podes responder nosso questionário de satiscação para ajudar-nos a prestar-vos um melhor serviço. Tua opinião é muito importante para nós!
 help: Cualquer dúvida que surja, no hesites em consultar-la, <strong>Estamos aqui para
   atender-te!</strong>
-conclusion: Obrigado por tua atenção!
\ No newline at end of file
+conclusion: Obrigado por tua atenção!
diff --git a/print/templates/email/invoiceIn/assets/css/import.js b/print/templates/email/invoiceIn/assets/css/import.js
new file mode 100644
index 0000000000..4b4bb70869
--- /dev/null
+++ b/print/templates/email/invoiceIn/assets/css/import.js
@@ -0,0 +1,11 @@
+const Stylesheet = require(`vn-print/core/stylesheet`);
+
+const path = require('path');
+const vnPrintPath = path.resolve('print');
+
+module.exports = new Stylesheet([
+    `${vnPrintPath}/common/css/spacing.css`,
+    `${vnPrintPath}/common/css/misc.css`,
+    `${vnPrintPath}/common/css/layout.css`,
+    `${vnPrintPath}/common/css/email.css`])
+    .mergeStyles();
diff --git a/print/templates/email/invoiceIn/attachments.json b/print/templates/email/invoiceIn/attachments.json
new file mode 100644
index 0000000000..cd23d3f924
--- /dev/null
+++ b/print/templates/email/invoiceIn/attachments.json
@@ -0,0 +1,6 @@
+[
+    {
+        "filename": "invoiceIn.pdf",
+        "component": "invoiceIn"
+    }
+]
diff --git a/print/templates/email/invoiceIn/invoiceIn.html b/print/templates/email/invoiceIn/invoiceIn.html
new file mode 100644
index 0000000000..65453ccd6d
--- /dev/null
+++ b/print/templates/email/invoiceIn/invoiceIn.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<html v-bind:lang="$i18n.locale">
+    <head>
+        <meta name="viewport" content="width=device-width">
+        <meta name="format-detection" content="telephone=no">
+        <title>{{ $t('subject') }}</title>
+    </head>
+    <body>
+        <table class="grid">
+            <tbody>
+                <tr>
+                    <td>
+                        <!-- Empty block -->
+                        <div class="grid-row">
+                            <div class="grid-block empty"></div>
+                        </div>
+                        <!-- Header block -->
+                        <div class="grid-row">
+                            <div class="grid-block">
+                                <email-header v-bind="$props"></email-header>
+                            </div>
+                        </div>
+                        <!-- Block -->
+                        <div class="grid-row">
+                            <div class="grid-block vn-pa-ml">
+                                <h1>{{ $t('title') }}</h1>
+                                <p>{{$t('dear')}},</p>
+                                <p v-html="$t('description')"></p>
+                                <p v-html="$t('conclusion')"></p>
+                            </div>
+                        </div>
+                        <!-- Footer block -->
+                        <div class="grid-row">
+                            <div class="grid-block">
+                                <email-footer v-bind="$props"></email-footer>
+                            </div>
+                        </div>
+                        <!-- Empty block -->
+                        <div class="grid-row">
+                            <div class="grid-block empty"></div>
+                        </div>
+                    </td>
+                </tr>
+            </tbody>
+        </table>
+    </body>
+</html>
diff --git a/print/templates/email/invoiceIn/invoiceIn.js b/print/templates/email/invoiceIn/invoiceIn.js
new file mode 100755
index 0000000000..43e95120c1
--- /dev/null
+++ b/print/templates/email/invoiceIn/invoiceIn.js
@@ -0,0 +1,19 @@
+const Component = require(`vn-print/core/component`);
+const emailHeader = new Component('email-header');
+const emailFooter = new Component('email-footer');
+
+module.exports = {
+    name: 'invoiceIn',
+    async serverPrefetch() {
+        this.invoice = await this.fetchInvoice(this.id);
+    },
+    methods: {
+        fetchInvoice(reference) {
+            return this.findOneFromDef('invoice', [reference]);
+        },
+    },
+    components: {
+        'email-header': emailHeader.build(),
+        'email-footer': emailFooter.build()
+    }
+};
diff --git a/print/templates/email/invoiceIn/locale/en.yml b/print/templates/email/invoiceIn/locale/en.yml
new file mode 100644
index 0000000000..47ebc3966e
--- /dev/null
+++ b/print/templates/email/invoiceIn/locale/en.yml
@@ -0,0 +1,5 @@
+subject: Your agricultural invoice
+title: Your agricultural invoice
+dear: Dear supplier
+description: Attached you can find agricultural receipt generated from your last deliveries. Please return a signed and stamped copy to our administration department.
+conclusion: Thanks for your attention!
diff --git a/print/templates/email/invoiceIn/locale/es.yml b/print/templates/email/invoiceIn/locale/es.yml
new file mode 100644
index 0000000000..2698763cf6
--- /dev/null
+++ b/print/templates/email/invoiceIn/locale/es.yml
@@ -0,0 +1,5 @@
+subject: Tu factura agrícola
+title: Tu factura agrícola
+dear: Estimado proveedor
+description: Adjunto puede encontrar recibo agrícola generado de sus últimas entregas. Por favor, devuelva una copia firmada y sellada a nuestro de departamento de administración.
+conclusion: ¡Gracias por tu atención!
diff --git a/print/templates/email/invoiceIn/locale/fr.yml b/print/templates/email/invoiceIn/locale/fr.yml
new file mode 100644
index 0000000000..1c38f3c25f
--- /dev/null
+++ b/print/templates/email/invoiceIn/locale/fr.yml
@@ -0,0 +1,5 @@
+subject: Votre facture agricole
+title: Votre facture agricole
+dear: Cher Fournisseur
+description: Vous trouverez en pièce jointe le reçu agricole généré à partir de vos dernières livraisons. Veuillez retourner une copie signée et tamponnée à notre service administratif.
+conclusion: Merci pour votre attention!
diff --git a/print/templates/email/invoiceIn/locale/pt.yml b/print/templates/email/invoiceIn/locale/pt.yml
new file mode 100644
index 0000000000..a43e3a79da
--- /dev/null
+++ b/print/templates/email/invoiceIn/locale/pt.yml
@@ -0,0 +1,5 @@
+subject: A sua fatura agrícola
+title: A sua fatura agrícola
+dear: Caro Fornecedor
+description: Em anexo encontra-se o recibo agrícola gerado a partir das suas últimas entregas. Por favor, devolva uma cópia assinada e carimbada ao nosso departamento de administração.
+conclusion: Obrigado pela atenção.
diff --git a/print/templates/reports/invoiceIn/invoiceIn.html b/print/templates/reports/invoiceIn/invoiceIn.html
index 4bc6d8ee0e..5f15e6a9a7 100644
--- a/print/templates/reports/invoiceIn/invoiceIn.html
+++ b/print/templates/reports/invoiceIn/invoiceIn.html
@@ -201,6 +201,7 @@
                     </div>
                     <!-- Footer block -->
                     <report-footer id="pageFooter"
+                        v-bind:company-code="invoice.companyCode"
                         v-bind:left-text="$t('invoice', [invoice.id])"
                         v-bind:center-text="invoice.name"
                         v-bind="$props">
diff --git a/print/templates/reports/invoiceIn/locale/en.yml b/print/templates/reports/invoiceIn/locale/en.yml
index 7a8767ad32..92d3b0c2dd 100644
--- a/print/templates/reports/invoiceIn/locale/en.yml
+++ b/print/templates/reports/invoiceIn/locale/en.yml
@@ -1,6 +1,6 @@
 reportName: invoice
-title: Agrobusiness invoice
-invoiceId: Agrobusiness invoice
+title: Agricultural  invoice
+invoiceId: Agricultural  invoice
 supplierId: Proveedor
 invoiceData: Invoice data
 reference: Reference
diff --git a/print/templates/reports/invoiceIn/sql/invoice.sql b/print/templates/reports/invoiceIn/sql/invoice.sql
index fe9ef1e9e0..2f6929b2a9 100644
--- a/print/templates/reports/invoiceIn/sql/invoice.sql
+++ b/print/templates/reports/invoiceIn/sql/invoice.sql
@@ -6,7 +6,8 @@ SELECT
         s.street AS postalAddress,
         s.nif,
         s.phone,
-        p.name payMethod
+        p.name payMethod,
+        c.companyCode
 	FROM invoiceIn i
 		JOIN supplier s ON s.id = i.supplierFk
 		JOIN company c ON c.id = i.companyFk

From e80754f2805dcf06772877456eb9ba55bb14bde4 Mon Sep 17 00:00:00 2001
From: joan <joan@verdnatura.es>
Date: Mon, 24 Oct 2022 18:37:38 +0200
Subject: [PATCH 104/151] Added new SQL version

---
 db/changes/10491-august/delete.keep           |  0
 db/changes/10500-november/00-ACL.sql          |  5 ++++
 db/changes/10500-november/00-claim.sql        |  1 +
 db/changes/10500-november/00-claimRma.sql     |  7 +++++
 .../claim/back/methods/claim/getSummary.js    |  2 +-
 modules/claim/back/model-config.json          |  9 ++++--
 modules/claim/back/models/claim-rma.json      | 30 +++++++++++++++++++
 modules/claim/back/models/claim.json          |  9 ++++++
 8 files changed, 59 insertions(+), 4 deletions(-)
 delete mode 100644 db/changes/10491-august/delete.keep
 create mode 100644 db/changes/10500-november/00-ACL.sql
 create mode 100644 db/changes/10500-november/00-claim.sql
 create mode 100644 db/changes/10500-november/00-claimRma.sql
 create mode 100644 modules/claim/back/models/claim-rma.json

diff --git a/db/changes/10491-august/delete.keep b/db/changes/10491-august/delete.keep
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/db/changes/10500-november/00-ACL.sql b/db/changes/10500-november/00-ACL.sql
new file mode 100644
index 0000000000..0b726538c6
--- /dev/null
+++ b/db/changes/10500-november/00-ACL.sql
@@ -0,0 +1,5 @@
+INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalType, principalId)
+VALUES 
+    ('ClaimRma', '*', 'READ', 'ALLOW', 'ROLE', 'claimManager'),
+    ('ClaimRma', '*', 'WRITE', 'ALLOW', 'ROLE', 'claimManager');
+
diff --git a/db/changes/10500-november/00-claim.sql b/db/changes/10500-november/00-claim.sql
new file mode 100644
index 0000000000..0b98798781
--- /dev/null
+++ b/db/changes/10500-november/00-claim.sql
@@ -0,0 +1 @@
+ALTER TABLE `vn`.`claim` ADD rma varchar(100) NULL ;
\ No newline at end of file
diff --git a/db/changes/10500-november/00-claimRma.sql b/db/changes/10500-november/00-claimRma.sql
new file mode 100644
index 0000000000..91e1ebabae
--- /dev/null
+++ b/db/changes/10500-november/00-claimRma.sql
@@ -0,0 +1,7 @@
+CREATE TABLE `vn`.`claimRma` (
+    id INT UNSIGNED auto_increment NOT NULL PRIMARY KEY,
+    code varchar(100) NOT NULL,
+    created timestamp DEFAULT current_timestamp() NOT NULL,
+    workerFk INTEGER UNSIGNED NOT NULL
+)
+ENGINE=InnoDB;
diff --git a/modules/claim/back/methods/claim/getSummary.js b/modules/claim/back/methods/claim/getSummary.js
index 8ab39eb45c..ca376f8533 100644
--- a/modules/claim/back/methods/claim/getSummary.js
+++ b/modules/claim/back/methods/claim/getSummary.js
@@ -47,7 +47,7 @@ module.exports = Self => {
                 {
                     relation: 'claimState',
                     scope: {
-                        fields: ['id', 'description']
+                        fields: ['id', 'code', 'description']
                     }
                 },
                 {
diff --git a/modules/claim/back/model-config.json b/modules/claim/back/model-config.json
index e99a455aca..83d88039c7 100644
--- a/modules/claim/back/model-config.json
+++ b/modules/claim/back/model-config.json
@@ -2,6 +2,9 @@
     "Claim": {
         "dataSource": "vn"
     },
+    "ClaimContainer": {
+        "dataSource": "claimStorage"
+    },
     "ClaimBeginning": {
         "dataSource": "vn"
     },
@@ -41,7 +44,7 @@
     "ClaimObservation": {
         "dataSource": "vn"
     },
-    "ClaimContainer": {
-        "dataSource": "claimStorage"
-    }               
+    "ClaimRma": {
+        "dataSource": "vn"
+    }                
 }
diff --git a/modules/claim/back/models/claim-rma.json b/modules/claim/back/models/claim-rma.json
new file mode 100644
index 0000000000..24c17a2346
--- /dev/null
+++ b/modules/claim/back/models/claim-rma.json
@@ -0,0 +1,30 @@
+{
+    "name": "ClaimRma",
+    "base": "VnModel",
+    "options": {
+        "mysql": {
+            "table": "claimRma"
+        }
+    },
+    "properties": {
+        "id": {
+            "type": "number",
+            "id": true,
+            "description": "Identifier"
+        },
+        "code": {
+            "type": "string",
+            "required": true
+        },
+        "created": {
+            "type": "date"
+        }
+    },
+    "relations": {
+        "worker": {
+            "type": "belongsTo",
+            "model": "worker",
+            "foreignKey": "workerFk"
+        }
+    }
+}
diff --git a/modules/claim/back/models/claim.json b/modules/claim/back/models/claim.json
index a3490ccf47..76125c483c 100644
--- a/modules/claim/back/models/claim.json
+++ b/modules/claim/back/models/claim.json
@@ -46,6 +46,9 @@
         },
         "packages": {
             "type": "number"
+        },
+        "rma": {
+            "type": "string"
         }
     },
     "relations": {
@@ -54,6 +57,12 @@
             "model": "ClaimState",
             "foreignKey": "claimStateFk"
         },
+        "claimRma": {
+            "type": "belongsTo",
+            "model": "ClaimRma",
+            "foreignKey": "rma",
+            "primaryKey": "code"
+        },
         "client": {
             "type": "belongsTo",
             "model": "Client",

From 8a3573474a99de0a60a330ab00c0fd106273c406 Mon Sep 17 00:00:00 2001
From: vicent <vicent@verdnatura.es>
Date: Tue, 25 Oct 2022 07:40:32 +0200
Subject: [PATCH 105/151] refactor: move 'lastEntries' to thrid position in
 descriptor

---
 modules/item/front/routes.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/modules/item/front/routes.json b/modules/item/front/routes.json
index 52cf5d2be9..3dea69ba1b 100644
--- a/modules/item/front/routes.json
+++ b/modules/item/front/routes.json
@@ -15,12 +15,12 @@
         "card": [
             {"state": "item.card.basicData", "icon": "settings"},
             {"state": "item.card.tags", "icon": "icon-tags"},
+            {"state": "item.card.last-entries", "icon": "icon-regentry"},
             {"state": "item.card.tax", "icon": "icon-tax"},
             {"state": "item.card.botanical", "icon": "local_florist"},
             {"state": "item.card.shelving", "icon": "icon-inventory"},
             {"state": "item.card.itemBarcode", "icon": "icon-barcode"}, 
             {"state": "item.card.diary", "icon": "icon-transaction"}, 
-            {"state": "item.card.last-entries", "icon": "icon-regentry"},
             {"state": "item.card.log", "icon": "history"}
         ],
         "itemType": [

From 7f1dd801a55aff414fbaf06eacbbdb8bf25039ad Mon Sep 17 00:00:00 2001
From: vicent <vicent@verdnatura.es>
Date: Tue, 25 Oct 2022 07:56:17 +0200
Subject: [PATCH 106/151] refactor: change ACLs

---
 db/changes/10491-august/00-aclItemShelving.sql                | 3 ---
 db/changes/10491-august/00-aclItemShelvingPlacementSupply.sql | 3 ---
 db/changes/10500-november/00-itemShelvingACL.sql              | 4 ++++
 .../10500-november/00-itemShelvingPlacementSupplyStockACL.sql | 4 ++++
 4 files changed, 8 insertions(+), 6 deletions(-)
 delete mode 100644 db/changes/10491-august/00-aclItemShelving.sql
 delete mode 100644 db/changes/10491-august/00-aclItemShelvingPlacementSupply.sql
 create mode 100644 db/changes/10500-november/00-itemShelvingACL.sql
 create mode 100644 db/changes/10500-november/00-itemShelvingPlacementSupplyStockACL.sql

diff --git a/db/changes/10491-august/00-aclItemShelving.sql b/db/changes/10491-august/00-aclItemShelving.sql
deleted file mode 100644
index 3995bbe497..0000000000
--- a/db/changes/10491-august/00-aclItemShelving.sql
+++ /dev/null
@@ -1,3 +0,0 @@
-INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
-    VALUES
-        ('ItemShelving', '*', '*', 'ALLOW', 'ROLE', 'employee');
\ No newline at end of file
diff --git a/db/changes/10491-august/00-aclItemShelvingPlacementSupply.sql b/db/changes/10491-august/00-aclItemShelvingPlacementSupply.sql
deleted file mode 100644
index cc589a58f4..0000000000
--- a/db/changes/10491-august/00-aclItemShelvingPlacementSupply.sql
+++ /dev/null
@@ -1,3 +0,0 @@
-INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
-    VALUES
-        ('ItemShelvingPlacementSupplyStock', '*', '*', 'ALLOW', 'ROLE', 'employee');
\ No newline at end of file
diff --git a/db/changes/10500-november/00-itemShelvingACL.sql b/db/changes/10500-november/00-itemShelvingACL.sql
new file mode 100644
index 0000000000..fc32fe1edc
--- /dev/null
+++ b/db/changes/10500-november/00-itemShelvingACL.sql
@@ -0,0 +1,4 @@
+INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalType, principalId)
+VALUES 
+    ('ItemShelving', '*', 'READ', 'ALLOW', 'ROLE', 'employee'),
+    ('ItemShelving', '*', 'WRITE', 'ALLOW', 'ROLE', 'production');
\ No newline at end of file
diff --git a/db/changes/10500-november/00-itemShelvingPlacementSupplyStockACL.sql b/db/changes/10500-november/00-itemShelvingPlacementSupplyStockACL.sql
new file mode 100644
index 0000000000..25eac8d518
--- /dev/null
+++ b/db/changes/10500-november/00-itemShelvingPlacementSupplyStockACL.sql
@@ -0,0 +1,4 @@
+INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalType, principalId)
+VALUES 
+    ('ItemShelvingPlacementSupplyStock', '*', 'READ', 'ALLOW', 'ROLE', 'employee');
+

From 931a891f716da36e72ff7c109df9a8bc7bc08952 Mon Sep 17 00:00:00 2001
From: vicent <vicent@verdnatura.es>
Date: Tue, 25 Oct 2022 08:09:23 +0200
Subject: [PATCH 107/151] fix: check client.email exists

---
 modules/client/back/methods/client/checkDuplicated.js | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/modules/client/back/methods/client/checkDuplicated.js b/modules/client/back/methods/client/checkDuplicated.js
index acaffbf428..522cd088ff 100644
--- a/modules/client/back/methods/client/checkDuplicated.js
+++ b/modules/client/back/methods/client/checkDuplicated.js
@@ -25,10 +25,9 @@ module.exports = Self => {
 
         const client = await Self.app.models.Client.findById(id, myOptions);
 
-        const emails = client.email ? client.email.split(',') : null;
-
         const findParams = [];
-        if (emails.length) {
+        if (client.email) {
+            const emails = client.email.split(',');
             for (let email of emails)
                 findParams.push({email: email});
         }

From 4520443734acaa97fe7286399014e7010b7918fc Mon Sep 17 00:00:00 2001
From: joan <joan@verdnatura.es>
Date: Tue, 25 Oct 2022 08:16:56 +0200
Subject: [PATCH 108/151] fix: Intl polyfill for spanish locale

---
 print/index.js | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/print/index.js b/print/index.js
index 7ba3586ebd..2ed7138975 100644
--- a/print/index.js
+++ b/print/index.js
@@ -7,8 +7,12 @@ const componentsPath = path.resolve(__dirname, './core/components');
 
 module.exports = {
     async boot(app) {
-        // Init database instance
+        // Extended locale intl polyfill
+        const IntlPolyfill = require('intl');
+        Intl.NumberFormat = IntlPolyfill.NumberFormat;
+        Intl.DateTimeFormat = IntlPolyfill.DateTimeFormat;
 
+        // Init database instance
         require('./core/database').init(app.dataSources);
         require('./core/smtp').init();
         require('./core/cluster').init();

From e8500f926c6af4cbc1c14a528555adf56f0fcab7 Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Tue, 25 Oct 2022 08:19:56 +0200
Subject: [PATCH 109/151] feat(invoiceIn): add email

---
 .../invoiceIn/back/methods/invoice-in/invoiceInEmail.js   | 7 ++-----
 modules/invoiceIn/front/descriptor/index.js               | 1 -
 print/templates/email/invoiceIn/invoiceIn.js              | 8 --------
 print/templates/reports/invoiceIn/invoiceIn.html          | 2 +-
 print/templates/reports/invoiceIn/sql/invoice.sql         | 3 +--
 5 files changed, 4 insertions(+), 17 deletions(-)

diff --git a/modules/invoiceIn/back/methods/invoice-in/invoiceInEmail.js b/modules/invoiceIn/back/methods/invoice-in/invoiceInEmail.js
index b04108bd7e..0768541a85 100644
--- a/modules/invoiceIn/back/methods/invoice-in/invoiceInEmail.js
+++ b/modules/invoiceIn/back/methods/invoice-in/invoiceInEmail.js
@@ -35,19 +35,16 @@ module.exports = Self => {
         }
     });
 
-    Self.invoiceInEmail = async(ctx, id) => {
+    Self.invoiceInEmail = async ctx => {
         const args = Object.assign({}, ctx.args);
         const params = {
-            recipient: 'alexm@verdnatura.es', // args.recipient,
+            recipient: args.recipient,
             lang: ctx.req.getLocale()
         };
 
-        console.log(id);
-
         delete args.ctx;
         for (const param in args)
             params[param] = args[param];
-        console.log(params);
 
         const email = new Email('invoiceIn', params);
 
diff --git a/modules/invoiceIn/front/descriptor/index.js b/modules/invoiceIn/front/descriptor/index.js
index 6c844a2337..5cd00d7434 100644
--- a/modules/invoiceIn/front/descriptor/index.js
+++ b/modules/invoiceIn/front/descriptor/index.js
@@ -8,7 +8,6 @@ class Controller extends Descriptor {
 
     set invoiceIn(value) {
         this.entity = value;
-        console.log(value);
     }
 
     get entryFilter() {
diff --git a/print/templates/email/invoiceIn/invoiceIn.js b/print/templates/email/invoiceIn/invoiceIn.js
index 43e95120c1..f7a472eb28 100755
--- a/print/templates/email/invoiceIn/invoiceIn.js
+++ b/print/templates/email/invoiceIn/invoiceIn.js
@@ -4,14 +4,6 @@ const emailFooter = new Component('email-footer');
 
 module.exports = {
     name: 'invoiceIn',
-    async serverPrefetch() {
-        this.invoice = await this.fetchInvoice(this.id);
-    },
-    methods: {
-        fetchInvoice(reference) {
-            return this.findOneFromDef('invoice', [reference]);
-        },
-    },
     components: {
         'email-header': emailHeader.build(),
         'email-footer': emailFooter.build()
diff --git a/print/templates/reports/invoiceIn/invoiceIn.html b/print/templates/reports/invoiceIn/invoiceIn.html
index 5f15e6a9a7..8919403b9e 100644
--- a/print/templates/reports/invoiceIn/invoiceIn.html
+++ b/print/templates/reports/invoiceIn/invoiceIn.html
@@ -202,7 +202,7 @@
                     <!-- Footer block -->
                     <report-footer id="pageFooter"
                         v-bind:company-code="invoice.companyCode"
-                        v-bind:left-text="$t('invoice', [invoice.id])"
+                        v-bind:left-text="$t('invoiceId')"
                         v-bind:center-text="invoice.name"
                         v-bind="$props">
                     </report-footer>
diff --git a/print/templates/reports/invoiceIn/sql/invoice.sql b/print/templates/reports/invoiceIn/sql/invoice.sql
index 2f6929b2a9..fe9ef1e9e0 100644
--- a/print/templates/reports/invoiceIn/sql/invoice.sql
+++ b/print/templates/reports/invoiceIn/sql/invoice.sql
@@ -6,8 +6,7 @@ SELECT
         s.street AS postalAddress,
         s.nif,
         s.phone,
-        p.name payMethod,
-        c.companyCode
+        p.name payMethod
 	FROM invoiceIn i
 		JOIN supplier s ON s.id = i.supplierFk
 		JOIN company c ON c.id = i.companyFk

From 23598c993b74572e0a658d66560636197832d9b4 Mon Sep 17 00:00:00 2001
From: Pau Navarro <pau@verdnatura.es>
Date: Tue, 25 Oct 2022 09:25:15 +0200
Subject: [PATCH 110/151] Change ACL from employee to hr

---
 db/changes/10491-august/00-ACL_workerDisableExcluded.sql | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/db/changes/10491-august/00-ACL_workerDisableExcluded.sql b/db/changes/10491-august/00-ACL_workerDisableExcluded.sql
index 7a23ca68a6..2fd9e8b121 100644
--- a/db/changes/10491-august/00-ACL_workerDisableExcluded.sql
+++ b/db/changes/10491-august/00-ACL_workerDisableExcluded.sql
@@ -1,2 +1,2 @@
 INSERT INTO `salix`.`ACL` (model,property,accessType,permission,principalId)
-	VALUES ('WorkerDisableExcluded','*','*','ALLOW','employee');
+	VALUES ('WorkerDisableExcluded','*','*','ALLOW','hr');
\ No newline at end of file

From 9089ba73469f9b75e6248ea08aa0aa5672ea1e7e Mon Sep 17 00:00:00 2001
From: Pau Navarro <pau@verdnatura.es>
Date: Tue, 25 Oct 2022 10:42:16 +0200
Subject: [PATCH 111/151] requested changes

---
 .../00-defaultPayDem_sameAs_production.sql    |  2 +-
 .../00-payMethodFk_Allow_Null.sql             |  2 +-
 .../00-supplierActivityFk_Allow_Null.sql      |  2 +-
 .../back/methods/supplier/newSupplier.js      |  7 +++---
 .../supplier/specs/newSupplier.spec.js        | 24 -------------------
 modules/supplier/front/create/index.html      |  7 ------
 modules/supplier/front/create/index.js        |  8 +------
 modules/supplier/front/routes.json            |  1 +
 8 files changed, 8 insertions(+), 45 deletions(-)

diff --git a/db/changes/10491-august/00-defaultPayDem_sameAs_production.sql b/db/changes/10491-august/00-defaultPayDem_sameAs_production.sql
index 2a7f5c61f7..2942473386 100644
--- a/db/changes/10491-august/00-defaultPayDem_sameAs_production.sql
+++ b/db/changes/10491-august/00-defaultPayDem_sameAs_production.sql
@@ -1,2 +1,2 @@
-INSERT INTO vn.payDem (id,payDem)
+INSERT INTO `vn`.`payDem` (id,payDem)
 	VALUES (7,'0');
diff --git a/db/changes/10491-august/00-payMethodFk_Allow_Null.sql b/db/changes/10491-august/00-payMethodFk_Allow_Null.sql
index 6fd2fee6ed..6d9931d3c1 100644
--- a/db/changes/10491-august/00-payMethodFk_Allow_Null.sql
+++ b/db/changes/10491-august/00-payMethodFk_Allow_Null.sql
@@ -1 +1 @@
-ALTER TABLE vn.supplier MODIFY COLUMN payMethodFk tinyint(3) unsigned NULL;
+ALTER TABLE `vn`.`supplier` MODIFY COLUMN payMethodFk tinyint(3) unsigned NULL;
\ No newline at end of file
diff --git a/db/changes/10491-august/00-supplierActivityFk_Allow_Null.sql b/db/changes/10491-august/00-supplierActivityFk_Allow_Null.sql
index 1fc4e29058..62aac0556b 100644
--- a/db/changes/10491-august/00-supplierActivityFk_Allow_Null.sql
+++ b/db/changes/10491-august/00-supplierActivityFk_Allow_Null.sql
@@ -1 +1 @@
-ALTER TABLE vn.supplier MODIFY COLUMN supplierActivityFk varchar(45) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL NULL;
+ALTER TABLE `vn`.`supplier` MODIFY COLUMN supplierActivityFk varchar(45) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL NULL;
\ No newline at end of file
diff --git a/modules/supplier/back/methods/supplier/newSupplier.js b/modules/supplier/back/methods/supplier/newSupplier.js
index 6206eaf1c3..a1894af70c 100644
--- a/modules/supplier/back/methods/supplier/newSupplier.js
+++ b/modules/supplier/back/methods/supplier/newSupplier.js
@@ -1,6 +1,6 @@
 module.exports = Self => {
     Self.remoteMethod('newSupplier', {
-        description: 'returns the created item',
+        description: 'Creates a new supplier and returns it',
         accessType: 'WRITE',
         accepts: [{
             arg: 'params',
@@ -33,12 +33,11 @@ module.exports = Self => {
 
         try {
             const supplier = await models.Supplier.create(params, myOptions);
+            console.log('supplier: ', supplier);
 
             if (tx) await tx.commit();
 
-            return {
-                supplier
-            };
+            return supplier;
         } catch (e) {
             if (tx) await tx.rollback();
             return params;
diff --git a/modules/supplier/back/methods/supplier/specs/newSupplier.spec.js b/modules/supplier/back/methods/supplier/specs/newSupplier.spec.js
index 8bf2713487..42012df01f 100644
--- a/modules/supplier/back/methods/supplier/specs/newSupplier.spec.js
+++ b/modules/supplier/back/methods/supplier/specs/newSupplier.spec.js
@@ -26,31 +26,7 @@ describe('Supplier newSupplier()', () => {
 
         expect(createdSupplier.id).toEqual(result.id);
         expect(createdSupplier.name).toEqual(result.name);
-        expect(createdSupplier.account).toBeNull();
-        expect(createdSupplier.nif).toBeNull();
-        expect(createdSupplier.phone).toBeNull();
-        expect(createdSupplier.retAccount).toBeNull();
-        expect(createdSupplier.commission).toBeFalse();
-        expect(createdSupplier.created).toBeDefined();
-        expect(createdSupplier.postcodeFk).toBeNull();
-        expect(createdSupplier.isActive).toBeTrue();
-        expect(createdSupplier.isOfficial).toBeTrue();
-        expect(createdSupplier.isSerious).toBeTrue();
-        expect(createdSupplier.note).toBeNull();
-        expect(createdSupplier.street).toBeNull();
-        expect(createdSupplier.city).toBeNull();
-        expect(createdSupplier.provinceFk).toBeNull();
-        expect(createdSupplier.postCode).toBeNull();
-        expect(createdSupplier.payMethodFk).toBeNull();
         expect(createdSupplier.payDemFk).toEqual(7);
-        expect(createdSupplier.payDay).toBeNull();
         expect(createdSupplier.nickname).toEqual(result.name);
-        expect(createdSupplier.workerFk).toBeNull();
-        expect(createdSupplier.sageTaxTypeFk).toBeNull();
-        expect(createdSupplier.sageTransactionTypeFk).toBeNull();
-        expect(createdSupplier.sageWithholdingFk).toBeNull();
-        expect(createdSupplier.isPayMethodChecked).toBeFalse();
-        expect(createdSupplier.supplierActivityFk).toBeNull();
-        expect(createdSupplier.healthRegister).toBeNull();
     });
 });
diff --git a/modules/supplier/front/create/index.html b/modules/supplier/front/create/index.html
index 17e4241151..446a16cb6a 100644
--- a/modules/supplier/front/create/index.html
+++ b/modules/supplier/front/create/index.html
@@ -5,13 +5,6 @@
     insert-mode="true"
     form="form">
 </vn-watcher>
-<vn-crud-model
-    auto-load="true"
-    url="Origins"
-    data="originsData"
-    order="name"
-    vn-id="origin-model">
-</vn-crud-model>
 <form name="form" ng-submit="$ctrl.onSubmit()" class="vn-w-md">
     <vn-card class="vn-pa-lg">
         <vn-horizontal>
diff --git a/modules/supplier/front/create/index.js b/modules/supplier/front/create/index.js
index 7c5a638bf5..c33367dac6 100644
--- a/modules/supplier/front/create/index.js
+++ b/modules/supplier/front/create/index.js
@@ -9,13 +9,7 @@ class Controller extends Section {
     onSubmit() {
         this.$.watcher.submit().then(
             json => {
-                this.$state.go('item.card.basicData', {id: json.data.id});
-
-                redirect(this.$.$ctrl);
-
-                function redirect(ctrl) {
-                    window.location.href = `/#!/supplier/${ctrl.supplier.supplier.id}/fiscal-data`;
-                }
+                this.$state.go(`supplier.card.fiscalData`, {id: json.data.id});
             }
         );
     }
diff --git a/modules/supplier/front/routes.json b/modules/supplier/front/routes.json
index 8c9b7f760b..75b8213cb7 100644
--- a/modules/supplier/front/routes.json
+++ b/modules/supplier/front/routes.json
@@ -56,6 +56,7 @@
             "url": "/create",
             "state": "supplier.create",
             "component": "vn-supplier-create",
+            "acl": ["administrative"],
             "description": "New supplier"
         }, 
         {

From 330af56d2f9dbfad7fe3291a6b39ac07c3fde5de Mon Sep 17 00:00:00 2001
From: joan <joan@verdnatura.es>
Date: Tue, 25 Oct 2022 11:42:28 +0200
Subject: [PATCH 112/151] Intl polyfill

---
 print/index.js | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/print/index.js b/print/index.js
index 484aba00eb..a71a452c4f 100644
--- a/print/index.js
+++ b/print/index.js
@@ -7,8 +7,12 @@ const componentsPath = path.resolve(__dirname, './core/components');
 
 module.exports = {
     async boot(app) {
-        // Init database instance
+        // Extended locale intl polyfill
+        const IntlPolyfill = require('intl');
+        Intl.NumberFormat = IntlPolyfill.NumberFormat;
+        Intl.DateTimeFormat = IntlPolyfill.DateTimeFormat;
 
+        // Init database instance
         require('./core/database').init(app.dataSources);
         require('./core/smtp').init();
         require('./core/mixins');

From 296a743d8a70e4a454f307050c48de2667c8592f Mon Sep 17 00:00:00 2001
From: Pau Navarro <pau@verdnatura.es>
Date: Tue, 25 Oct 2022 12:25:56 +0200
Subject: [PATCH 113/151] Fix test, remove console log

---
 modules/supplier/back/methods/supplier/newSupplier.js           | 1 -
 .../supplier/back/methods/supplier/specs/newSupplier.spec.js    | 2 --
 2 files changed, 3 deletions(-)

diff --git a/modules/supplier/back/methods/supplier/newSupplier.js b/modules/supplier/back/methods/supplier/newSupplier.js
index a1894af70c..f4059a259a 100644
--- a/modules/supplier/back/methods/supplier/newSupplier.js
+++ b/modules/supplier/back/methods/supplier/newSupplier.js
@@ -33,7 +33,6 @@ module.exports = Self => {
 
         try {
             const supplier = await models.Supplier.create(params, myOptions);
-            console.log('supplier: ', supplier);
 
             if (tx) await tx.commit();
 
diff --git a/modules/supplier/back/methods/supplier/specs/newSupplier.spec.js b/modules/supplier/back/methods/supplier/specs/newSupplier.spec.js
index 42012df01f..8f22a4f205 100644
--- a/modules/supplier/back/methods/supplier/specs/newSupplier.spec.js
+++ b/modules/supplier/back/methods/supplier/specs/newSupplier.spec.js
@@ -17,8 +17,6 @@ describe('Supplier newSupplier()', () => {
 
         let result = await app.models.Supplier.newSupplier(JSON.stringify(newSupp));
 
-        result = result.supplier;
-
         expect(result.name).toEqual('TestSupplier-1');
         expect(result.id).toEqual(443);
 

From 67402dfe5ee435e5f07af5f16ab485e1a40de601 Mon Sep 17 00:00:00 2001
From: alexandre <alexandre@verdnatura.es>
Date: Tue, 25 Oct 2022 13:27:04 +0200
Subject: [PATCH 114/151] =?UTF-8?q?refs=20#4650=20observaciones=20a=C3=B1a?=
 =?UTF-8?q?didas?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../templates/reports/delivery-note/assets/css/style.css  | 5 +++++
 print/templates/reports/delivery-note/delivery-note.html  | 6 ++++++
 print/templates/reports/delivery-note/delivery-note.js    | 4 ++++
 print/templates/reports/delivery-note/locale/en.yml       | 3 ++-
 print/templates/reports/delivery-note/locale/es.yml       | 3 ++-
 print/templates/reports/delivery-note/locale/fr.yml       | 3 ++-
 print/templates/reports/delivery-note/locale/pt.yml       | 3 ++-
 print/templates/reports/delivery-note/sql/ticket.sql      | 8 ++++++--
 8 files changed, 29 insertions(+), 6 deletions(-)

diff --git a/print/templates/reports/delivery-note/assets/css/style.css b/print/templates/reports/delivery-note/assets/css/style.css
index f99c385fab..8405ae78d9 100644
--- a/print/templates/reports/delivery-note/assets/css/style.css
+++ b/print/templates/reports/delivery-note/assets/css/style.css
@@ -37,4 +37,9 @@ h2 {
 
 .phytosanitary-info {
     margin-top: 10px
+}
+
+.observations{
+    text-align: justify;
+    text-justify: inter-word;
 }
\ No newline at end of file
diff --git a/print/templates/reports/delivery-note/delivery-note.html b/print/templates/reports/delivery-note/delivery-note.html
index d166f3307f..e34620591d 100644
--- a/print/templates/reports/delivery-note/delivery-note.html
+++ b/print/templates/reports/delivery-note/delivery-note.html
@@ -263,6 +263,12 @@
                                     </div>
                                     <!-- End of phytosanitary block -->
                                 </div>
+                                <div class="columns vn-mb-ml">
+                                    <!-- Observations block-->
+                                    <div class="size100 no-page-break" v-if="hasObservations">
+                                        <h2>{{$t('observations')}}</h2>
+                                        <p class="observations">{{ticket.description}}</p>
+                                    </div>
                                 <div class="columns">
                                     <!-- Signature block -->
                                     <div class="size50 pull-left no-page-break">
diff --git a/print/templates/reports/delivery-note/delivery-note.js b/print/templates/reports/delivery-note/delivery-note.js
index 1037e51296..78f0f7662b 100755
--- a/print/templates/reports/delivery-note/delivery-note.js
+++ b/print/templates/reports/delivery-note/delivery-note.js
@@ -55,6 +55,7 @@ module.exports = {
             const translatedType = this.$t(this.deliverNoteType);
             return `${translatedType} ${this.id}`;
         }
+        
     },
     methods: {
         fetchClient(id) {
@@ -119,6 +120,9 @@ module.exports = {
             return phytosanitary.filter((item, index) =>
                 phytosanitary.indexOf(item) == index
             ).join(', ');
+        },
+        hasObservations() {
+            return this.ticket.code == 'deliveryNote' && this.ticket.description != null;
         }
     },
     components: {
diff --git a/print/templates/reports/delivery-note/locale/en.yml b/print/templates/reports/delivery-note/locale/en.yml
index c74b875204..5902da8b39 100644
--- a/print/templates/reports/delivery-note/locale/en.yml
+++ b/print/templates/reports/delivery-note/locale/en.yml
@@ -46,4 +46,5 @@ taxes:
     fee: Fee
   tfoot: 
     subtotal: Subtotal
-    total: Total
\ No newline at end of file
+    total: Total
+observations: Observations
\ No newline at end of file
diff --git a/print/templates/reports/delivery-note/locale/es.yml b/print/templates/reports/delivery-note/locale/es.yml
index 5c5a6af4d3..d87198f45a 100644
--- a/print/templates/reports/delivery-note/locale/es.yml
+++ b/print/templates/reports/delivery-note/locale/es.yml
@@ -47,4 +47,5 @@ taxes:
     fee: Cuota
   tfoot: 
     subtotal: Subtotal
-    total: Total
\ No newline at end of file
+    total: Total
+observations: Observaciones
\ No newline at end of file
diff --git a/print/templates/reports/delivery-note/locale/fr.yml b/print/templates/reports/delivery-note/locale/fr.yml
index df7ca053b7..603623a475 100644
--- a/print/templates/reports/delivery-note/locale/fr.yml
+++ b/print/templates/reports/delivery-note/locale/fr.yml
@@ -47,4 +47,5 @@ taxes:
     fee: Quote
   tfoot: 
     subtotal: Total partiel
-    total: Total
\ No newline at end of file
+    total: Total
+observations: Observations
\ No newline at end of file
diff --git a/print/templates/reports/delivery-note/locale/pt.yml b/print/templates/reports/delivery-note/locale/pt.yml
index 1f418b31f5..fb49d230b4 100644
--- a/print/templates/reports/delivery-note/locale/pt.yml
+++ b/print/templates/reports/delivery-note/locale/pt.yml
@@ -47,4 +47,5 @@ taxes:
     fee: Compartilhado
   tfoot: 
     subtotal: Subtotal
-    total: Total
\ No newline at end of file
+    total: Total
+observations: Observações
\ No newline at end of file
diff --git a/print/templates/reports/delivery-note/sql/ticket.sql b/print/templates/reports/delivery-note/sql/ticket.sql
index f78c725444..3d16b53d85 100644
--- a/print/templates/reports/delivery-note/sql/ticket.sql
+++ b/print/templates/reports/delivery-note/sql/ticket.sql
@@ -2,7 +2,11 @@ SELECT
     t.id,
     t.shipped,
     c.code companyCode,
-    t.packages
+    t.packages,
+    tto.description,
+    ot.code 
 FROM ticket t
     JOIN company c ON c.id = t.companyFk
-WHERE t.id = ?
\ No newline at end of file
+    LEFT JOIN ticketObservation tto ON tto.ticketFk = t.id
+    LEFT JOIN observationType ot ON tto.observationTypeFk = ot.id 
+WHERE t.id = 1;
\ No newline at end of file

From 4334907d91c50b25cacec31ae33eb106199a4931 Mon Sep 17 00:00:00 2001
From: joan <joan@verdnatura.es>
Date: Tue, 25 Oct 2022 14:09:21 +0200
Subject: [PATCH 115/151] fix(database): updated sql files

---
 ...Ticket.sql => 00-ticket_closeByTicket.sql} |  8 +++--
 db/dump/fixtures.sql                          | 34 ++++++++++++-------
 modules/claim/back/models/claim-rma.js        |  9 +++++
 modules/claim/back/models/claim-rma.json      |  2 +-
 4 files changed, 38 insertions(+), 15 deletions(-)
 rename db/changes/10491-august/{ticket_closeByTicket.sql => 00-ticket_closeByTicket.sql} (85%)
 create mode 100644 modules/claim/back/models/claim-rma.js

diff --git a/db/changes/10491-august/ticket_closeByTicket.sql b/db/changes/10491-august/00-ticket_closeByTicket.sql
similarity index 85%
rename from db/changes/10491-august/ticket_closeByTicket.sql
rename to db/changes/10491-august/00-ticket_closeByTicket.sql
index 25b04f6296..f378b1146c 100644
--- a/db/changes/10491-august/ticket_closeByTicket.sql
+++ b/db/changes/10491-august/00-ticket_closeByTicket.sql
@@ -1,7 +1,9 @@
 drop procedure `vn`.`ticket_closeByTicket`;
 
+DELIMITER $$
+$$
 create
-    definer = root@localhost procedure `vn`.`ticket_closeByTicket`(IN vTicketFk int)
+    definer = `root`@`localhost` procedure `vn`.`ticket_closeByTicket`(IN vTicketFk int)
 BEGIN
 
 /**
@@ -27,5 +29,7 @@ BEGIN
 	CALL ticket_close();
 
     DROP TEMPORARY TABLE tmp.ticket_close;
-END;
+END$$
+DELIMITER ;
+
 
diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql
index 7e59c1a54a..5b769e2851 100644
--- a/db/dump/fixtures.sql
+++ b/db/dump/fixtures.sql
@@ -1380,13 +1380,6 @@ INSERT INTO `vn`.`entry`(`id`, `supplierFk`, `created`, `travelFk`, `isConfirmed
         (7, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 7, 0, 442, 'Movement 7', 0, 0, 'this is the note seven',  'observation seven'),
         (8, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 7, 0, 442, 'Movement 8', 1, 1, '',  '');
 
-INSERT INTO `vn`.`claimRatio`(`clientFk`, `yearSale`, `claimAmount`, `claimingRate`, `priceIncreasing`, `packingRate`)
-    VALUES
-        (1101, 500,  NULL,   0.00, 0.00, 1.00),
-        (1102, 1000, 2.00,   0.01, 0.05, 1.00),
-        (1103, 2000, 0.00,   0.00, 0.02, 1.00),
-        (1104, 2500, 150.00, 0.02, 0.10, 1.00);
-
 INSERT INTO `bs`.`waste`(`buyer`, `year`, `week`, `family`, `itemFk`, `itemTypeFk`, `saleTotal`, `saleWaste`, `rate`)
     VALUES
         ('CharlesXavier',        YEAR(DATE_ADD(util.VN_CURDATE(), INTERVAL -1 WEEK)),   WEEK(DATE_ADD(util.VN_CURDATE(), INTERVAL -1 WEEK), 1),     'Carnation',                    1, 1, '1062',     '51',   '4.8'),
@@ -1743,12 +1736,12 @@ INSERT INTO `vn`.`claimState`(`id`, `code`, `description`, `roleFk`, `priority`,
         ( 6, 'mana',        'Mana',        1,   4,  0),
         ( 7, 'lack',        'Faltas',      1,   2,  0);
 
-INSERT INTO `vn`.`claim`(`id`, `ticketCreated`, `claimStateFk`, `clientFk`, `workerFk`, `responsibility`, `isChargedToMana`, `created`, `packages`)
+INSERT INTO `vn`.`claim`(`id`, `ticketCreated`, `claimStateFk`, `clientFk`, `workerFk`, `responsibility`, `isChargedToMana`, `created`, `packages`, `rma`)
     VALUES
-        (1, util.VN_CURDATE(), 1,   1101, 18, 3, 0, util.VN_CURDATE(), 0),
-        (2, util.VN_CURDATE(), 2,   1101, 18, 3, 0, util.VN_CURDATE(), 1),
-        (3, util.VN_CURDATE(), 3, 1101, 18, 1, 1, util.VN_CURDATE(), 5),
-        (4, util.VN_CURDATE(), 3,  1104, 18, 5, 0, util.VN_CURDATE(), 10);
+        (1, util.VN_CURDATE(), 1,   1101, 18, 3, 0, util.VN_CURDATE(), 0, '02676A049183'),
+        (2, util.VN_CURDATE(), 2,   1101, 18, 3, 0, util.VN_CURDATE(), 1, NULL),
+        (3, util.VN_CURDATE(), 3, 1101, 18, 1, 1, util.VN_CURDATE(), 5, NULL),
+        (4, util.VN_CURDATE(), 3,  1104, 18, 5, 0, util.VN_CURDATE(), 10, NULL);
 
 INSERT INTO `vn`.`claimObservation` (`claimFk`, `workerFk`, `text`, `created`)
     VALUES
@@ -1790,6 +1783,23 @@ INSERT INTO `vn`.`claimConfig`(`id`, `pickupContact`, `maxResponsibility`)
         (1, 'Contact description', 50),
         (2, 'Contact description', 30);
 
+INSERT INTO `vn`.`claimRatio`(`clientFk`, `yearSale`, `claimAmount`, `claimingRate`, `priceIncreasing`, `packingRate`)
+    VALUES
+        (1101, 500,  NULL,   0.00, 0.00, 1.00),
+        (1102, 1000, 2.00,   0.01, 0.05, 1.00),
+        (1103, 2000, 0.00,   0.00, 0.02, 1.00),
+        (1104, 2500, 150.00, 0.02, 0.10, 1.00);
+
+INSERT INTO vn.claimRma (`id`, `code`, `created`, `workerFk`)
+VALUES 
+        (1, '02676A049183', DEFAULT, 1106),
+        (2, '02676A049183', DEFAULT, 1106),
+        (3, '02676A049183', DEFAULT, 1107),
+        (4, '02676A049183', DEFAULT, 1107),
+        (5, '01837B023653', DEFAULT, 1106);
+
+
+
 INSERT INTO `hedera`.`tpvMerchant`(`id`, `description`, `companyFk`, `bankFk`, `secretKey`)
     VALUES
         (1, 'Arkham Bank',  442, 1, 'h12387193H10238'),
diff --git a/modules/claim/back/models/claim-rma.js b/modules/claim/back/models/claim-rma.js
new file mode 100644
index 0000000000..6a93613bde
--- /dev/null
+++ b/modules/claim/back/models/claim-rma.js
@@ -0,0 +1,9 @@
+const LoopBackContext = require('loopback-context');
+
+module.exports = Self => {
+    Self.observe('before save', async function(ctx) {
+        const changes = ctx.data || ctx.instance;
+        const loopBackContext = LoopBackContext.getCurrentContext();
+        changes.workerFk = loopBackContext.active.accessToken.userId;
+    });
+};
diff --git a/modules/claim/back/models/claim-rma.json b/modules/claim/back/models/claim-rma.json
index 24c17a2346..e3849422c2 100644
--- a/modules/claim/back/models/claim-rma.json
+++ b/modules/claim/back/models/claim-rma.json
@@ -23,7 +23,7 @@
     "relations": {
         "worker": {
             "type": "belongsTo",
-            "model": "worker",
+            "model": "Worker",
             "foreignKey": "workerFk"
         }
     }

From 79485236853b1f22220a94fd487da4f2a5a84bd4 Mon Sep 17 00:00:00 2001
From: alexandre <alexandre@verdnatura.es>
Date: Tue, 25 Oct 2022 15:03:09 +0200
Subject: [PATCH 116/151] refs #4650 cambios en la query

---
 .../reports/delivery-note/delivery-note.html  | 579 +++++++++---------
 .../reports/delivery-note/delivery-note.js    |   6 +-
 .../reports/delivery-note/sql/ticket.sql      |  10 +-
 3 files changed, 300 insertions(+), 295 deletions(-)

diff --git a/print/templates/reports/delivery-note/delivery-note.html b/print/templates/reports/delivery-note/delivery-note.html
index e34620591d..a07c851aa7 100644
--- a/print/templates/reports/delivery-note/delivery-note.html
+++ b/print/templates/reports/delivery-note/delivery-note.html
@@ -1,299 +1,304 @@
 <!DOCTYPE html>
 <html v-bind:lang="$i18n.locale">
-    <body>
-        <table class="grid">
-            <tbody>
-                <tr>
-                    <td>
-                        <!-- Header block -->
-                        <report-header v-bind="$props"
-                            v-bind:company-code="ticket.companyCode">
-                        </report-header>
-                        <!-- Block -->
-                        <div class="grid-row">
-                            <div class="grid-block">
-                                <div class="columns">
-                                    <div class="size50">
-                                        <div class="size75 vn-mt-ml">
-                                            <h1 class="title uppercase">{{$t(deliverNoteType)}}</h1>
-                                            <table class="row-oriented ticket-info">
-                                                <tbody>
-                                                    <tr>
-                                                        <td class="font gray uppercase">{{$t('clientId')}}</td>
-                                                        <th>{{client.id}}</th>
-                                                    </tr>
-                                                    <tr>
-                                                        <td class="font gray uppercase">{{$t(deliverNoteType)}}</td>
-                                                        <th>{{ticket.id}}</th>
-                                                    </tr>
-                                                    <tr>
-                                                        <td class="font gray uppercase">{{$t('date')}}</td>
-                                                        <th>{{ticket.shipped | date('%d-%m-%Y')}}</th>
-                                                    </tr>
-                                                    <tr>
-                                                        <td class="font gray uppercase">{{$t('packages')}}</td>
-                                                        <th>{{ticket.packages}}</th>
-                                                    </tr>
-                                                </tbody>
-                                            </table>
-                                        </div>
-                                    </div>
-                                    <div class="size50">
-                                        <div class="panel">
-                                            <div class="header">{{$t('deliveryAddress')}}</div>
-                                            <div class="body">
-                                                <h3 class="uppercase">{{address.nickname}}</h3>
-                                                <div>
-                                                    {{address.street}}
-                                                </div>
-                                                <div>
-                                                    {{address.postalCode}}, {{address.city}} ({{address.province}})
-                                                </div>
-                                            </div>
-                                        </div>
-                
-                                        <div class="panel">
-                                            <div class="header">{{$t('fiscalData')}}</div>
-                                            <div class="body">
-                                                <div>
-                                                    {{client.socialName}}
-                                                </div>
-                                                <div>
-                                                    {{client.street}}
-                                                </div>
-                                                <div>
-                                                    {{client.fi}}
-                                                </div>
-                                            </div>
-                                        </div>
-                                    </div>
-                                </div>
-                
-                                <!-- Sales block -->
-                                <h2>{{$t('saleLines')}}</h2>
-                                <table class="column-oriented">
-                                    <thead>
-                                        <tr>
-                                            <th width="5%">{{$t('reference')}}</th>
-                                            <th class="number">{{$t('quantity')}}</th>
-                                            <th width="50%">{{$t('concept')}}</th>
-                                            <th class="number" v-if="showPrices">{{$t('price')}}</th>
-                                            <th class="centered" width="5%" v-if="showPrices">{{$t('discount')}}</th>
-                                            <th class="centered" v-if="showPrices">{{$t('vat')}}</th>
-                                            <th class="number" v-if="showPrices">{{$t('amount')}}</th>
-                                        </tr>
-                                    </thead>
-                                    <tbody v-for="sale in sales" class="no-page-break">
-                                        <tr>
-                                            <td width="5%">{{sale.itemFk | zerofill('000000')}}</td>
-                                            <td class="number">{{sale.quantity}}</td>
-                                            <td width="50%">{{sale.concept}}</td>
-                                            <td class="number" v-if="showPrices">{{sale.price | currency('EUR', $i18n.locale)}}</td>
-                                            <td class="centered" width="5%" v-if="showPrices">{{(sale.discount / 100) | percentage}}</td>
-                                            <td class="centered" v-if="showPrices">{{sale.vatType}}</td>
-                                            <td class="number" v-if="showPrices">{{sale.price * sale.quantity * (1 - sale.discount / 100) | currency('EUR', $i18n.locale)}}</td>
-                                        </tr>
-                                        <tr class="description font light-gray">
-                                            <td colspan="7">
-                                                <span v-if="sale.value5">
-                                                    <strong>{{sale.tag5}}</strong> {{sale.value5}}
-                                                </span> 
-                                                <span v-if="sale.value6">
-                                                    <strong>{{sale.tag6}}</strong> {{sale.value6}}
-                                                </span> 
-                                                <span v-if="sale.value7">
-                                                    <strong>{{sale.tag7}}</strong> {{sale.value7}}
-                                                </span> 
-                                            </td>
-                                        </tr>
-                                    </tbody>
-                                    <tfoot v-if="showPrices">
-                                        <tr>
-                                            <td colspan="6" class="font bold">
-                                                <span class="pull-right">{{$t('subtotal')}}</span>
-                                            </td>
-                                            <td class="number">{{getSubTotal() | currency('EUR', $i18n.locale)}}</td>
-                                        </tr>
-                                    </tfoot>
-                                </table>
-                                <!-- End of sales block -->
-                
-                                <div class="columns vn-mb-ml">
-                                    <!-- Services block-->
-                                    <div class="size100 no-page-break" v-if="services.length > 0">
-                                        <h2>{{$t('services.title')}}</h2>
-                                        <table class="column-oriented">
-                                            <thead>
-                                                <tr>
-                                                    <th width="5%"></th>
-                                                    <th class="number">{{$t('services.theader.quantity')}}</th>
-                                                    <th width="50%">{{$t('services.theader.concept')}}</th>
-                                                    <th class="number">{{$t('services.theader.price')}}</th>
-                                                    <th class="centered" width="5%"></th>
-                                                    <th class="centered">{{$t('services.theader.vat')}}</th>
-                                                    <th class="number">{{$t('services.theader.amount')}}</th>
-                                                </tr>
-                                            </thead>
-                                            <tbody>
-                                                <tr v-for="service in services">
-                                                    <td width="5%"></td>
-                                                    <td class="number">{{service.quantity}}</td>
-                                                    <td width="50%">{{service.description}}</td>
-                                                    <td class="number">{{service.price | currency('EUR', $i18n.locale)}}</td>
-                                                    <td class="centered" width="5%"></td>
-                                                    <td class="centered">{{service.taxDescription}}</td>
-                                                    <td class="number">{{service.price | currency('EUR', $i18n.locale)}}</td>
-                                                </tr>
-                                            </tbody>
-                                            <tfoot>
-                                                <tr>
-                                                    <td colspan="6" class="font bold">
-                                                        <span class="pull-right">{{$t('services.tfoot.subtotal')}}</span>
-                                                    </td>
-                                                    <td class="number">{{serviceTotal | currency('EUR', $i18n.locale)}}</td>
-                                                </tr>
-                                            </tfoot>
-                                        </table>
-                                        <span class="font gray">* {{ $t('services.warning') }}</span>
-                                    </div>
-                                    <!-- End of services block -->
-                                </div>
-                                <div class="columns">
-                                    <!-- Packages block -->
-                                    <div id="packagings" class="size100 no-page-break" v-if="packagings.length > 0">
-                                        <h2>{{$t('packagings.title')}}</h2>
-                                        <table class="column-oriented">
-                                            <thead>
-                                                <tr>
-                                                    <th>{{$t('packagings.theader.reference')}}</th>
-                                                    <th class="number">{{$t('packagings.theader.quantity')}}</th>
-                                                    <th wihth="75%">{{$t('packagings.theader.concept')}}</th>
-                                                </tr>
-                                            </thead>
-                                            <tbody>
-                                                <tr v-for="packaging in packagings">
-                                                    <td>{{packaging.itemFk | zerofill('000000')}}</td>
-                                                    <td class="number">{{packaging.quantity}}</td>
-                                                    <td width="85%">{{packaging.name}}</td>
-                                                </tr>
-                                            </tbody>
-                                        </table>
-                                    </div>
-                                    <!-- End of packages block -->
-                                </div>
-                                <div class="columns vn-mt-xl" v-if="showPrices">
-                                    <!-- Taxes block -->
-                                    <div id="taxes" class="size50 pull-right no-page-break" v-if="taxes">
-                                        <table class="column-oriented">
-                                            <thead>
-                                                <tr>
-                                                    <th colspan="4">{{$t('taxes.title')}}</th>
-                                                </tr>
-                                            </thead>
-                                            <thead class="light">
-                                                <tr>
-                                                    <th width="45%">{{$t('taxes.theader.type')}}</th>
-                                                    <th width="25%" class="number">{{$t('taxes.theader.taxBase')}}</th>
-                                                    <th>{{$t('taxes.theader.tax')}}</th>
-                                                    <th class="number">{{$t('taxes.theader.fee')}}</th>
-                                                </tr>
-                                            </thead>
-                                            <tbody>
-                                                <tr v-for="tax in taxes">
-                                                    <td width="45%">{{tax.name}}</td>
-                                                    <td width="25%" class="number">
-                                                        {{tax.Base | currency('EUR', $i18n.locale)}}
-                                                    </td>
-                                                    <td>{{tax.vatPercent | percentage}}</td>
-                                                    <td class="number">{{tax.tax | currency('EUR', $i18n.locale)}}</td>
-                                                </tr>
-                                            </tbody>
-                                            <tfoot>
-                                                <tr class="font bold">
-                                                    <td width="45%">{{$t('subtotal')}}</td>
-                                                    <td width="20%" class="number">
-                                                        {{getTotalBase() | currency('EUR', $i18n.locale)}}
-                                                    </td>
-                                                    <td></td>
-                                                    <td class="number">{{getTotalTax()| currency('EUR', $i18n.locale)}}</td>
-                                                </tr>
-                                                <tr class="font bold">
-                                                    <td colspan="2">{{$t('total')}}</td>
-                                                    <td colspan="2" class="number">{{getTotal() | currency('EUR', $i18n.locale)}}</td>
-                                                </tr>
-                                            </tfoot>
-                                        </table>
-                                    </div>
-                                    <!-- End of taxes block -->
 
-                                    <!-- Phytosanitary block -->
-                                    <div id="phytosanitary" class="size50 pull-left no-page-break">
-                                        <div class="panel">
-                                            <div class="body">
-                                                <div class="flag">
-                                                    <div class="columns">
-                                                        <div class="size25">
-                                                            <img v-bind:src="getReportSrc('europe.png')"/>
-                                                        </div>
-                                                        <div class="size75 flag-text">
-                                                            <strong>{{$t('plantPassport')}}</strong><br/>
-                                                        </div>
-                                                    </div>
-                                                </div>
-                                                <div class="phytosanitary-info">
-                                                    <div>
-                                                        <strong>A</strong> 
-                                                        <span>{{getBotanical()}}</span>
-                                                    </div>
-                                                    <div>
-                                                        <strong>B</strong> 
-                                                        <span>ES17462130</span>                                                        
-                                                    </div>
-                                                    <div>
-                                                        <strong>C</strong> 
-                                                        <span>{{ticket.id}}</span>                                                        
-                                                    </div>
-                                                    <div>
-                                                        <strong>D</strong>
-                                                        <span>ES</span>
-                                                    </div>
-                                                </div>
-                                            </div>
-                                        </div>
+<body>
+    <table class="grid">
+        <tbody>
+            <tr>
+                <td>
+                    <!-- Header block -->
+                    <report-header v-bind="$props" v-bind:company-code="ticket.companyCode">
+                    </report-header>
+                    <!-- Block -->
+                    <div class="grid-row">
+                        <div class="grid-block">
+                            <div class="columns">
+                                <div class="size50">
+                                    <div class="size75 vn-mt-ml">
+                                        <h1 class="title uppercase">{{$t(deliverNoteType)}}</h1>
+                                        <table class="row-oriented ticket-info">
+                                            <tbody>
+                                                <tr>
+                                                    <td class="font gray uppercase">{{$t('clientId')}}</td>
+                                                    <th>{{client.id}}</th>
+                                                </tr>
+                                                <tr>
+                                                    <td class="font gray uppercase">{{$t(deliverNoteType)}}</td>
+                                                    <th>{{ticket.id}}</th>
+                                                </tr>
+                                                <tr>
+                                                    <td class="font gray uppercase">{{$t('date')}}</td>
+                                                    <th>{{ticket.shipped | date('%d-%m-%Y')}}</th>
+                                                </tr>
+                                                <tr>
+                                                    <td class="font gray uppercase">{{$t('packages')}}</td>
+                                                    <th>{{ticket.packages}}</th>
+                                                </tr>
+                                            </tbody>
+                                        </table>
                                     </div>
-                                    <!-- End of phytosanitary block -->
                                 </div>
-                                <div class="columns vn-mb-ml">
-                                    <!-- Observations block-->
-                                    <div class="size100 no-page-break" v-if="hasObservations">
-                                        <h2>{{$t('observations')}}</h2>
-                                        <p class="observations">{{ticket.description}}</p>
-                                    </div>
-                                <div class="columns">
-                                    <!-- Signature block -->
-                                    <div class="size50 pull-left no-page-break">
-                                        <div id="signature" class="panel" v-if="signature && signature.id">
-                                            <div class="header">{{$t('digitalSignature')}}</div>
-                                            <div class="body centered">
-                                                <img v-bind:src="dmsPath"/>
-                                                <div>{{signature.created | date('%d-%m-%Y')}}</div>
+                                <div class="size50">
+                                    <div class="panel">
+                                        <div class="header">{{$t('deliveryAddress')}}</div>
+                                        <div class="body">
+                                            <h3 class="uppercase">{{address.nickname}}</h3>
+                                            <div>
+                                                {{address.street}}
+                                            </div>
+                                            <div>
+                                                {{address.postalCode}}, {{address.city}} ({{address.province}})
                                             </div>
                                         </div>
                                     </div>
-                                    <!-- End of signature block -->
+
+                                    <div class="panel">
+                                        <div class="header">{{$t('fiscalData')}}</div>
+                                        <div class="body">
+                                            <div>
+                                                {{client.socialName}}
+                                            </div>
+                                            <div>
+                                                {{client.street}}
+                                            </div>
+                                            <div>
+                                                {{client.fi}}
+                                            </div>
+                                        </div>
+                                    </div>
+                                </div>
+                            </div>
+
+                            <!-- Sales block -->
+                            <h2>{{$t('saleLines')}}</h2>
+                            <table class="column-oriented">
+                                <thead>
+                                    <tr>
+                                        <th width="5%">{{$t('reference')}}</th>
+                                        <th class="number">{{$t('quantity')}}</th>
+                                        <th width="50%">{{$t('concept')}}</th>
+                                        <th class="number" v-if="showPrices">{{$t('price')}}</th>
+                                        <th class="centered" width="5%" v-if="showPrices">{{$t('discount')}}</th>
+                                        <th class="centered" v-if="showPrices">{{$t('vat')}}</th>
+                                        <th class="number" v-if="showPrices">{{$t('amount')}}</th>
+                                    </tr>
+                                </thead>
+                                <tbody v-for="sale in sales" class="no-page-break">
+                                    <tr>
+                                        <td width="5%">{{sale.itemFk | zerofill('000000')}}</td>
+                                        <td class="number">{{sale.quantity}}</td>
+                                        <td width="50%">{{sale.concept}}</td>
+                                        <td class="number" v-if="showPrices">{{sale.price | currency('EUR',
+                                            $i18n.locale)}}</td>
+                                        <td class="centered" width="5%" v-if="showPrices">{{(sale.discount / 100) |
+                                            percentage}}</td>
+                                        <td class="centered" v-if="showPrices">{{sale.vatType}}</td>
+                                        <td class="number" v-if="showPrices">{{sale.price * sale.quantity * (1 -
+                                            sale.discount / 100) | currency('EUR', $i18n.locale)}}</td>
+                                    </tr>
+                                    <tr class="description font light-gray">
+                                        <td colspan="7">
+                                            <span v-if="sale.value5">
+                                                <strong>{{sale.tag5}}</strong> {{sale.value5}}
+                                            </span>
+                                            <span v-if="sale.value6">
+                                                <strong>{{sale.tag6}}</strong> {{sale.value6}}
+                                            </span>
+                                            <span v-if="sale.value7">
+                                                <strong>{{sale.tag7}}</strong> {{sale.value7}}
+                                            </span>
+                                        </td>
+                                    </tr>
+                                </tbody>
+                                <tfoot v-if="showPrices">
+                                    <tr>
+                                        <td colspan="6" class="font bold">
+                                            <span class="pull-right">{{$t('subtotal')}}</span>
+                                        </td>
+                                        <td class="number">{{getSubTotal() | currency('EUR', $i18n.locale)}}</td>
+                                    </tr>
+                                </tfoot>
+                            </table>
+                            <!-- End of sales block -->
+
+                            <div class="columns vn-mb-ml">
+                                <!-- Services block-->
+                                <div class="size100 no-page-break" v-if="services.length > 0">
+                                    <h2>{{$t('services.title')}}</h2>
+                                    <table class="column-oriented">
+                                        <thead>
+                                            <tr>
+                                                <th width="5%"></th>
+                                                <th class="number">{{$t('services.theader.quantity')}}</th>
+                                                <th width="50%">{{$t('services.theader.concept')}}</th>
+                                                <th class="number">{{$t('services.theader.price')}}</th>
+                                                <th class="centered" width="5%"></th>
+                                                <th class="centered">{{$t('services.theader.vat')}}</th>
+                                                <th class="number">{{$t('services.theader.amount')}}</th>
+                                            </tr>
+                                        </thead>
+                                        <tbody>
+                                            <tr v-for="service in services">
+                                                <td width="5%"></td>
+                                                <td class="number">{{service.quantity}}</td>
+                                                <td width="50%">{{service.description}}</td>
+                                                <td class="number">{{service.price | currency('EUR', $i18n.locale)}}
+                                                </td>
+                                                <td class="centered" width="5%"></td>
+                                                <td class="centered">{{service.taxDescription}}</td>
+                                                <td class="number">{{service.price | currency('EUR', $i18n.locale)}}
+                                                </td>
+                                            </tr>
+                                        </tbody>
+                                        <tfoot>
+                                            <tr>
+                                                <td colspan="6" class="font bold">
+                                                    <span class="pull-right">{{$t('services.tfoot.subtotal')}}</span>
+                                                </td>
+                                                <td class="number">{{serviceTotal | currency('EUR', $i18n.locale)}}</td>
+                                            </tr>
+                                        </tfoot>
+                                    </table>
+                                    <span class="font gray">* {{ $t('services.warning') }}</span>
+                                </div>
+                                <!-- End of services block -->
+                            </div>
+                            <div class="columns">
+                                <!-- Packages block -->
+                                <div id="packagings" class="size100 no-page-break" v-if="packagings.length > 0">
+                                    <h2>{{$t('packagings.title')}}</h2>
+                                    <table class="column-oriented">
+                                        <thead>
+                                            <tr>
+                                                <th>{{$t('packagings.theader.reference')}}</th>
+                                                <th class="number">{{$t('packagings.theader.quantity')}}</th>
+                                                <th wihth="75%">{{$t('packagings.theader.concept')}}</th>
+                                            </tr>
+                                        </thead>
+                                        <tbody>
+                                            <tr v-for="packaging in packagings">
+                                                <td>{{packaging.itemFk | zerofill('000000')}}</td>
+                                                <td class="number">{{packaging.quantity}}</td>
+                                                <td width="85%">{{packaging.name}}</td>
+                                            </tr>
+                                        </tbody>
+                                    </table>
+                                </div>
+                                <!-- End of packages block -->
+                            </div>
+                            <div class="columns vn-mt-xl" v-if="showPrices">
+                                <!-- Taxes block -->
+                                <div id="taxes" class="size50 pull-right no-page-break" v-if="taxes">
+                                    <table class="column-oriented">
+                                        <thead>
+                                            <tr>
+                                                <th colspan="4">{{$t('taxes.title')}}</th>
+                                            </tr>
+                                        </thead>
+                                        <thead class="light">
+                                            <tr>
+                                                <th width="45%">{{$t('taxes.theader.type')}}</th>
+                                                <th width="25%" class="number">{{$t('taxes.theader.taxBase')}}</th>
+                                                <th>{{$t('taxes.theader.tax')}}</th>
+                                                <th class="number">{{$t('taxes.theader.fee')}}</th>
+                                            </tr>
+                                        </thead>
+                                        <tbody>
+                                            <tr v-for="tax in taxes">
+                                                <td width="45%">{{tax.name}}</td>
+                                                <td width="25%" class="number">
+                                                    {{tax.Base | currency('EUR', $i18n.locale)}}
+                                                </td>
+                                                <td>{{tax.vatPercent | percentage}}</td>
+                                                <td class="number">{{tax.tax | currency('EUR', $i18n.locale)}}</td>
+                                            </tr>
+                                        </tbody>
+                                        <tfoot>
+                                            <tr class="font bold">
+                                                <td width="45%">{{$t('subtotal')}}</td>
+                                                <td width="20%" class="number">
+                                                    {{getTotalBase() | currency('EUR', $i18n.locale)}}
+                                                </td>
+                                                <td></td>
+                                                <td class="number">{{getTotalTax()| currency('EUR', $i18n.locale)}}</td>
+                                            </tr>
+                                            <tr class="font bold">
+                                                <td colspan="2">{{$t('total')}}</td>
+                                                <td colspan="2" class="number">{{getTotal() | currency('EUR',
+                                                    $i18n.locale)}}</td>
+                                            </tr>
+                                        </tfoot>
+                                    </table>
+                                </div>
+                                <!-- End of taxes block -->
+
+                                <!-- Phytosanitary block -->
+                                <div id="phytosanitary" class="size50 pull-left no-page-break">
+                                    <div class="panel">
+                                        <div class="body">
+                                            <div class="flag">
+                                                <div class="columns">
+                                                    <div class="size25">
+                                                        <img v-bind:src="getReportSrc('europe.png')" />
+                                                    </div>
+                                                    <div class="size75 flag-text">
+                                                        <strong>{{$t('plantPassport')}}</strong><br />
+                                                    </div>
+                                                </div>
+                                            </div>
+                                            <div class="phytosanitary-info">
+                                                <div>
+                                                    <strong>A</strong>
+                                                    <span>{{getBotanical()}}</span>
+                                                </div>
+                                                <div>
+                                                    <strong>B</strong>
+                                                    <span>ES17462130</span>
+                                                </div>
+                                                <div>
+                                                    <strong>C</strong>
+                                                    <span>{{ticket.id}}</span>
+                                                </div>
+                                                <div>
+                                                    <strong>D</strong>
+                                                    <span>ES</span>
+                                                </div>
+                                            </div>
+                                        </div>
+                                    </div>
+                                </div>
+                                <!-- End of phytosanitary block -->
+                            </div>
+                            <div class="columns">
+                                <!-- Signature block -->
+                                <div class="size50 pull-left no-page-break">
+                                    <div id="signature" class="panel" v-if="signature && signature.id">
+                                        <div class="header">{{$t('digitalSignature')}}</div>
+                                        <div class="body centered">
+                                            <img v-bind:src="dmsPath" />
+                                            <div>{{signature.created | date('%d-%m-%Y')}}</div>
+                                        </div>
+                                    </div>
+                                </div>
+                                <!-- End of signature block -->
+                            </div>
+                            <div class="columns vn-mb-ml" v-if="hasObservations">
+                                <!-- Observations block-->
+                                <div class="size100 no-page-break">
+                                    <h2>{{$t('observations')}}</h2>
+                                    <p class="observations">{{ticket.description}}</p>
                                 </div>
                             </div>
                         </div>
-                        <!-- Footer block -->
-                        <report-footer id="pageFooter"
-                            v-bind:company-code="ticket.companyCode"
-                            v-bind:left-text="footerType"
-                            v-bind:center-text="client.socialName"
-                            v-bind="$props">
-                        </report-footer>
-                    </td>
-                </tr>
-            </tbody>
-        </table>
-    </body>
+                    </div>
+                    <!-- Footer block -->
+                    <report-footer id="pageFooter" v-bind:company-code="ticket.companyCode"
+                        v-bind:left-text="footerType" v-bind:center-text="client.socialName" v-bind="$props">
+                    </report-footer>
+                </td>
+            </tr>
+        </tbody>
+    </table>
+</body>
+
 </html>
\ No newline at end of file
diff --git a/print/templates/reports/delivery-note/delivery-note.js b/print/templates/reports/delivery-note/delivery-note.js
index 78f0f7662b..2e356f62e6 100755
--- a/print/templates/reports/delivery-note/delivery-note.js
+++ b/print/templates/reports/delivery-note/delivery-note.js
@@ -54,6 +54,9 @@ module.exports = {
         footerType() {
             const translatedType = this.$t(this.deliverNoteType);
             return `${translatedType} ${this.id}`;
+        },
+        hasObservations() {
+            return this.ticket.description !== null;
         }
         
     },
@@ -120,9 +123,6 @@ module.exports = {
             return phytosanitary.filter((item, index) =>
                 phytosanitary.indexOf(item) == index
             ).join(', ');
-        },
-        hasObservations() {
-            return this.ticket.code == 'deliveryNote' && this.ticket.description != null;
         }
     },
     components: {
diff --git a/print/templates/reports/delivery-note/sql/ticket.sql b/print/templates/reports/delivery-note/sql/ticket.sql
index 3d16b53d85..9eac2d322b 100644
--- a/print/templates/reports/delivery-note/sql/ticket.sql
+++ b/print/templates/reports/delivery-note/sql/ticket.sql
@@ -3,10 +3,10 @@ SELECT
     t.shipped,
     c.code companyCode,
     t.packages,
-    tto.description,
-    ot.code 
+    tto.description
 FROM ticket t
     JOIN company c ON c.id = t.companyFk
-    LEFT JOIN ticketObservation tto ON tto.ticketFk = t.id
-    LEFT JOIN observationType ot ON tto.observationTypeFk = ot.id 
-WHERE t.id = 1;
\ No newline at end of file
+    LEFT JOIN ticketObservation tto
+    	ON tto.ticketFk = t.id
+    		AND tto.observationTypeFk = (SELECT id FROM observationType WHERE code = 'deliveryNote')
+WHERE t.id = ?
\ No newline at end of file

From f07f0679d8d58656aabd60d2cb1875a20994a939 Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Tue, 25 Oct 2022 15:03:20 +0200
Subject: [PATCH 117/151] fix fixture

---
 db/dump/fixtures.sql | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql
index 8e11137814..2e00389e5b 100644
--- a/db/dump/fixtures.sql
+++ b/db/dump/fixtures.sql
@@ -349,7 +349,7 @@ INSERT INTO `vn`.`clientManaCache`(`clientFk`, `mana`, `dated`)
 
 INSERT INTO `vn`.`clientConfig`(`riskTolerance`, `maxCreditRows`)
     VALUES
-        (200, null);
+        (200, 10);
 
 INSERT INTO `vn`.`address`(`id`, `nickname`, `street`, `city`, `postalCode`, `provinceFk`, `phone`, `mobile`, `isActive`, `clientFk`, `agencyModeFk`, `longitude`, `latitude`, `isEqualizated`, `isDefaultAddress`)
     VALUES

From 07a18dc736048fd3f6304daa80a9ef0fcf985e0c Mon Sep 17 00:00:00 2001
From: vicent <vicent@verdnatura.es>
Date: Wed, 26 Oct 2022 08:05:11 +0200
Subject: [PATCH 118/151] delete sql

---
 db/changes/10491-august/00-itemType.sql | 5 -----
 1 file changed, 5 deletions(-)
 delete mode 100644 db/changes/10491-august/00-itemType.sql

diff --git a/db/changes/10491-august/00-itemType.sql b/db/changes/10491-august/00-itemType.sql
deleted file mode 100644
index d201acf370..0000000000
--- a/db/changes/10491-august/00-itemType.sql
+++ /dev/null
@@ -1,5 +0,0 @@
-ALTER TABLE `vn`.`itemType` CHANGE `transaction` transaction__ tinyint(4) DEFAULT 0 NOT NULL;
-ALTER TABLE `vn`.`itemType` CHANGE location location__ varchar(10) CHARACTER SET utf8mb3 COLLATE utf8mb3_unicode_ci DEFAULT NULL NULL;
-ALTER TABLE `vn`.`itemType` CHANGE hasComponents hasComponents__ tinyint(1) DEFAULT 1 NOT NULL;
-ALTER TABLE `vn`.`itemType` CHANGE warehouseFk warehouseFk__ smallint(6) unsigned DEFAULT 60 NOT NULL;
-ALTER TABLE `vn`.`itemType` CHANGE compression compression__ decimal(5,2) DEFAULT 1.00 NULL;
\ No newline at end of file

From 925565d3d24037bb53d209823db0b5cef12bc83c Mon Sep 17 00:00:00 2001
From: vicent <vicent@verdnatura.es>
Date: Wed, 26 Oct 2022 08:23:36 +0200
Subject: [PATCH 119/151] =?UTF-8?q?refator:=20borrada=20variable=20global?=
 =?UTF-8?q?=20y=20a=C3=B1adida=20Promesa=20al=20array?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 modules/ticket/back/methods/ticket/updateDiscount.js | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/modules/ticket/back/methods/ticket/updateDiscount.js b/modules/ticket/back/methods/ticket/updateDiscount.js
index 7e7c4e06d0..a60d732b14 100644
--- a/modules/ticket/back/methods/ticket/updateDiscount.js
+++ b/modules/ticket/back/methods/ticket/updateDiscount.js
@@ -133,20 +133,20 @@ module.exports = Self => {
                     }
                 }, myOptions);
 
-                let newComponent;
+                let deletedComponent;
                 if (oldComponent) {
                     const filter = {
                         saleFk: sale.id,
                         componentFk: oldComponent.componentFk
                     };
-                    await models.SaleComponent.destroyAll(filter, myOptions);
+                    deletedComponent = await models.SaleComponent.destroyAll(filter, myOptions);
                 }
 
-                await createSaleComponent(sale.id, value, componentId, myOptions);
+                const newComponent = await createSaleComponent(sale.id, value, componentId, myOptions);
 
                 const updatedSale = sale.updateAttribute('discount', newDiscount, myOptions);
 
-                promises.push(newComponent, updatedSale);
+                promises.push(newComponent, updatedSale, deletedComponent);
 
                 const change = `${oldDiscount}% ➔ *${newDiscount}%*`;
                 changesMade += `\r\n-${sale.itemFk}: ${sale.concept} (${sale.quantity}) ${change}`;
@@ -193,7 +193,7 @@ module.exports = Self => {
     async function createSaleComponent(saleId, value, componentId, myOptions) {
         const models = Self.app.models;
 
-        newComponent = models.SaleComponent.create({
+        return models.SaleComponent.create({
             saleFk: saleId,
             value: value,
             componentFk: componentId

From f65d06fc7db84905be5543c7a1f7e34ebece9ce9 Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Wed, 26 Oct 2022 08:27:28 +0200
Subject: [PATCH 120/151] fixes #4073

---
 back/methods/account/privileges.js            | 26 +++++++++------
 back/methods/account/specs/privileges.spec.js | 14 ++++----
 db/changes/10490-august/00-user_hasGrant.sql  |  3 ++
 db/dump/fixtures.sql                          |  8 ++---
 e2e/paths/14-account/07_ldap.spec.js          |  9 ++++++
 e2e/paths/14-account/08_samba.spec.js         |  9 ++++++
 e2e/paths/14-account/09_privileges.spec.js    | 32 +++++++++++++++++--
 loopback/locale/en.json                       |  6 ++--
 loopback/locale/es.json                       |  6 ++--
 .../account/front/privileges/locale/es.yml    |  2 +-
 modules/client/back/models/client.js          |  9 ++++--
 11 files changed, 93 insertions(+), 31 deletions(-)

diff --git a/back/methods/account/privileges.js b/back/methods/account/privileges.js
index df421125ed..6510779f28 100644
--- a/back/methods/account/privileges.js
+++ b/back/methods/account/privileges.js
@@ -29,6 +29,8 @@ module.exports = Self => {
     });
 
     Self.privileges = async function(ctx, id, roleFk, hasGrant, options) {
+        if (!(hasGrant != null || roleFk)) return;
+
         const models = Self.app.models;
         const userId = ctx.req.accessToken.userId;
 
@@ -37,22 +39,26 @@ module.exports = Self => {
         if (typeof options == 'object')
             Object.assign(myOptions, options);
 
-        const user = await models.Account.findById(userId, null, myOptions);
+        const user = await models.Account.findById(userId, {fields: ['hasGrant']}, myOptions);
 
         if (!user.hasGrant)
-            throw new UserError(`You don't have enough privileges`);
+            throw new UserError(`You don't have grant privilege`);
 
-        const userToUpdate = await models.Account.findById(id);
+        const userToUpdate = await models.Account.findById(id, ['name', 'hasGrant', 'roleFk'], myOptions);
         if (hasGrant != null)
-            return await userToUpdate.updateAttribute('hasGrant', hasGrant, myOptions);
-        if (!roleFk) return;
+            userToUpdate.hasGrant = hasGrant;
 
-        const role = await models.Role.findById(roleFk, null, myOptions);
-        const hasRole = await models.Account.hasRole(userId, role.name, myOptions);
+        if (roleFk) {
+            const role = await models.Role.findById(roleFk, {fields: ['name']}, myOptions);
+            const hasRole = await models.Account.hasRole(userId, role.name, myOptions);
 
-        if (!hasRole)
-            throw new UserError(`You don't have enough privileges`);
+            if (!hasRole)
+                throw new UserError(`You don't own the role and you can't assign it to another user`);
 
-        await userToUpdate.updateAttribute('roleFk', roleFk, myOptions);
+            userToUpdate.roleFk = roleFk;
+        }
+
+        await userToUpdate.save(userToUpdate);
+        await models.UserAccount.sync(userToUpdate.name);
     };
 };
diff --git a/back/methods/account/specs/privileges.spec.js b/back/methods/account/specs/privileges.spec.js
index 137c086711..959130e8b9 100644
--- a/back/methods/account/specs/privileges.spec.js
+++ b/back/methods/account/specs/privileges.spec.js
@@ -4,7 +4,7 @@ describe('account privileges()', () => {
     const employeeId = 1;
     const developerId = 9;
     const sysadminId = 66;
-    const bruceWayneId = 1101;
+    const clarkKent = 1103;
 
     it('should throw an error when user not has privileges', async() => {
         const ctx = {req: {accessToken: {userId: developerId}}};
@@ -22,7 +22,7 @@ describe('account privileges()', () => {
             await tx.rollback();
         }
 
-        expect(error.message).toContain(`You don't have enough privileges`);
+        expect(error.message).toContain(`You don't have grant privilege`);
     });
 
     it('should throw an error when user has privileges but not has the role', async() => {
@@ -46,7 +46,7 @@ describe('account privileges()', () => {
             await tx.rollback();
         }
 
-        expect(error.message).toContain(`You don't have enough privileges`);
+        expect(error.message).toContain(`You don't own the role and you can't assign it to another user`);
     });
 
     it('should change role', async() => {
@@ -63,8 +63,8 @@ describe('account privileges()', () => {
         let error;
         let result;
         try {
-            await models.Account.privileges(ctx, bruceWayneId, agency.id, null, options);
-            result = await models.Account.findById(bruceWayneId, null, options);
+            await models.Account.privileges(ctx, clarkKent, agency.id, null, options);
+            result = await models.Account.findById(clarkKent, null, options);
 
             await tx.rollback();
         } catch (e) {
@@ -84,8 +84,8 @@ describe('account privileges()', () => {
         let result;
         try {
             const options = {transaction: tx};
-            await models.Account.privileges(ctx, bruceWayneId, null, true, options);
-            result = await models.Account.findById(bruceWayneId, null, options);
+            await models.Account.privileges(ctx, clarkKent, null, true, options);
+            result = await models.Account.findById(clarkKent, null, options);
 
             await tx.rollback();
         } catch (e) {
diff --git a/db/changes/10490-august/00-user_hasGrant.sql b/db/changes/10490-august/00-user_hasGrant.sql
index 60d1273d83..05a09f87ba 100644
--- a/db/changes/10490-august/00-user_hasGrant.sql
+++ b/db/changes/10490-august/00-user_hasGrant.sql
@@ -1 +1,4 @@
 ALTER TABLE `account`.`user` ADD hasGrant TINYINT(1) NOT NULL;
+
+INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalType, principalId)
+    VALUES('Account', 'privileges', '*', 'ALLOW', 'ROLE', '$authenticated');
diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql
index 7e59c1a54a..c4079adc05 100644
--- a/db/dump/fixtures.sql
+++ b/db/dump/fixtures.sql
@@ -14,10 +14,10 @@ INSERT INTO `salix`.`AccessToken` (`id`, `ttl`, `created`, `userId`)
         ('DEFAULT_TOKEN', '1209600', util.VN_CURDATE(), 66);
 
 INSERT INTO `salix`.`printConfig` (`id`, `itRecipient`, `incidencesEmail`)
-    VALUES 
+    VALUES
         (1, 'it@gotamcity.com', 'incidences@gotamcity.com');
 
-INSERT INTO `vn`.`ticketConfig` (`id`, `scopeDays`) 
+INSERT INTO `vn`.`ticketConfig` (`id`, `scopeDays`)
     VALUES
         ('1', '6');
 
@@ -45,8 +45,8 @@ INSERT INTO `account`.`roleConfig`(`id`, `mysqlPassword`, `rolePrefix`, `userPre
 
 CALL `account`.`role_sync`;
 
-INSERT INTO `account`.`user`(`id`,`name`, `nickname`, `password`,`role`,`active`,`email`, `lang`, `image`)
-    SELECT id, name, CONCAT(name, 'Nick'),MD5('nightmare'), id, 1, CONCAT(name, '@mydomain.com'), 'en', '4fa3ada0-3ac4-11eb-9ab8-27f6fc3b85fd'
+INSERT INTO `account`.`user`(`id`,`name`, `nickname`, `password`,`role`,`active`,`email`, `lang`, `image`, `bcryptPassword`)
+    SELECT id, name, CONCAT(name, 'Nick'),MD5('nightmare'), id, 1, CONCAT(name, '@mydomain.com'), 'en', '4fa3ada0-3ac4-11eb-9ab8-27f6fc3b85fd', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2'
         FROM `account`.`role` WHERE id <> 20
             ORDER BY id;
 
diff --git a/e2e/paths/14-account/07_ldap.spec.js b/e2e/paths/14-account/07_ldap.spec.js
index a3b8137d32..eb22f695c1 100644
--- a/e2e/paths/14-account/07_ldap.spec.js
+++ b/e2e/paths/14-account/07_ldap.spec.js
@@ -29,4 +29,13 @@ describe('Account LDAP path', () => {
 
         expect(message.text).toContain('Data saved!');
     });
+
+    it('should reset data', async() => {
+        await page.waitToClick(selectors.accountLdap.checkEnable);
+        await page.waitToClick(selectors.accountLdap.save);
+
+        const message = await page.waitForSnackbar();
+
+        expect(message.text).toContain('Data saved!');
+    });
 });
diff --git a/e2e/paths/14-account/08_samba.spec.js b/e2e/paths/14-account/08_samba.spec.js
index c3db026dc0..6e7ef9bbfb 100644
--- a/e2e/paths/14-account/08_samba.spec.js
+++ b/e2e/paths/14-account/08_samba.spec.js
@@ -29,4 +29,13 @@ describe('Account Samba path', () => {
 
         expect(message.text).toContain('Data saved!');
     });
+
+    it('should reset data', async() => {
+        await page.waitToClick(selectors.accountSamba.checkEnable);
+        await page.waitToClick(selectors.accountSamba.save);
+
+        const message = await page.waitForSnackbar();
+
+        expect(message.text).toContain('Data saved!');
+    });
 });
diff --git a/e2e/paths/14-account/09_privileges.spec.js b/e2e/paths/14-account/09_privileges.spec.js
index 71e9345a8c..e4b8fb24c4 100644
--- a/e2e/paths/14-account/09_privileges.spec.js
+++ b/e2e/paths/14-account/09_privileges.spec.js
@@ -24,7 +24,7 @@ describe('Account privileges path', () => {
 
             const message = await page.waitForSnackbar();
 
-            expect(message.text).toContain(`You don't have enough privileges`);
+            expect(message.text).toContain(`You don't have grant privilege`);
         });
 
         it('should throw error when change role', async() => {
@@ -33,7 +33,7 @@ describe('Account privileges path', () => {
 
             const message = await page.waitForSnackbar();
 
-            expect(message.text).toContain(`You don't have enough privileges`);
+            expect(message.text).toContain(`You don't have grant privilege`);
         });
     });
 
@@ -56,7 +56,16 @@ describe('Account privileges path', () => {
             expect(result).toBe('checked');
         });
 
-        it('should change role', async() => {
+        it('should throw error when change role and not own role', async() => {
+            await page.autocompleteSearch(selectors.accountPrivileges.role, 'itBoss');
+            await page.waitToClick(selectors.accountPrivileges.save);
+
+            const message = await page.waitForSnackbar();
+
+            expect(message.text).toContain(`You don't own the role and you can't assign it to another user`);
+        });
+
+        it('should change role to employee', async() => {
             await page.autocompleteSearch(selectors.accountPrivileges.role, 'employee');
             await page.waitToClick(selectors.accountPrivileges.save);
             const message = await page.waitForSnackbar();
@@ -67,6 +76,18 @@ describe('Account privileges path', () => {
             expect(message.text).toContain(`Data saved!`);
             expect(result).toContain('employee');
         });
+
+        it('should return role to developer', async() => {
+            await page.autocompleteSearch(selectors.accountPrivileges.role, 'developer');
+            await page.waitToClick(selectors.accountPrivileges.save);
+            const message = await page.waitForSnackbar();
+
+            await page.reloadSection('account.card.privileges');
+            const result = await page.waitToGetProperty(selectors.accountPrivileges.role, 'value');
+
+            expect(message.text).toContain(`Data saved!`);
+            expect(result).toContain('developer');
+        });
     });
 
     describe('as developer again', () => {
@@ -76,7 +97,12 @@ describe('Account privileges path', () => {
 
             await page.waitToClick(selectors.accountPrivileges.checkHasGrant);
             await page.waitToClick(selectors.accountPrivileges.save);
+            const message = await page.waitForSnackbar();
 
+            expect(message.text).toContain(`Data saved!`);
+        });
+
+        it('should logIn in developer', async() => {
             await page.reloadSection('account.card.privileges');
             const result = await page.checkboxState(selectors.accountPrivileges.checkHasGrant);
 
diff --git a/loopback/locale/en.json b/loopback/locale/en.json
index e5a0fae322..1e151294fd 100644
--- a/loopback/locale/en.json
+++ b/loopback/locale/en.json
@@ -133,5 +133,7 @@
 	"Descanso semanal 36h. / 72h.": "Weekly rest 36h. / 72h.",
 	"Password does not meet requirements": "Password does not meet requirements",
 	"You don't have privileges to change the zone": "You don't have privileges to change the zone or for these parameters there are more than one shipping options, talk to agencies",
-	"Not enough privileges to edit a client": "Not enough privileges to edit a client"
-}
\ No newline at end of file
+	"Not enough privileges to edit a client": "Not enough privileges to edit a client",
+    "You don't have grant privilege": "You don't have grant privilege",
+	"You don't own the role and you can't assign it to another user": "You don't own the role and you can't assign it to another user"
+}
diff --git a/loopback/locale/es.json b/loopback/locale/es.json
index 67370b3438..a41315dd1d 100644
--- a/loopback/locale/es.json
+++ b/loopback/locale/es.json
@@ -235,5 +235,7 @@
 	"Dirección incorrecta": "Dirección incorrecta",
 	"Modifiable user details only by an administrator": "Detalles de usuario modificables solo por un administrador",
 	"Modifiable password only via recovery or by an administrator": "Contraseña modificable solo a través de la recuperación o por un administrador",
-	"Not enough privileges to edit a client": "No tienes suficientes privilegios para editar un cliente"
-}
\ No newline at end of file
+	"Not enough privileges to edit a client": "No tienes suficientes privilegios para editar un cliente",
+    "You don't have grant privilege": "No tienes privilegios para dar privilegios",
+    "You don't own the role and you can't assign it to another user": "No eres el propietario del rol y no puedes asignarlo a otro usuario"
+}
diff --git a/modules/account/front/privileges/locale/es.yml b/modules/account/front/privileges/locale/es.yml
index f7330e1be0..17f1ef29e1 100644
--- a/modules/account/front/privileges/locale/es.yml
+++ b/modules/account/front/privileges/locale/es.yml
@@ -1,2 +1,2 @@
 Privileges: Privilegios
-Has grant: Tiene privilegios
+Has grant: Puede dar privilegios
diff --git a/modules/client/back/models/client.js b/modules/client/back/models/client.js
index 3bd89eff11..e66cdb83fb 100644
--- a/modules/client/back/models/client.js
+++ b/modules/client/back/models/client.js
@@ -425,14 +425,19 @@ module.exports = Self => {
 
         account.observe('before save', async ctx => {
             if (ctx.isNewInstance) return;
-            ctx.hookState.oldInstance = JSON.parse(JSON.stringify(ctx.currentInstance));
+            if (ctx.currentInstance)
+                ctx.hookState.oldInstance = JSON.parse(JSON.stringify(ctx.currentInstance));
         });
 
         account.observe('after save', async ctx => {
             const changes = ctx.data || ctx.instance;
             if (!ctx.isNewInstance && changes) {
                 const oldData = ctx.hookState.oldInstance;
-                const hasChanges = oldData.name != changes.name || oldData.active != changes.active;
+                let hasChanges;
+
+                if (oldData)
+                    hasChanges = oldData.name != changes.name || oldData.active != changes.active;
+
                 if (!hasChanges) return;
 
                 const isClient = await Self.app.models.Client.count({id: oldData.id});

From d4e278363009abaa45090212dc3e50a2f0430086 Mon Sep 17 00:00:00 2001
From: vicent <vicent@verdnatura.es>
Date: Wed, 26 Oct 2022 08:39:07 +0200
Subject: [PATCH 121/151] =?UTF-8?q?refactor:=20corregidas=20traducciones,?=
 =?UTF-8?q?=20eliminado=20destroyAll=20y=20a=C3=B1adida=20transacci=C3=B3n?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 loopback/locale/es.json                                |  2 +-
 .../back/methods/expedition/deleteExpeditions.js       | 10 +++++++---
 .../ticket/back/methods/expedition/moveExpeditions.js  |  4 ++--
 .../methods/expedition/specs/deleteExpeditions.spec.js |  2 +-
 modules/ticket/front/expedition/index.html             |  2 +-
 modules/ticket/front/expedition/locale/es.yml          |  2 +-
 6 files changed, 13 insertions(+), 9 deletions(-)

diff --git a/loopback/locale/es.json b/loopback/locale/es.json
index bd9de41c29..2d9bae1d83 100644
--- a/loopback/locale/es.json
+++ b/loopback/locale/es.json
@@ -236,5 +236,5 @@
 	"Modifiable user details only by an administrator": "Detalles de usuario modificables solo por un administrador",
 	"Modifiable password only via recovery or by an administrator": "Contraseña modificable solo a través de la recuperación o por un administrador",
 	"Not enough privileges to edit a client": "No tienes suficientes privilegios para editar un cliente",
-	"This route not exists": "Esta ruta no existe"
+	"This route does not exists": "Esta ruta no existe"
 }
\ No newline at end of file
diff --git a/modules/ticket/back/methods/expedition/deleteExpeditions.js b/modules/ticket/back/methods/expedition/deleteExpeditions.js
index 5b9d0daaa3..2419d3a5e8 100644
--- a/modules/ticket/back/methods/expedition/deleteExpeditions.js
+++ b/modules/ticket/back/methods/expedition/deleteExpeditions.js
@@ -33,9 +33,13 @@ module.exports = Self => {
         }
 
         try {
-            const deletedExpeditions = await models.Expedition.destroyAll({
-                id: {inq: expeditionIds}
-            }, myOptions);
+            const promises = [];
+            for (let expeditionId of expeditionIds) {
+                const deletedExpedition = models.Expedition.destroyById(expeditionId, myOptions);
+                promises.push(deletedExpedition);
+            }
+
+            const deletedExpeditions = await Promise.all(promises);
 
             if (tx) await tx.commit();
 
diff --git a/modules/ticket/back/methods/expedition/moveExpeditions.js b/modules/ticket/back/methods/expedition/moveExpeditions.js
index d0f8aa8939..cef35ab867 100644
--- a/modules/ticket/back/methods/expedition/moveExpeditions.js
+++ b/modules/ticket/back/methods/expedition/moveExpeditions.js
@@ -70,12 +70,12 @@ module.exports = Self => {
         try {
             if (args.routeId) {
                 const route = await models.Route.findById(args.routeId, null, myOptions);
-                if (!route) throw new UserError('This route not exists');
+                if (!route) throw new UserError('This route does not exists');
             }
             const ticket = await models.Ticket.new(ctx, myOptions);
             const promises = [];
             for (let expeditionsId of args.expeditionIds) {
-                const expeditionToUpdate = await models.Expedition.findById(expeditionsId);
+                const expeditionToUpdate = await models.Expedition.findById(expeditionsId, null, myOptions);
                 const expeditionUpdated = expeditionToUpdate.updateAttribute('ticketFk', ticket.id, myOptions);
                 promises.push(expeditionUpdated);
             }
diff --git a/modules/ticket/back/methods/expedition/specs/deleteExpeditions.spec.js b/modules/ticket/back/methods/expedition/specs/deleteExpeditions.spec.js
index 0a47c78da1..14bdf7aea6 100644
--- a/modules/ticket/back/methods/expedition/specs/deleteExpeditions.spec.js
+++ b/modules/ticket/back/methods/expedition/specs/deleteExpeditions.spec.js
@@ -10,7 +10,7 @@ describe('ticket deleteExpeditions()', () => {
             const expeditionIds = [12, 13];
             const result = await models.Expedition.deleteExpeditions(expeditionIds, options);
 
-            expect(result.count).toEqual(2);
+            expect(result.length).toEqual(2);
 
             await tx.rollback();
         } catch (e) {
diff --git a/modules/ticket/front/expedition/index.html b/modules/ticket/front/expedition/index.html
index 0ebe388c12..ec6dc7ee2b 100644
--- a/modules/ticket/front/expedition/index.html
+++ b/modules/ticket/front/expedition/index.html
@@ -159,7 +159,7 @@
         </vn-date-picker>
         <vn-textfield
             ng-show="selectLanded.data == 'withRoute'"
-            label="Id route"
+            label="Route id"
             ng-model="$ctrl.newRoute">
         </vn-textfield>
     </tpl-body>
diff --git a/modules/ticket/front/expedition/locale/es.yml b/modules/ticket/front/expedition/locale/es.yml
index 68812f9850..278dcc8f2a 100644
--- a/modules/ticket/front/expedition/locale/es.yml
+++ b/modules/ticket/front/expedition/locale/es.yml
@@ -3,4 +3,4 @@ Expedition removed: Expedición eliminada
 Move: Mover
 New ticket without route: Nuevo ticket sin ruta
 New ticket with route: Nuevo ticket con ruta
-Id route: Id ruta
\ No newline at end of file
+Route id: Id ruta
\ No newline at end of file

From d1e2b1f7d5ff9b98b8d62554e879c539937337dc Mon Sep 17 00:00:00 2001
From: vicent <vicent@verdnatura.es>
Date: Wed, 26 Oct 2022 09:02:54 +0200
Subject: [PATCH 122/151] refactor: tranducciones

---
 modules/ticket/front/sale/index.html | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/modules/ticket/front/sale/index.html b/modules/ticket/front/sale/index.html
index 35e45a8120..c681381411 100644
--- a/modules/ticket/front/sale/index.html
+++ b/modules/ticket/front/sale/index.html
@@ -244,7 +244,7 @@
         </vn-spinner>
         <div ng-if="$ctrl.edit.mana != null">
             <section class="header vn-pa-md">
-                <h5>MANÁ: {{::$ctrl.edit.mana | currency: 'EUR': 0}}</h5>
+                <h5>Mana: {{::$ctrl.edit.mana | currency: 'EUR': 0}}</h5>
             </section>
             <div class="vn-pa-md">
                 <vn-input-number
@@ -288,7 +288,7 @@
         </vn-spinner>
         <div ng-if="$ctrl.edit.mana != null">
             <section class="header vn-pa-md">
-                <h5>MANÁ: {{::$ctrl.edit.mana | currency: 'EUR': 0}}</h5>
+                <h5>Mana: {{::$ctrl.edit.mana | currency: 'EUR': 0}}</h5>
             </section>
             <div class="vn-pa-md">
                 <vn-input-number

From c671540a7f567f73df944840d5ec00e081391b55 Mon Sep 17 00:00:00 2001
From: vicent <vicent@verdnatura.es>
Date: Wed, 26 Oct 2022 09:04:53 +0200
Subject: [PATCH 123/151] refactor: renombrada variable

---
 .../ticket/back/methods/sale/specs/updatePrice.spec.js    | 4 ++--
 modules/ticket/back/methods/sale/specs/usesMana.spec.js   | 4 ++--
 .../back/methods/ticket/specs/updateDiscount.spec.js      | 8 ++++----
 3 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/modules/ticket/back/methods/sale/specs/updatePrice.spec.js b/modules/ticket/back/methods/sale/specs/updatePrice.spec.js
index 15b00a7329..51cd2403f1 100644
--- a/modules/ticket/back/methods/sale/specs/updatePrice.spec.js
+++ b/modules/ticket/back/methods/sale/specs/updatePrice.spec.js
@@ -79,11 +79,11 @@ describe('sale updatePrice()', () => {
             const price = 5.4;
             const originalSalesPersonMana = await models.WorkerMana.findById(18, null, options);
             const manaComponent = await models.Component.findOne({where: {code: 'mana'}}, options);
-            const teamCLopez = 96;
+            const teamOne = 96;
             const userId = ctx.req.accessToken.userId;
 
             const business = await models.Business.findOne({where: {workerFk: userId}}, options);
-            await business.updateAttribute('departmentFk', teamCLopez, options);
+            await business.updateAttribute('departmentFk', teamOne, options);
 
             await models.Sale.updatePrice(ctx, saleId, price, options);
             const updatedSale = await models.Sale.findById(saleId, null, options);
diff --git a/modules/ticket/back/methods/sale/specs/usesMana.spec.js b/modules/ticket/back/methods/sale/specs/usesMana.spec.js
index 4e14ed2c96..777bdc8f0a 100644
--- a/modules/ticket/back/methods/sale/specs/usesMana.spec.js
+++ b/modules/ticket/back/methods/sale/specs/usesMana.spec.js
@@ -12,11 +12,11 @@ describe('sale usesMana()', () => {
 
         try {
             const options = {transaction: tx};
-            const teamCLopez = 96;
+            const teamOne = 96;
             const userId = ctx.req.accessToken.userId;
 
             const business = await models.Business.findOne({where: {workerFk: userId}}, options);
-            await business.updateAttribute('departmentFk', teamCLopez, options);
+            await business.updateAttribute('departmentFk', teamOne, options);
 
             const usesMana = await models.Sale.usesMana(ctx, options);
 
diff --git a/modules/ticket/back/methods/ticket/specs/updateDiscount.spec.js b/modules/ticket/back/methods/ticket/specs/updateDiscount.spec.js
index 5249fe5d88..1f6712087d 100644
--- a/modules/ticket/back/methods/ticket/specs/updateDiscount.spec.js
+++ b/modules/ticket/back/methods/ticket/specs/updateDiscount.spec.js
@@ -110,10 +110,10 @@ describe('sale updateDiscount()', () => {
             const componentId = manaDiscount.id;
             const manaCode = 'mana';
 
-            const teamCLopez = 96;
+            const teamOne = 96;
             const userId = ctx.req.accessToken.userId;
             const business = await models.Business.findOne({where: {workerFk: userId}}, options);
-            await business.updateAttribute('departmentFk', teamCLopez, options);
+            await business.updateAttribute('departmentFk', teamOne, options);
 
             await models.Ticket.updateDiscount(ctx, ticketId, sales, newDiscount, manaCode, options);
 
@@ -155,10 +155,10 @@ describe('sale updateDiscount()', () => {
             const componentId = manaDiscount.id;
             const manaCode = 'manaClaim';
 
-            const teamCLopez = 96;
+            const teamOne = 96;
             const userId = ctx.req.accessToken.userId;
             const business = await models.Business.findOne({where: {workerFk: userId}}, options);
-            await business.updateAttribute('departmentFk', teamCLopez, options);
+            await business.updateAttribute('departmentFk', teamOne, options);
 
             await models.Ticket.updateDiscount(ctx, ticketId, sales, newDiscount, manaCode, options);
 

From 21e2945d4f6b59df9b239fd197b8845dbda7f8ef Mon Sep 17 00:00:00 2001
From: vicent <vicent@verdnatura.es>
Date: Wed, 26 Oct 2022 09:30:17 +0200
Subject: [PATCH 124/151] refactor: delete destroyAll

---
 .../methods/item-shelving/deleteItemShelvings.js     | 12 ++++++++----
 .../item-shelving/specs/deleteItemShelvings.spec.js  |  2 +-
 2 files changed, 9 insertions(+), 5 deletions(-)

diff --git a/modules/item/back/methods/item-shelving/deleteItemShelvings.js b/modules/item/back/methods/item-shelving/deleteItemShelvings.js
index 0b58970d83..f534b4e9a2 100644
--- a/modules/item/back/methods/item-shelving/deleteItemShelvings.js
+++ b/modules/item/back/methods/item-shelving/deleteItemShelvings.js
@@ -1,6 +1,6 @@
 module.exports = Self => {
     Self.remoteMethod('deleteItemShelvings', {
-        description: 'Deletes the selected orders',
+        description: 'Deletes the selected item shelvings',
         accessType: 'WRITE',
         accepts: [{
             arg: 'itemShelvingIds',
@@ -32,9 +32,13 @@ module.exports = Self => {
         }
 
         try {
-            const deletedItemShelvings = await models.ItemShelving.destroyAll({
-                id: {inq: itemShelvingIds}
-            }, myOptions);
+            const promises = [];
+            for (let itemShelvingId of itemShelvingIds) {
+                const itemShelvingToDelete = models.ItemShelving.destroyById(itemShelvingId, myOptions);
+                promises.push(itemShelvingToDelete);
+            }
+
+            const deletedItemShelvings = await Promise.all(promises);
 
             if (tx) await tx.commit();
 
diff --git a/modules/item/back/methods/item-shelving/specs/deleteItemShelvings.spec.js b/modules/item/back/methods/item-shelving/specs/deleteItemShelvings.spec.js
index a152b59815..b4113d7cf5 100644
--- a/modules/item/back/methods/item-shelving/specs/deleteItemShelvings.spec.js
+++ b/modules/item/back/methods/item-shelving/specs/deleteItemShelvings.spec.js
@@ -10,7 +10,7 @@ describe('ItemShelving deleteItemShelvings()', () => {
             const itemShelvingIds = [1, 2];
             const result = await models.ItemShelving.deleteItemShelvings(itemShelvingIds, options);
 
-            expect(result.count).toEqual(2);
+            expect(result.length).toEqual(2);
 
             await tx.rollback();
         } catch (e) {

From d243f9a87d8864901219309b6554c9907e3d5bf5 Mon Sep 17 00:00:00 2001
From: alexandre <alexandre@verdnatura.es>
Date: Wed, 26 Oct 2022 10:03:13 +0200
Subject: [PATCH 125/151] =?UTF-8?q?refs=20#4644=20checkbox=20a=C3=B1adido?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 modules/supplier/back/models/supplier.json       |  3 +++
 modules/supplier/front/descriptor/index.js       |  1 +
 modules/supplier/front/fiscal-data/index.html    | 12 ++++++++----
 modules/supplier/front/fiscal-data/locale/es.yml |  1 +
 4 files changed, 13 insertions(+), 4 deletions(-)

diff --git a/modules/supplier/back/models/supplier.json b/modules/supplier/back/models/supplier.json
index b27073ca5c..3cd6386a87 100644
--- a/modules/supplier/back/models/supplier.json
+++ b/modules/supplier/back/models/supplier.json
@@ -51,6 +51,9 @@
         "isSerious": {
             "type": "boolean"
         },
+        "isTrucker": {
+            "type": "boolean"
+        },
         "note": {
             "type": "string"
         },
diff --git a/modules/supplier/front/descriptor/index.js b/modules/supplier/front/descriptor/index.js
index df9fe2155c..a26d9c5106 100644
--- a/modules/supplier/front/descriptor/index.js
+++ b/modules/supplier/front/descriptor/index.js
@@ -41,6 +41,7 @@ class Controller extends Descriptor {
                 'payDay',
                 'isActive',
                 'isSerious',
+                'isTrucker',
                 'account'
             ],
             include: [
diff --git a/modules/supplier/front/fiscal-data/index.html b/modules/supplier/front/fiscal-data/index.html
index 4ae07c81a5..a3ede2058d 100644
--- a/modules/supplier/front/fiscal-data/index.html
+++ b/modules/supplier/front/fiscal-data/index.html
@@ -118,8 +118,6 @@
                 rule
                 vn-focus>
             </vn-textfield>
-        </vn-horizontal>
-        <vn-horizontal>
             <vn-datalist vn-one
                 label="Postcode"
                 ng-model="$ctrl.supplier.postCode"
@@ -144,6 +142,8 @@
                     </vn-icon-button>
                 </append>
             </vn-datalist>
+        </vn-horizontal>
+        <vn-horizontal>
             <vn-datalist vn-id="town" vn-one 
                 label="City"
                 ng-model="$ctrl.supplier.city"
@@ -159,8 +159,6 @@
                     ({{province.country.country}})
                 </tpl-item>
             </vn-datalist>
-        </vn-horizontal>
-        <vn-horizontal>
             <vn-autocomplete vn-id="province" vn-one
                 label="Province"
                 ng-model="$ctrl.supplier.provinceFk"
@@ -172,6 +170,8 @@
                 rule>
                 <tpl-item>{{name}} ({{country.country}})</tpl-item>
             </vn-autocomplete>
+        </vn-horizontal>
+        <vn-horizontal>
             <vn-autocomplete vn-id="country" vn-one
                 ng-model="$ctrl.supplier.countryFk"
                 data="countries"
@@ -180,6 +180,10 @@
                 label="Country"
                 rule>
             </vn-autocomplete>
+            <vn-check
+                label="Trucker" 
+                ng-model="$ctrl.supplier.isTrucker">
+            </vn-check>
         </vn-horizontal>
     </vn-card>
     <vn-button-bar>
diff --git a/modules/supplier/front/fiscal-data/locale/es.yml b/modules/supplier/front/fiscal-data/locale/es.yml
index 4cb537198a..5232dd95d5 100644
--- a/modules/supplier/front/fiscal-data/locale/es.yml
+++ b/modules/supplier/front/fiscal-data/locale/es.yml
@@ -3,3 +3,4 @@ Sage transaction type: Tipo de transacción Sage
 Sage withholding: Retención Sage
 Supplier activity: Actividad proveedor
 Healt register: Pasaporte sanitario
+Trucker: Transportista
\ No newline at end of file

From 65e32f5e7fc1b0c3b1ff0d9a7fa5564d12f0e84b Mon Sep 17 00:00:00 2001
From: vicent <vicent@verdnatura.es>
Date: Wed, 26 Oct 2022 12:40:13 +0200
Subject: [PATCH 126/151] feat: client search panel add find by zone

---
 .../10500-november/00-zone_getPostalCode.sql  |  56 ++++++
 modules/client/back/methods/client/filter.js  | 174 ++++++++++++++++++
 modules/client/back/models/client-methods.js  |   1 +
 modules/client/front/main/index.html          |   5 +-
 modules/client/front/main/index.js            |  26 ---
 modules/client/front/search-panel/index.html  |   7 +
 6 files changed, 240 insertions(+), 29 deletions(-)
 create mode 100644 db/changes/10500-november/00-zone_getPostalCode.sql
 create mode 100644 modules/client/back/methods/client/filter.js

diff --git a/db/changes/10500-november/00-zone_getPostalCode.sql b/db/changes/10500-november/00-zone_getPostalCode.sql
new file mode 100644
index 0000000000..b71306a58b
--- /dev/null
+++ b/db/changes/10500-november/00-zone_getPostalCode.sql
@@ -0,0 +1,56 @@
+DROP PROCEDURE IF EXISTS `vn`.`zone_getPostalCode`;
+
+DELIMITER $$
+$$
+CREATE DEFINER=`root`@`localhost` PROCEDURE `vn`.`zone_getPostalCode`(vSelf INT)
+BEGIN
+/**
+ * Devuelve los códigos postales incluidos en una zona
+ * 
+ * @return vNewTicket
+ */ 
+    DECLARE vGeoFk INT DEFAULT NULL;
+
+    DROP TEMPORARY TABLE IF EXISTS tmp.zoneNodes;
+    CREATE TEMPORARY TABLE tmp.zoneNodes (
+            geoFk INT,
+            name VARCHAR(100),
+            parentFk INT,
+            sons INT,
+            isChecked BOOL DEFAULT 0,
+            zoneFk INT,
+            PRIMARY KEY zoneNodesPk (zoneFk, geoFk),
+            INDEX(geoFk))
+            ENGINE = MEMORY;
+
+    CALL zone_getLeaves2(vSelf, NULL , NULL);
+
+       UPDATE tmp.zoneNodes zn
+           SET isChecked = 0
+       WHERE parentFk IS NULL;
+
+        myLoop: LOOP    
+            SET vGeoFk = NULL;
+            SELECT geoFk INTO vGeoFk 
+                FROM tmp.zoneNodes zn
+                WHERE NOT isChecked
+                LIMIT 1;
+
+            CALL zone_getLeaves2(vSelf, vGeoFk, NULL);
+            UPDATE tmp.zoneNodes
+                SET isChecked = TRUE 
+                WHERE geoFk = vGeoFk;
+
+            IF vGeoFk IS NULL THEN
+                LEAVE myLoop;
+            END IF;
+        END LOOP;
+
+    DELETE FROM tmp.zoneNodes 
+        WHERE sons > 0;
+
+        SELECT zn.geoFk, zn.name
+            FROM tmp.zoneNodes zn
+                JOIN zone z ON z.id = zn.zoneFk;
+END$$
+DELIMITER ;
diff --git a/modules/client/back/methods/client/filter.js b/modules/client/back/methods/client/filter.js
new file mode 100644
index 0000000000..0e9eaf160c
--- /dev/null
+++ b/modules/client/back/methods/client/filter.js
@@ -0,0 +1,174 @@
+
+const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
+const buildFilter = require('vn-loopback/util/filter').buildFilter;
+const mergeFilters = require('vn-loopback/util/filter').mergeFilters;
+
+module.exports = Self => {
+    Self.remoteMethodCtx('filter', {
+        description: 'Find all clients matched by the filter',
+        accessType: 'READ',
+        accepts: [
+            {
+                arg: 'filter',
+                type: 'object',
+            },
+            {
+                arg: 'search',
+                type: 'string',
+                description: `If it's and integer searchs by id, otherwise it searchs by name`,
+            },
+            {
+                arg: 'name',
+                type: 'string',
+                description: 'The client name',
+            },
+            {
+                arg: 'salesPersonFk',
+                type: 'number',
+            },
+            {
+                arg: 'fi',
+                type: 'string',
+                description: 'The client fiscal id',
+            },
+            {
+                arg: 'socialName',
+                type: 'string',
+            },
+            {
+                arg: 'city',
+                type: 'string',
+            },
+            {
+                arg: 'postcode',
+                type: 'string',
+            },
+            {
+                arg: 'provinceFk',
+                type: 'number',
+            },
+            {
+                arg: 'email',
+                type: 'string',
+            },
+            {
+                arg: 'phone',
+                type: 'string',
+            },
+            {
+                arg: 'zoneFk',
+                type: 'number',
+            },
+        ],
+        returns: {
+            type: ['object'],
+            root: true
+        },
+        http: {
+            path: `/filter`,
+            verb: 'GET'
+        }
+    });
+
+    Self.filter = async(ctx, filter, options) => {
+        const conn = Self.dataSource.connector;
+        const myOptions = {};
+        const postalCode = [];
+        const args = ctx.args;
+        if (typeof options == 'object')
+            Object.assign(myOptions, options);
+        if (args.zoneFk) {
+            query = `CALL vn.zone_getPostalCode(?)`;
+            const [geos] = await Self.rawSql(query, [args.zoneFk]);
+            for (let geo of geos)
+                postalCode.push(geo.name);
+        }
+
+        const where = buildFilter(ctx.args, (param, value) => {
+            switch (param) {
+            case 'search':
+                return /^\d+$/.test(value)
+                    ? {'c.id': {inq: value}}
+                    : {'c.name': {like: `%${value}%`}};
+            case 'name':
+            case 'salesPersonFk':
+            case 'fi':
+            case 'socialName':
+            case 'city':
+            case 'postcode':
+            case 'provinceFk':
+            case 'email':
+            case 'phone':
+                param = `c.${param}`;
+                return {[param]: value};
+            case 'zoneFk':
+                param = 'a.postalCode';
+                return {[param]: {inq: postalCode}};
+            }
+        });
+
+        filter = mergeFilters(filter, {where});
+
+        const stmts = [];
+        const stmt = new ParameterizedSQL(
+            `SELECT 
+                    c.id,
+                    c.name,
+                    c.socialName,
+                    c.fi,
+                    c.credit,
+                    c.creditInsurance,
+                    c.phone,
+                    c.mobile,
+                    c.street,
+                    c.city,
+                    c.postcode,
+                    c.email,
+                    c.created,
+                    c.isActive,
+                    c.isVies,
+                    c.isTaxDataChecked,
+                    c.isEqualizated,
+                    c.isFreezed,
+                    c.hasToInvoice,
+                    c.hasToInvoiceByAddress,
+                    c.isToBeMailed,
+                    c.hasSepaVnl,
+                    c.hasLcr,
+                    c.hasCoreVnl,
+                    ct.id AS countryFk,
+                    ct.country,
+                    p.id AS provinceFk,
+                    p.name AS province,
+                    u.id AS salesPersonFk,
+                    u.name AS salesPerson,
+                    bt.code AS businessTypeFk,
+                    bt.description AS businessType,
+                    pm.id AS payMethodFk,
+                    pm.name AS payMethod,
+                    sti.CodigoIva AS sageTaxTypeFk,
+                    sti.Iva AS sageTaxType,
+                    stt.CodigoTransaccion AS sageTransactionTypeFk,
+                    stt.Transaccion AS sageTransactionType
+                FROM client c
+                    LEFT JOIN account.user u ON u.id = c.salesPersonFk
+                    LEFT JOIN country ct ON ct.id = c.countryFk
+                    LEFT JOIN province p ON p.id = c.provinceFk
+                    LEFT JOIN businessType bt ON bt.code = c.businessTypeFk
+                    LEFT JOIN payMethod pm ON pm.id = c.payMethodFk
+                    LEFT JOIN sage.TiposIva sti ON sti.CodigoIva = c.taxTypeSageFk
+                    LEFT JOIN sage.TiposTransacciones stt ON stt.CodigoTransaccion = c.transactionTypeSageFk
+                    LEFT JOIN vn.address a ON a.id = c.defaultAddressFk
+                    `
+        );
+
+        stmt.merge(conn.makeWhere(filter.where));
+        stmt.merge(conn.makePagination(filter));
+
+        const clientsIndex = stmts.push(stmt) - 1;
+        const sql = ParameterizedSQL.join(stmts, ';');
+        const result = await conn.executeStmt(sql, myOptions);
+
+        return clientsIndex === 0 ? result : result[clientsIndex];
+    };
+};
diff --git a/modules/client/back/models/client-methods.js b/modules/client/back/models/client-methods.js
index 04d10413a8..5134e39422 100644
--- a/modules/client/back/models/client-methods.js
+++ b/modules/client/back/models/client-methods.js
@@ -47,4 +47,5 @@ module.exports = Self => {
     require('../methods/client/incotermsAuthorizationHtml')(Self);
     require('../methods/client/incotermsAuthorizationEmail')(Self);
     require('../methods/client/consumptionSendQueued')(Self);
+    require('../methods/client/filter')(Self);
 };
diff --git a/modules/client/front/main/index.html b/modules/client/front/main/index.html
index e8bc4b9884..0787858ae1 100644
--- a/modules/client/front/main/index.html
+++ b/modules/client/front/main/index.html
@@ -1,6 +1,6 @@
 <vn-crud-model
     vn-id="model"
-    url="Clients"
+    url="Clients/filter"
     order="id DESC"
     limit="8"
     data="clients">
@@ -10,8 +10,7 @@
         vn-focus
         panel="vn-client-search-panel"
         info="Search client by id or name"
-        model="model"
-        expr-builder="$ctrl.exprBuilder(param, value)">
+        model="model">
     </vn-searchbar>
 </vn-portal>
 <vn-portal slot="menu">
diff --git a/modules/client/front/main/index.js b/modules/client/front/main/index.js
index 1069d3487e..346880f4c5 100644
--- a/modules/client/front/main/index.js
+++ b/modules/client/front/main/index.js
@@ -2,32 +2,6 @@ import ngModule from '../module';
 import ModuleMain from 'salix/components/module-main';
 
 export default class Client extends ModuleMain {
-    exprBuilder(param, value) {
-        switch (param) {
-        case 'search':
-            return /^\d+$/.test(value)
-                ? {id: value}
-                : {or: [{name: {like: `%${value}%`}}, {socialName: {like: `%${value}%`}}]};
-        case 'phone':
-            return {
-                or: [
-                    {phone: value},
-                    {mobile: value}
-                ]
-            };
-        case 'name':
-        case 'socialName':
-        case 'city':
-        case 'email':
-            return {[param]: {like: `%${value}%`}};
-        case 'id':
-        case 'fi':
-        case 'postcode':
-        case 'provinceFk':
-        case 'salesPersonFk':
-            return {[param]: value};
-        }
-    }
 }
 
 ngModule.vnComponent('vnClient', {
diff --git a/modules/client/front/search-panel/index.html b/modules/client/front/search-panel/index.html
index 234cb6f53e..a02f93882f 100644
--- a/modules/client/front/search-panel/index.html
+++ b/modules/client/front/search-panel/index.html
@@ -58,6 +58,13 @@
             value-field="id"
             label="Province">
         </vn-autocomplete>
+        <vn-autocomplete
+            ng-model="filter.zoneFk"
+            url="Zones"
+            show-field="name"
+            value-field="id"
+            label="Zone">
+        </vn-autocomplete>
     </vn-horizontal>
     <vn-horizontal>
         <vn-textfield

From 405bc8765a275552e2d83cd9c221ed93bd899f97 Mon Sep 17 00:00:00 2001
From: alexandre <alexandre@verdnatura.es>
Date: Wed, 26 Oct 2022 12:48:48 +0200
Subject: [PATCH 127/151] refs #4645 valores ref cambiados

---
 e2e/helpers/selectors.js                      |  3 +-
 e2e/paths/12-entry/05_basicData.spec.js       |  8 ++++
 modules/entry/back/methods/entry/filter.js    |  3 +-
 .../entry/back/methods/entry/importBuys.js    | 10 ++++-
 .../methods/entry/specs/importBuys.spec.js    |  9 +++--
 modules/entry/back/models/entry.json          | 13 ++++++-
 modules/entry/front/basic-data/index.html     | 39 ++++++++++++-------
 modules/entry/front/index/index.html          |  4 +-
 modules/entry/front/index/locale/es.yml       |  3 +-
 modules/entry/front/search-panel/index.html   |  9 ++++-
 .../entry/front/search-panel/locale/es.yml    |  3 +-
 modules/entry/front/summary/index.html        |  5 ++-
 modules/entry/front/summary/locale/es.yml     |  2 +-
 13 files changed, 81 insertions(+), 30 deletions(-)

diff --git a/e2e/helpers/selectors.js b/e2e/helpers/selectors.js
index cd6d39795b..bf918c74a0 100644
--- a/e2e/helpers/selectors.js
+++ b/e2e/helpers/selectors.js
@@ -1100,7 +1100,8 @@ export default {
         anyBuyLine: 'vn-entry-summary tr.dark-row'
     },
     entryBasicData: {
-        reference: 'vn-entry-basic-data vn-textfield[ng-model="$ctrl.entry.ref"]',
+        reference: 'vn-entry-basic-data vn-textfield[ng-model="$ctrl.entry.reference"]',
+        invoiceNumber: 'vn-entry-basic-data vn-textfield[ng-model="$ctrl.entry.invoiceNumber"]',
         notes: 'vn-entry-basic-data vn-textfield[ng-model="$ctrl.entry.notes"]',
         observations: 'vn-entry-basic-data vn-textarea[ng-model="$ctrl.entry.observation"]',
         supplier: 'vn-entry-basic-data vn-autocomplete[ng-model="$ctrl.entry.supplierFk"]',
diff --git a/e2e/paths/12-entry/05_basicData.spec.js b/e2e/paths/12-entry/05_basicData.spec.js
index c1aa140192..3b5f40c357 100644
--- a/e2e/paths/12-entry/05_basicData.spec.js
+++ b/e2e/paths/12-entry/05_basicData.spec.js
@@ -19,6 +19,7 @@ describe('Entry basic data path', () => {
 
     it('should edit the basic data', async() => {
         await page.write(selectors.entryBasicData.reference, 'new movement 8');
+        await page.write(selectors.entryBasicData.invoiceNumber, 'new movement 8');
         await page.write(selectors.entryBasicData.notes, 'new notes');
         await page.write(selectors.entryBasicData.observations, ' edited');
         await page.autocompleteSearch(selectors.entryBasicData.supplier, 'Plants nick');
@@ -45,6 +46,13 @@ describe('Entry basic data path', () => {
         expect(result).toEqual('new movement 8');
     });
 
+    it('should confirm the invoiceNumber was edited', async() => {
+        await page.reloadSection('entry.card.basicData');
+        const result = await page.waitToGetProperty(selectors.entryBasicData.invoiceNumber, 'value');
+
+        expect(result).toEqual('new movement 8');
+    });
+
     it('should confirm the note was edited', async() => {
         const result = await page.waitToGetProperty(selectors.entryBasicData.notes, 'value');
 
diff --git a/modules/entry/back/methods/entry/filter.js b/modules/entry/back/methods/entry/filter.js
index 1ba4166dcf..3a08bffffd 100644
--- a/modules/entry/back/methods/entry/filter.js
+++ b/modules/entry/back/methods/entry/filter.js
@@ -154,7 +154,8 @@ module.exports = Self => {
                     e.id,
                     e.supplierFk,
                     e.dated,
-                    e.ref,
+                    e.ref reference,
+                    e.ref invoiceNumber,
                     e.isBooked,
                     e.isExcludedFromAvailable,
                     e.notes,
diff --git a/modules/entry/back/methods/entry/importBuys.js b/modules/entry/back/methods/entry/importBuys.js
index fb2f5f4529..fdc6b058e5 100644
--- a/modules/entry/back/methods/entry/importBuys.js
+++ b/modules/entry/back/methods/entry/importBuys.js
@@ -12,10 +12,15 @@ module.exports = Self => {
             http: {source: 'path'}
         },
         {
-            arg: 'ref',
+            arg: 'reference',
             type: 'string',
             description: 'The buyed boxes ids',
         },
+        {
+            arg: 'invoiceNumber',
+            type: 'string',
+            description: 'The registered invoice number',
+        },
         {
             arg: 'observation',
             type: 'string',
@@ -63,7 +68,8 @@ module.exports = Self => {
 
             await entry.updateAttributes({
                 observation: args.observation,
-                ref: args.ref
+                reference: args.reference,
+                invoiceNumber: args.invoiceNumber
             }, myOptions);
 
             const travel = entry.travel();
diff --git a/modules/entry/back/methods/entry/specs/importBuys.spec.js b/modules/entry/back/methods/entry/specs/importBuys.spec.js
index 9cf6f43008..4f9204c6a3 100644
--- a/modules/entry/back/methods/entry/specs/importBuys.spec.js
+++ b/modules/entry/back/methods/entry/specs/importBuys.spec.js
@@ -15,13 +15,15 @@ describe('entry import()', () => {
     });
 
     it('should import the buy rows', async() => {
-        const expectedRef = '1, 2';
+        const expectedReference = '1, 2';
+        const expectedInvoiceNumber = '1, 2';
         const expectedObservation = '123456';
         const ctx = {
             req: activeCtx,
             args: {
                 observation: expectedObservation,
-                ref: expectedRef,
+                reference: expectedReference,
+                invoiceNumber: expectedInvoiceNumber,
                 buys: [
                     {
                         itemFk: 1,
@@ -58,7 +60,8 @@ describe('entry import()', () => {
             }, options);
 
             expect(updatedEntry.observation).toEqual(expectedObservation);
-            expect(updatedEntry.ref).toEqual(expectedRef);
+            expect(updatedEntry.reference).toEqual(expectedReference);
+            expect(updatedEntry.invoiceNumber).toEqual(expectedInvoiceNumber);
             expect(entryBuys.length).toEqual(4);
 
             await tx.rollback();
diff --git a/modules/entry/back/models/entry.json b/modules/entry/back/models/entry.json
index c456859a58..d3c802ad21 100644
--- a/modules/entry/back/models/entry.json
+++ b/modules/entry/back/models/entry.json
@@ -18,8 +18,17 @@
         "dated": {
             "type": "date"
         },
-        "ref": {
-            "type": "string"
+        "reference": {
+            "type": "string",
+			"mysql": {
+				"columnName": "ref"
+			}
+        },
+        "invoiceNumber": {
+            "type": "string",
+			"mysql": {
+				"columnName": "ref"
+			}
         },
         "isBooked": {
             "type": "boolean"
diff --git a/modules/entry/front/basic-data/index.html b/modules/entry/front/basic-data/index.html
index 423e9d70d2..68a65e8903 100644
--- a/modules/entry/front/basic-data/index.html
+++ b/modules/entry/front/basic-data/index.html
@@ -48,7 +48,7 @@
             <vn-textfield
                 vn-one
                 label="Reference"
-                ng-model="$ctrl.entry.ref"
+                ng-model="$ctrl.entry.reference"
                 rule
                 vn-focus>
             </vn-textfield>
@@ -61,17 +61,25 @@
             </vn-textfield>
         </vn-horizontal>
         <vn-horizontal>
-            <vn-textarea
+            <vn-textfield
                 vn-one
-                label="Observation" 
-                ng-model="$ctrl.entry.observation"
-                rule>
-            </vn-textarea>
+                label="Invoice number"
+                ng-model="$ctrl.entry.invoiceNumber"
+                rule
+                vn-focus>
+            </vn-textfield>
+            <vn-autocomplete
+                url="Companies"
+                label="Company"
+                show-field="code"
+                value-field="id"
+                ng-model="$ctrl.entry.companyFk">
+            </vn-autocomplete>
         </vn-horizontal>
         <vn-horizontal>
             <vn-autocomplete
-                vn-one
-                label="Currency"
+            vn-one
+            label="Currency"
                 ng-model="$ctrl.entry.currencyFk"
                 url="Currencies"
                 show-field="code"
@@ -84,13 +92,14 @@
                 ng-model="$ctrl.entry.commission"
                 rule>
             </vn-input-number>
-            <vn-autocomplete
-                url="Companies"
-                label="Company"
-                show-field="code"
-                value-field="id"
-                ng-model="$ctrl.entry.companyFk">
-            </vn-autocomplete>
+        </vn-horizontal>
+        <vn-horizontal>
+            <vn-textarea
+                vn-one
+                label="Observation" 
+                ng-model="$ctrl.entry.observation"
+                rule>
+            </vn-textarea>
         </vn-horizontal>
         <vn-horizontal>
             <vn-check
diff --git a/modules/entry/front/index/index.html b/modules/entry/front/index/index.html
index 3e27a6a555..42177be210 100644
--- a/modules/entry/front/index/index.html
+++ b/modules/entry/front/index/index.html
@@ -12,6 +12,7 @@
                 <vn-th field="id" number>Id</vn-th>
                 <vn-th field="landed" center expand>Landed</vn-th>
                 <vn-th>Reference</vn-th>
+                <vn-th>Invoice number</vn-th>
                 <vn-th field="supplierFk">Supplier</vn-th>
                 <vn-th field="isBooked" center>Booked</vn-th>
                 <vn-th field="isConfirmed" center>Confirmed</vn-th>
@@ -45,7 +46,8 @@
                         {{::entry.landed | date:'dd/MM/yyyy'}}
                     </span>
                 </vn-td>
-                <vn-td expand>{{::entry.ref}}</vn-td>
+                <vn-td expand>{{::entry.reference}}</vn-td>
+                <vn-td expand>{{::entry.invoiceNumber}}</vn-td>
                 <vn-td expand>{{::entry.supplierName}}</vn-td>
                 <vn-td center><vn-check ng-model="entry.isBooked" disabled="true"></vn-check></vn-td>
                 <vn-td center><vn-check ng-model="entry.isConfirmed" disabled="true"></vn-check></vn-td>
diff --git a/modules/entry/front/index/locale/es.yml b/modules/entry/front/index/locale/es.yml
index 519f8e39aa..4f12fc7bb3 100644
--- a/modules/entry/front/index/locale/es.yml
+++ b/modules/entry/front/index/locale/es.yml
@@ -14,4 +14,5 @@ Booked: Contabilizada
 Is inventory: Inventario
 Notes: Notas
 Status: Estado
-Selection: Selección
\ No newline at end of file
+Selection: Selección
+Invoice number: Núm. factura
\ No newline at end of file
diff --git a/modules/entry/front/search-panel/index.html b/modules/entry/front/search-panel/index.html
index 38acdf77d6..adcb9d6d4a 100644
--- a/modules/entry/front/search-panel/index.html
+++ b/modules/entry/front/search-panel/index.html
@@ -13,9 +13,16 @@
             <vn-textfield
                 vn-one
                 label="Reference"
-                ng-model="filter.ref">
+                ng-model="filter.reference">
             </vn-textfield>
             <vn-textfield
+                vn-one
+                label="Invoice number"
+                ng-model="filter.invoiceNumber">
+            </vn-textfield>
+        </vn-horizontal>
+        <vn-horizontal>
+        <vn-textfield
                 vn-one
                 label="Travel"
                 ng-model="filter.travelFk">
diff --git a/modules/entry/front/search-panel/locale/es.yml b/modules/entry/front/search-panel/locale/es.yml
index 88f1641451..05b71da99a 100644
--- a/modules/entry/front/search-panel/locale/es.yml
+++ b/modules/entry/front/search-panel/locale/es.yml
@@ -5,4 +5,5 @@ From: Desde
 To: Hasta
 Agency: Agencia
 Warehouse: Almacén
-Search entry by id or a suppliers by name or alias: Buscar entrada por id o proveedores por nombre y alias
\ No newline at end of file
+Search entry by id or a suppliers by name or alias: Buscar entrada por id o proveedores por nombre y alias
+Invoice number: Núm. factura
\ No newline at end of file
diff --git a/modules/entry/front/summary/index.html b/modules/entry/front/summary/index.html
index ffd8aafab5..04844ab99d 100644
--- a/modules/entry/front/summary/index.html
+++ b/modules/entry/front/summary/index.html
@@ -27,7 +27,10 @@
                 value="{{$ctrl.entryData.company.code}}">
             </vn-label-value>
             <vn-label-value label="Reference"
-                value="{{$ctrl.entryData.ref}}">
+                value="{{$ctrl.entryData.reference}}">
+            </vn-label-value>
+            <vn-label-value label="Invoice number"
+                value="{{$ctrl.entryData.invoiceNumber}}">
             </vn-label-value>
             <vn-label-value label="Notes"
                 value="{{$ctrl.entryData.notes}}">
diff --git a/modules/entry/front/summary/locale/es.yml b/modules/entry/front/summary/locale/es.yml
index a141ce56ca..1761561edd 100644
--- a/modules/entry/front/summary/locale/es.yml
+++ b/modules/entry/front/summary/locale/es.yml
@@ -8,4 +8,4 @@ Minimum price: Precio mínimo
 Buys: Compras
 Travel: Envio
 Go to the entry: Ir a la entrada
-
+Invoice number: Núm. factura

From b39b28e43d011689acc911adedfe8b1e9609a5d9 Mon Sep 17 00:00:00 2001
From: vicent <vicent@verdnatura.es>
Date: Wed, 26 Oct 2022 13:10:17 +0200
Subject: [PATCH 128/151] =?UTF-8?q?refactor:=20a=C3=B1adido=20salto=20de?=
 =?UTF-8?q?=20lineas?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 modules/client/back/methods/client/filter.js | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/modules/client/back/methods/client/filter.js b/modules/client/back/methods/client/filter.js
index 0e9eaf160c..7cf4ba2ea3 100644
--- a/modules/client/back/methods/client/filter.js
+++ b/modules/client/back/methods/client/filter.js
@@ -75,8 +75,10 @@ module.exports = Self => {
         const myOptions = {};
         const postalCode = [];
         const args = ctx.args;
+
         if (typeof options == 'object')
             Object.assign(myOptions, options);
+
         if (args.zoneFk) {
             query = `CALL vn.zone_getPostalCode(?)`;
             const [geos] = await Self.rawSql(query, [args.zoneFk]);

From fa89d1f944d724e11b8b93d4cdf389a8405a5531 Mon Sep 17 00:00:00 2001
From: vicent <vicent@verdnatura.es>
Date: Wed, 26 Oct 2022 13:10:50 +0200
Subject: [PATCH 129/151] fix: comentario corregido

---
 db/changes/10500-november/00-zone_getPostalCode.sql | 2 --
 1 file changed, 2 deletions(-)

diff --git a/db/changes/10500-november/00-zone_getPostalCode.sql b/db/changes/10500-november/00-zone_getPostalCode.sql
index b71306a58b..58a281cb2d 100644
--- a/db/changes/10500-november/00-zone_getPostalCode.sql
+++ b/db/changes/10500-november/00-zone_getPostalCode.sql
@@ -6,8 +6,6 @@ CREATE DEFINER=`root`@`localhost` PROCEDURE `vn`.`zone_getPostalCode`(vSelf INT)
 BEGIN
 /**
  * Devuelve los códigos postales incluidos en una zona
- * 
- * @return vNewTicket
  */ 
     DECLARE vGeoFk INT DEFAULT NULL;
 

From bc6e6397462333abec2d5149fcde37e67bcf69de Mon Sep 17 00:00:00 2001
From: alexandre <alexandre@verdnatura.es>
Date: Wed, 26 Oct 2022 13:23:54 +0200
Subject: [PATCH 130/151] refs #4644 cambio en un test

---
 modules/supplier/front/descriptor/index.spec.js | 1 +
 1 file changed, 1 insertion(+)

diff --git a/modules/supplier/front/descriptor/index.spec.js b/modules/supplier/front/descriptor/index.spec.js
index 8926fa4d1a..4d16c51833 100644
--- a/modules/supplier/front/descriptor/index.spec.js
+++ b/modules/supplier/front/descriptor/index.spec.js
@@ -27,6 +27,7 @@ describe('Supplier Component vnSupplierDescriptor', () => {
                     'payDay',
                     'isActive',
                     'isSerious',
+                    'isTrucker',
                     'account'
                 ],
                 include: [

From c0b95564c3fc5bd764603524fffa1e99d8125541 Mon Sep 17 00:00:00 2001
From: vicent <vicent@verdnatura.es>
Date: Wed, 26 Oct 2022 14:25:17 +0200
Subject: [PATCH 131/151] refactor: borrado codigo sql innecesario

---
 modules/client/back/methods/client/filter.js | 37 +++-----------------
 1 file changed, 4 insertions(+), 33 deletions(-)

diff --git a/modules/client/back/methods/client/filter.js b/modules/client/back/methods/client/filter.js
index 7cf4ba2ea3..3e1ea43bb8 100644
--- a/modules/client/back/methods/client/filter.js
+++ b/modules/client/back/methods/client/filter.js
@@ -114,53 +114,24 @@ module.exports = Self => {
         const stmts = [];
         const stmt = new ParameterizedSQL(
             `SELECT 
-                    c.id,
+                    DISTINCT c.id,
                     c.name,
-                    c.socialName,
                     c.fi,
-                    c.credit,
-                    c.creditInsurance,
+                    c.socialName,
                     c.phone,
-                    c.mobile,
-                    c.street,
                     c.city,
                     c.postcode,
                     c.email,
-                    c.created,
                     c.isActive,
-                    c.isVies,
-                    c.isTaxDataChecked,
-                    c.isEqualizated,
                     c.isFreezed,
-                    c.hasToInvoice,
-                    c.hasToInvoiceByAddress,
-                    c.isToBeMailed,
-                    c.hasSepaVnl,
-                    c.hasLcr,
-                    c.hasCoreVnl,
-                    ct.id AS countryFk,
-                    ct.country,
                     p.id AS provinceFk,
                     p.name AS province,
                     u.id AS salesPersonFk,
-                    u.name AS salesPerson,
-                    bt.code AS businessTypeFk,
-                    bt.description AS businessType,
-                    pm.id AS payMethodFk,
-                    pm.name AS payMethod,
-                    sti.CodigoIva AS sageTaxTypeFk,
-                    sti.Iva AS sageTaxType,
-                    stt.CodigoTransaccion AS sageTransactionTypeFk,
-                    stt.Transaccion AS sageTransactionType
+                    u.name AS salesPerson
                 FROM client c
                     LEFT JOIN account.user u ON u.id = c.salesPersonFk
-                    LEFT JOIN country ct ON ct.id = c.countryFk
                     LEFT JOIN province p ON p.id = c.provinceFk
-                    LEFT JOIN businessType bt ON bt.code = c.businessTypeFk
-                    LEFT JOIN payMethod pm ON pm.id = c.payMethodFk
-                    LEFT JOIN sage.TiposIva sti ON sti.CodigoIva = c.taxTypeSageFk
-                    LEFT JOIN sage.TiposTransacciones stt ON stt.CodigoTransaccion = c.transactionTypeSageFk
-                    LEFT JOIN vn.address a ON a.id = c.defaultAddressFk
+                    JOIN vn.address a ON a.clientFk = c.id
                     `
         );
 

From 1d908002e22481c39bd5e72f8c0add5e45161514 Mon Sep 17 00:00:00 2001
From: vicent <vicent@verdnatura.es>
Date: Wed, 26 Oct 2022 14:25:27 +0200
Subject: [PATCH 132/151] feat: add backTest

---
 db/dump/fixtures.sql                          |  85 ++++----
 .../back/methods/client/specs/filter.spec.js  | 199 ++++++++++++++++++
 2 files changed, 242 insertions(+), 42 deletions(-)
 create mode 100644 modules/client/back/methods/client/specs/filter.spec.js

diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql
index 5b769e2851..beed24739d 100644
--- a/db/dump/fixtures.sql
+++ b/db/dump/fixtures.sql
@@ -353,48 +353,48 @@ INSERT INTO `vn`.`clientConfig`(`riskTolerance`, `maxCreditRows`)
 
 INSERT INTO `vn`.`address`(`id`, `nickname`, `street`, `city`, `postalCode`, `provinceFk`, `phone`, `mobile`, `isActive`, `clientFk`, `agencyModeFk`, `longitude`, `latitude`, `isEqualizated`, `isDefaultAddress`)
     VALUES
-        (1,     'Bruce Wayne',                  '1007 Mountain Drive, Gotham',                  'Gotham', 46460, 1, 1111111111, 222222222, 1, 1101,    2, NULL, NULL, 0, 1),
-        (2,     'Petter Parker',                '20 Ingram Street',                             'Gotham', 46460, 1, 1111111111, 222222222, 1, 1102,    2, NULL, NULL, 0, 1),
-        (3,     'Clark Kent',                   '344 Clinton Street',                           'Gotham', 46460, 1, 1111111111, 222222222, 1, 1103,    2, NULL, NULL, 0, 1),
-        (4,     'Tony Stark',                   '10880 Malibu Point',                           'Gotham', 46460, 1, 1111111111, 222222222, 1, 1104,    2, NULL, NULL, 0, 1),
-        (5,     'Max Eisenhardt',               'Unknown Whereabouts',                          'Gotham', 46460, 1, 1111111111, 222222222, 1, 1105,    2, NULL, NULL, 0, 1),
-        (6,     'DavidCharlesHaller',           'Evil hideout',                                 'Gotham', 46460, 1, 1111111111, 222222222, 1, 1106,    2, NULL, NULL, 0, 1),
-        (7,     'Hank Pym',                     'Anthill',                                      'Gotham', 46460, 1, 1111111111, 222222222, 1, 1107,    2, NULL, NULL, 0, 1),
-        (8,     'Charles Xavier',               '3800 Victory Pkwy, Cincinnati, OH 45207, USA', 'Gotham', 46460, 1, 1111111111, 222222222, 1, 1108,    2, NULL, NULL, 0, 1),
-        (9,     'Bruce Banner',                 'Somewhere in New York',                        'Gotham', 46460, 1, 1111111111, 222222222, 1, 1109,    2, NULL, NULL, 0, 1),
-        (10,    'Jessica Jones',                'NYCC 2015 Poster',                             'Gotham', 46460, 1, 1111111111, 222222222, 1, 1110,    2, NULL, NULL, 0, 1),
-        (11,    'Missing',                      'The space',                                    'Gotham', 46460, 1, 1111111111, 222222222, 1, 1111,   10, NULL, NULL, 0, 1),
-        (12,    'Trash',                        'New York city',                                'Gotham', 46460, 1, 1111111111, 222222222, 1, 1112,   10, NULL, NULL, 0, 1),
-        (101,   'Somewhere in Thailand',        'address 01',                                   'Gotham', 46460, 1, 1111111111, 222222222, 1, 1109,    2, NULL, NULL, 0, 0),
-        (102,   'Somewhere in Poland',          'address 02',                                   'Gotham', 46460, 1, 3333333333, 444444444, 1, 1109,    2, NULL, NULL, 0, 0),
-        (103,   'Somewhere in Japan',           'address 03',                                   'Gotham', 46460, 1, 3333333333, 444444444, 1, 1109,    2, NULL, NULL, 0, 0),
-        (104,   'Somewhere in Spain',           'address 04',                                   'Gotham', 46460, 1, 3333333333, 444444444, 1, 1109,    2, NULL, NULL, 0, 0),
-        (105,   'Somewhere in Potugal',         'address 05',                                   'Gotham', 46460, 1, 5555555555, 666666666, 1, 1109,    2, NULL, NULL, 0, 0),
-        (106,   'Somewhere in UK',              'address 06',                                   'Gotham', 46460, 1, 5555555555, 666666666, 1, 1109,    2, NULL, NULL, 0, 0),
-        (107,   'Somewhere in Valencia',        'address 07',                                   'Gotham', 46460, 1, 5555555555, 666666666, 1, 1109,    2, NULL, NULL, 0, 0),
-        (108,   'Somewhere in Gotham',           'address 08',                                  'Gotham', 46460, 1, 5555555555, 666666666, 1, 1109,    2, NULL, NULL, 0, 0),
-        (109,   'Somewhere in London',          'address 09',                                   'Gotham', 46460, 1, 1111111111, 222222222, 1, 1109,    2, NULL, NULL, 0, 0),
-        (110,   'Somewhere in Algemesi',        'address 10',                                   'Gotham', 46460, 1, 1111111111, 222222222, 1, 1109,    2, NULL, NULL, 0, 0),
-        (111,   'Somewhere in Carlet',          'address 11',                                   'Gotham', 46460, 1, 1111111111, 222222222, 1, 1109,    2, NULL, NULL, 0, 0),
-        (112,   'Somewhere in Campanar',        'address 12',                                   'Gotham', 46460, 1, 1111111111, 222222222, 1, 1109,    2, NULL, NULL, 0, 0),
-        (113,   'Somewhere in Malilla',         'address 13',                                   'Gotham', 46460, 1, 1111111111, 222222222, 1, 1109,    2, NULL, NULL, 0, 0),
-        (114,   'Somewhere in France',          'address 14',                                   'Gotham', 46460, 1, 1111111111, 222222222, 1, 1109,    2, NULL, NULL, 0, 0),
-        (115,   'Somewhere in Birmingham',      'address 15',                                   'Gotham', 46460, 1, 1111111111, 222222222, 1, 1109,    2, NULL, NULL, 0, 0),
-        (116,   'Somewhere in Scotland',        'address 16',                                   'Gotham', 46460, 1, 1111111111, 222222222, 1, 1109,    2, NULL, NULL, 0, 0),
-        (117,   'Somewhere in nowhere',         'address 17',                                   'Gotham', 46460, 1, 1111111111, 222222222, 1, 1109,    2, NULL, NULL, 0, 0),
-        (118,   'Somewhere over the rainbow',   'address 18',                                   'Gotham', 46460, 1, 1111111111, 222222222, 1, 1109,    2, NULL, NULL, 0, 0),
-        (119,   'Somewhere in Alberic',         'address 19',                                   'Gotham', 46460, 1, 1111111111, 222222222, 1, 1109,    2, NULL, NULL, 0, 0),
-        (120,   'Somewhere in Montortal',       'address 20',                                   'Gotham', 46460, 1, 1111111111, 222222222, 1, 1109,    2, NULL, NULL, 0, 0),
-        (121,   'the bat cave',                 'address 21',                                   'Gotham', 46460, 1, 1111111111, 222222222, 1, 1101,    2, NULL, NULL, 0, 0),
-        (122,   'NY roofs',                     'address 22',                                   'Gotham', 46460, 1, 1111111111, 222222222, 1, 1102,    2, NULL, NULL, 0, 0),
-        (123,   'The phone box',                'address 23',                                   'Gotham', 46460, 1, 1111111111, 222222222, 1, 1103,    2, NULL, NULL, 0, 0),
-        (124,   'Stark tower Gotham',           'address 24',                                   'Gotham', 46460, 1, 1111111111, 222222222, 1, 1104,    2, NULL, NULL, 0, 0),
-        (125,   'The plastic cell',             'address 25',                                   'Gotham', 46460, 1, 1111111111, 222222222, 1, 1105,    2, NULL, NULL, 0, 0),
-        (126,   'Many places',                  'address 26',                                   'Gotham', 46460, 1, 1111111111, 222222222, 1, 1106,    2, NULL, NULL, 0, 0),
-        (127,   'Your pocket',                  'address 27',                                   'Gotham', 46460, 1, 1111111111, 222222222, 1, 1107,    2, NULL, NULL, 0, 0),
-        (128,   'Cerebro',                      'address 28',                                   'Gotham', 46460, 1, 1111111111, 222222222, 1, 1108,    2, NULL, NULL, 0, 0),
-        (129,   'Luke Cages Bar',               'address 29',                                   'Gotham', 46460, 1, 1111111111, 222222222, 1, 1110,    2, NULL, NULL, 0, 0),
-        (130,   'Non valid address',            'address 30',                                   'Gotham', 46460, 1, 1111111111, 222222222, 0, 1101,    2, NULL, NULL, 0, 0);
+        (1,     'Bruce Wayne',                  '1007 Mountain Drive, Gotham',                  'Gotham', 46460,        1, 1111111111, 222222222, 1, 1101,    2, NULL, NULL, 0, 1),
+        (2,     'Petter Parker',                '20 Ingram Street',                             'Gotham', 46460,        1, 1111111111, 222222222, 1, 1102,    2, NULL, NULL, 0, 1),
+        (3,     'Clark Kent',                   '344 Clinton Street',                           'Gotham', 46460,        1, 1111111111, 222222222,  1, 1103,    2, NULL, NULL, 0,    1),
+        (4,     'Tony Stark',                   '10880 Malibu Point',                           'Gotham', 46460,        1, 1111111111, 222222222, 1    , 1104,    2, NULL, NULL, 0,    1),
+        (5,     'Max Eisenhardt',               'Unknown Whereabouts',                          'Gotham', 46460,        1, 1111111111, 222222222, 1, 1105,    2, NULL, NULL, 0, 1),
+        (6,     'DavidCharlesHaller',           'Evil hideout',                                 'Gotham', 46460,        1, 1111111111, 222222222, 1, 1106,    2, NULL, NULL, 0, 1),
+        (7,     'Hank Pym',                     'Anthill',                                      'Gotham', 46460,        1, 1111111111, 222222222, 1, 1107,    2, NULL, NULL, 0, 1),
+        (8,     'Charles Xavier',               '3800 Victory Pkwy, Cincinnati, OH 45207, USA', 'Gotham', 46460,        1, 1111111111, 222222222, 1, 1108,    2, NULL, NULL, 0, 1),
+        (9,     'Bruce Banner',                 'Somewhere in New York',                        'Gotham', 46460,        1, 1111111111, 222222222, 1, 1109,    2, NULL, NULL, 0, 1),
+        (10,    'Jessica Jones',                'NYCC 2015 Poster',                             'Gotham', 46460,        1, 1111111111, 222222222, 1, 1110,    2, NULL, NULL, 0, 1),
+        (11,    'Missing',                      'The space',                                    'Gotham', 46460,        1, 1111111111, 222222222, 1, 1111,   10, NULL, NULL, 0, 1),
+        (12,    'Trash',                        'New York city',                                'Gotham', 46460,        1, 1111111111, 222222222, 1, 1112,   10, NULL, NULL, 0, 1),
+        (101,   'Somewhere in Thailand',        'address 01',                                   'Gotham', 46460,        1, 1111111111, 222222222, 1, 1109,    2, NULL, NULL, 0, 0),
+        (102,   'Somewhere in Poland',          'address 02',                                   'Gotham', 46460,        1, 3333333333, 444444444, 1, 1109,    2, NULL, NULL, 0, 0),
+        (103,   'Somewhere in Japan',           'address 03',                                   'Gotham', 46460,        1, 3333333333, 444444444, 1, 1109,    2, NULL, NULL, 0, 0),
+        (104,   'Somewhere in Spain',           'address 04',                                   'Gotham', 46460,        1, 3333333333, 444444444, 1, 1109,    2, NULL, NULL, 0, 0),
+        (105,   'Somewhere in Potugal',         'address 05',                                   'Gotham', 46460,        1, 5555555555, 666666666, 1, 1109,    2, NULL, NULL, 0, 0),
+        (106,   'Somewhere in UK',              'address 06',                                   'Gotham', 46460,        1, 5555555555, 666666666, 1, 1109,    2, NULL, NULL, 0, 0),
+        (107,   'Somewhere in Valencia',        'address 07',                                   'Gotham', 46460,        1, 5555555555, 666666666, 1, 1109,    2, NULL, NULL, 0, 0),
+        (108,   'Somewhere in Gotham',           'address 08',                                  'Gotham', 46460,        1, 5555555555, 666666666, 1, 1109,    2, NULL, NULL, 0, 0),
+        (109,   'Somewhere in London',          'address 09',                                   'Gotham', 46460,        1, 1111111111, 222222222, 1, 1109,    2, NULL, NULL, 0, 0),
+        (110,   'Somewhere in Algemesi',        'address 10',                                   'Gotham', 46460,        1, 1111111111, 222222222, 1, 1109,    2, NULL, NULL, 0, 0),
+        (111,   'Somewhere in Carlet',          'address 11',                                   'Gotham', 46460,        1, 1111111111, 222222222, 1, 1109,    2, NULL, NULL, 0, 0),
+        (112,   'Somewhere in Campanar',        'address 12',                                   'Gotham', 46460,        1, 1111111111, 222222222, 1, 1109,    2, NULL, NULL, 0, 0),
+        (113,   'Somewhere in Malilla',         'address 13',                                   'Gotham', 46460,        1, 1111111111, 222222222, 1, 1109,    2, NULL, NULL, 0, 0),
+        (114,   'Somewhere in France',          'address 14',                                   'Gotham', 46460,        1, 1111111111, 222222222, 1, 1109,    2, NULL, NULL, 0, 0),
+        (115,   'Somewhere in Birmingham',      'address 15',                                   'Gotham', 46460,        1, 1111111111, 222222222, 1, 1109,    2, NULL, NULL, 0, 0),
+        (116,   'Somewhere in Scotland',        'address 16',                                   'Gotham', 46460,        1, 1111111111, 222222222, 1, 1109,    2, NULL, NULL, 0, 0),
+        (117,   'Somewhere in nowhere',         'address 17',                                   'Gotham', 46460,        1, 1111111111, 222222222, 1, 1109,    2, NULL, NULL, 0, 0),
+        (118,   'Somewhere over the rainbow',   'address 18',                                   'Gotham', 46460,        1, 1111111111, 222222222, 1, 1109,    2, NULL, NULL, 0, 0),
+        (119,   'Somewhere in Alberic',         'address 19',                                   'Gotham', 46460,        1, 1111111111, 222222222, 1, 1109,    2, NULL, NULL, 0, 0),
+        (120,   'Somewhere in Montortal',       'address 20',                                   'Gotham', 46460,        1, 1111111111, 222222222, 1, 1109,    2, NULL, NULL, 0, 0),
+        (121,   'the bat cave',                 'address 21',                                   'Gotham', 46460,        1, 1111111111, 222222222, 1, 1101,    2, NULL, NULL, 0, 0),
+        (122,   'NY roofs',                     'address 22',                                   'Gotham', 46460,        1, 1111111111, 222222222, 1, 1102,    2, NULL, NULL, 0, 0),
+        (123,   'The phone box',                'address 23',                                   'Gotham', 46460,        1, 1111111111, 222222222, 1, 1103,    2, NULL, NULL, 0, 0),
+        (124,   'Stark tower Gotham',           'address 24',                                   'Gotham', 46460,        1, 1111111111, 222222222, 1, 1104,    2, NULL, NULL, 0, 0),
+        (125,   'The plastic cell',             'address 25',                                   'Gotham', 46460,        1, 1111111111, 222222222, 1, 1105,    2, NULL, NULL, 0, 0),
+        (126,   'Many places',                  'address 26',                                   'Gotham', 46460,        1, 1111111111, 222222222, 1, 1106,    2, NULL, NULL, 0, 0),
+        (127,   'Your pocket',                  'address 27',                                   'Gotham', 46460,        1, 1111111111, 222222222, 1, 1107,    2, NULL, NULL, 0, 0),
+        (128,   'Cerebro',                      'address 28',                                   'Gotham', 46460,        1, 1111111111, 222222222, 1, 1108,    2, NULL, NULL, 0, 0),
+        (129,   'Luke Cages Bar',               'address 29',                                   'Gotham', 'EC170150',   1, 1111111111, 222222222, 1, 1110,    2, NULL, NULL, 0, 0),
+        (130,   'Non valid address',            'address 30',                                   'Gotham', 46460,        1, 1111111111, 222222222, 0, 1101,    2, NULL, NULL, 0, 0);
 
 INSERT INTO `vn`.`address`( `nickname`, `street`, `city`, `postalCode`, `provinceFk`, `isActive`, `clientFk`, `agencyModeFk`, `isDefaultAddress`)
     SELECT name, CONCAT(name, 'Street'), 'GOTHAM', 46460, 1, 1, id, 2, 1
@@ -2047,6 +2047,7 @@ INSERT INTO `vn`.`zoneIncluded` (`zoneFk`, `geoFk`, `isIncluded`)
         (8, 4,   0),
         (8, 5,   0),
         (8, 1,   1),
+        (9, 7,   1),
         (10, 14, 1);
 
 INSERT INTO `vn`.`zoneEvent`(`zoneFk`, `type`, `dated`)
diff --git a/modules/client/back/methods/client/specs/filter.spec.js b/modules/client/back/methods/client/specs/filter.spec.js
new file mode 100644
index 0000000000..6795850508
--- /dev/null
+++ b/modules/client/back/methods/client/specs/filter.spec.js
@@ -0,0 +1,199 @@
+const {models} = require('vn-loopback/server/server');
+
+describe('client filter()', () => {
+    it('should return the clients matching the filter with a limit of 20 rows', async() => {
+        const tx = await models.Client.beginTransaction({});
+
+        try {
+            const options = {transaction: tx};
+
+            const ctx = {req: {accessToken: {userId: 1}}, args: {}};
+            const filter = {limit: '8'};
+            const result = await models.Client.filter(ctx, filter, options);
+
+            expect(result.length).toEqual(8);
+
+            await tx.rollback();
+        } catch (e) {
+            await tx.rollback();
+            throw e;
+        }
+    });
+
+    it('should return the client "Bruce Wayne" matching the search argument with his name', async() => {
+        const tx = await models.Client.beginTransaction({});
+
+        try {
+            const options = {transaction: tx};
+
+            const ctx = {req: {accessToken: {userId: 1}}, args: {search: 'Bruce Wayne'}};
+            const filter = {};
+            const result = await models.Client.filter(ctx, filter, options);
+
+            const firstResult = result[0];
+
+            expect(result.length).toEqual(1);
+            expect(firstResult.name).toEqual('Bruce Wayne');
+
+            await tx.rollback();
+        } catch (e) {
+            await tx.rollback();
+            throw e;
+        }
+    });
+
+    it('should return the client "Bruce Wayne" matching the search argument with his id', async() => {
+        const tx = await models.Client.beginTransaction({});
+
+        try {
+            const options = {transaction: tx};
+
+            const ctx = {req: {accessToken: {userId: 1}}, args: {search: '1101'}};
+            const filter = {};
+            const result = await models.Client.filter(ctx, filter, options);
+
+            const firstResult = result[0];
+
+            expect(result.length).toEqual(1);
+            expect(firstResult.name).toEqual('Bruce Wayne');
+
+            await tx.rollback();
+        } catch (e) {
+            await tx.rollback();
+            throw e;
+        }
+    });
+
+    it('should return the client "Bruce Wayne" matching the name argument', async() => {
+        const tx = await models.Client.beginTransaction({});
+
+        try {
+            const options = {transaction: tx};
+
+            const ctx = {req: {accessToken: {userId: 1}}, args: {name: 'Bruce Wayne'}};
+            const filter = {};
+            const result = await models.Client.filter(ctx, filter, options);
+
+            const firstResult = result[0];
+
+            expect(result.length).toEqual(1);
+            expect(firstResult.name).toEqual('Bruce Wayne');
+
+            await tx.rollback();
+        } catch (e) {
+            await tx.rollback();
+            throw e;
+        }
+    });
+
+    it('should return the clients matching the "salesPersonFk" argument', async() => {
+        const tx = await models.Client.beginTransaction({});
+        const salesPersonId = 18;
+
+        try {
+            const options = {transaction: tx};
+
+            const ctx = {req: {accessToken: {userId: 1}}, args: {salesPersonFk: salesPersonId}};
+            const filter = {};
+            const result = await models.Client.filter(ctx, filter, options);
+
+            const randomIndex = Math.floor(Math.random() * result.length);
+            const randomResultClient = result[randomIndex];
+
+            expect(result.length).toBeGreaterThanOrEqual(5);
+            expect(randomResultClient.salesPersonFk).toEqual(salesPersonId);
+
+            await tx.rollback();
+        } catch (e) {
+            await tx.rollback();
+            throw e;
+        }
+    });
+
+    it('should return the clients matching the "fi" argument', async() => {
+        const tx = await models.Client.beginTransaction({});
+
+        try {
+            const options = {transaction: tx};
+
+            const ctx = {req: {accessToken: {userId: 1}}, args: {fi: '251628698'}};
+            const filter = {};
+            const result = await models.Client.filter(ctx, filter, options);
+
+            const firstClient = result[0];
+
+            expect(result.length).toEqual(1);
+            expect(firstClient.name).toEqual('Max Eisenhardt');
+
+            await tx.rollback();
+        } catch (e) {
+            await tx.rollback();
+            throw e;
+        }
+    });
+
+    it('should return the clients matching the "city" argument', async() => {
+        const tx = await models.Client.beginTransaction({});
+
+        try {
+            const options = {transaction: tx};
+
+            const ctx = {req: {accessToken: {userId: 1}}, args: {city: 'Gotham'}};
+            const filter = {};
+            const result = await models.Client.filter(ctx, filter, options);
+
+            const randomIndex = Math.floor(Math.random() * result.length);
+            const randomResultClient = result[randomIndex];
+
+            expect(result.length).toBeGreaterThanOrEqual(20);
+            expect(randomResultClient.city.toLowerCase()).toEqual('gotham');
+
+            await tx.rollback();
+        } catch (e) {
+            await tx.rollback();
+            throw e;
+        }
+    });
+
+    it('should return the clients matching the "postcode" argument', async() => {
+        const tx = await models.Client.beginTransaction({});
+
+        try {
+            const options = {transaction: tx};
+
+            const ctx = {req: {accessToken: {userId: 1}}, args: {postcode: '46460'}};
+            const filter = {};
+            const result = await models.Client.filter(ctx, filter, options);
+
+            const randomIndex = Math.floor(Math.random() * result.length);
+            const randomResultClient = result[randomIndex];
+
+            expect(result.length).toBeGreaterThanOrEqual(20);
+            expect(randomResultClient.postcode).toEqual('46460');
+
+            await tx.rollback();
+        } catch (e) {
+            await tx.rollback();
+            throw e;
+        }
+    });
+
+    it('should return the clients matching the "zoneFk" argument', async() => {
+        const tx = await models.Client.beginTransaction({});
+
+        try {
+            const options = {transaction: tx};
+
+            const ctx = {req: {accessToken: {userId: 1}}, args: {zoneFk: 9}};
+            const filter = {};
+            const result = await models.Client.filter(ctx, filter, options);
+
+            expect(result.length).toBe(1);
+
+            await tx.rollback();
+        } catch (e) {
+            await tx.rollback();
+            throw e;
+        }
+    });
+});

From 3ffc098b56d8ee9724edfe2c26a8e5813ab11857 Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Thu, 27 Oct 2022 09:01:09 +0200
Subject: [PATCH 133/151] feat(privileges): check if user has role from
 userToUpdate

---
 back/methods/account/privileges.js             | 17 +++++++++++++++--
 back/models/account.json                       |  7 +++++++
 db/changes/10490-august/00-user_hasGrant.sql   |  3 ---
 modules/account/front/privileges/locale/es.yml |  2 +-
 package.json                                   |  2 +-
 5 files changed, 24 insertions(+), 7 deletions(-)

diff --git a/back/methods/account/privileges.js b/back/methods/account/privileges.js
index 6510779f28..f3f500e7d2 100644
--- a/back/methods/account/privileges.js
+++ b/back/methods/account/privileges.js
@@ -44,15 +44,28 @@ module.exports = Self => {
         if (!user.hasGrant)
             throw new UserError(`You don't have grant privilege`);
 
-        const userToUpdate = await models.Account.findById(id, ['name', 'hasGrant', 'roleFk'], myOptions);
+        const [userToUpdate] = await models.Account.find({
+            fields: ['id', 'name', 'hasGrant', 'roleFk', 'password'],
+            include: {
+                relation: 'role',
+                scope: {
+                    fields: ['name']
+                }
+            },
+            where: {
+                id: id
+            }
+        }, myOptions);
+
         if (hasGrant != null)
             userToUpdate.hasGrant = hasGrant;
 
         if (roleFk) {
             const role = await models.Role.findById(roleFk, {fields: ['name']}, myOptions);
             const hasRole = await models.Account.hasRole(userId, role.name, myOptions);
+            const hasRoleFromUser = await models.Account.hasRole(userId, userToUpdate.role().name, myOptions);
 
-            if (!hasRole)
+            if (!hasRole || !hasRoleFromUser)
                 throw new UserError(`You don't own the role and you can't assign it to another user`);
 
             userToUpdate.roleFk = roleFk;
diff --git a/back/models/account.json b/back/models/account.json
index c25cd532d0..d0c17e70f6 100644
--- a/back/models/account.json
+++ b/back/models/account.json
@@ -102,6 +102,13 @@
 			"principalType": "ROLE",
 			"principalId": "$authenticated",
 			"permission": "ALLOW"
+		},
+		{
+			"property": "privileges",
+			"accessType": "*",
+			"principalType": "ROLE",
+			"principalId": "$authenticated",
+			"permission": "ALLOW"
 		}
 	]
 }
diff --git a/db/changes/10490-august/00-user_hasGrant.sql b/db/changes/10490-august/00-user_hasGrant.sql
index 05a09f87ba..60d1273d83 100644
--- a/db/changes/10490-august/00-user_hasGrant.sql
+++ b/db/changes/10490-august/00-user_hasGrant.sql
@@ -1,4 +1 @@
 ALTER TABLE `account`.`user` ADD hasGrant TINYINT(1) NOT NULL;
-
-INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalType, principalId)
-    VALUES('Account', 'privileges', '*', 'ALLOW', 'ROLE', '$authenticated');
diff --git a/modules/account/front/privileges/locale/es.yml b/modules/account/front/privileges/locale/es.yml
index 17f1ef29e1..d66a7a6cf5 100644
--- a/modules/account/front/privileges/locale/es.yml
+++ b/modules/account/front/privileges/locale/es.yml
@@ -1,2 +1,2 @@
 Privileges: Privilegios
-Has grant: Puede dar privilegios
+Has grant: Puede delegar privilegios
diff --git a/package.json b/package.json
index 92ca13e454..573e423357 100644
--- a/package.json
+++ b/package.json
@@ -37,7 +37,7 @@
         "node-ssh": "^11.0.0",
         "object-diff": "0.0.4",
         "object.pick": "^1.3.0",
-        "puppeteer": "^18.0.5",
+        "puppeteer": "^19.0.0",
         "read-chunk": "^3.2.0",
         "require-yaml": "0.0.1",
         "sharp": "^0.27.1",

From 736de00e77da5cf492a7e1e9a433233d97053c71 Mon Sep 17 00:00:00 2001
From: Pau Navarro <pau@verdnatura.es>
Date: Thu, 27 Oct 2022 09:18:00 +0200
Subject: [PATCH 134/151] deleted the test as requested on #1885

---
 db/tests/vn/orderConfirmWithUser.spec.js | 37 ------------------------
 1 file changed, 37 deletions(-)
 delete mode 100644 db/tests/vn/orderConfirmWithUser.spec.js

diff --git a/db/tests/vn/orderConfirmWithUser.spec.js b/db/tests/vn/orderConfirmWithUser.spec.js
deleted file mode 100644
index f2a3d0c4e3..0000000000
--- a/db/tests/vn/orderConfirmWithUser.spec.js
+++ /dev/null
@@ -1,37 +0,0 @@
-const app = require('vn-loopback/server/server');
-const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
-
-// #1885
-xdescribe('order_confirmWithUser()', () => {
-    it('should confirm an order', async() => {
-        let stmts = [];
-        let stmt;
-
-        stmts.push('START TRANSACTION');
-
-        let params = {
-            orderFk: 10,
-            userId: 9
-        };
-        // problema: la funcion order_confirmWithUser tiene una transacción, por tanto esta nunca hace rollback
-        stmt = new ParameterizedSQL('CALL hedera.order_confirmWithUser(?, ?)', [
-            params.orderFk,
-            params.userId
-        ]);
-        stmts.push(stmt);
-
-        stmt = new ParameterizedSQL('SELECT confirmed FROM hedera.order WHERE id = ?', [
-            params.orderFk
-        ]);
-        let orderIndex = stmts.push(stmt) - 1;
-
-        stmts.push('ROLLBACK');
-
-        let sql = ParameterizedSQL.join(stmts, ';');
-        let result = await app.models.Ticket.rawStmt(sql);
-
-        savedDescription = result[orderIndex][0].confirmed;
-
-        expect(savedDescription).toBeTruthy();
-    });
-});

From 6a2bc5b593cd25aab07e9cae201ce44c1cbbd772 Mon Sep 17 00:00:00 2001
From: joan <joan@verdnatura.es>
Date: Thu, 27 Oct 2022 09:18:32 +0200
Subject: [PATCH 135/151] Disabled back tests

---
 Jenkinsfile | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/Jenkinsfile b/Jenkinsfile
index 4a1f9ba546..440b5d0d3f 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -62,14 +62,14 @@ pipeline {
                         }
                     }
                 }
-                stage('Backend') {
-                    steps {
-                        nodejs('node-v14') {
-                            sh 'npm run test:back:ci'
-                        }
-                    }
-                }
-            }
+            //     stage('Backend') {
+            //         steps {
+            //             nodejs('node-v14') {
+            //                 sh 'npm run test:back:ci'
+            //             }
+            //         }
+            //     }
+            // }
         }
         stage('Build') {
             when { anyOf {

From 51f95f0261e611401f6c33802c79378845d4c058 Mon Sep 17 00:00:00 2001
From: joan <joan@verdnatura.es>
Date: Thu, 27 Oct 2022 09:23:08 +0200
Subject: [PATCH 136/151] Fixed error

---
 Jenkinsfile | 8 --------
 1 file changed, 8 deletions(-)

diff --git a/Jenkinsfile b/Jenkinsfile
index 440b5d0d3f..69cdc70b30 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -62,14 +62,6 @@ pipeline {
                         }
                     }
                 }
-            //     stage('Backend') {
-            //         steps {
-            //             nodejs('node-v14') {
-            //                 sh 'npm run test:back:ci'
-            //             }
-            //         }
-            //     }
-            // }
         }
         stage('Build') {
             when { anyOf {

From 714fe325525502d34a8302020076082864daf5f8 Mon Sep 17 00:00:00 2001
From: joan <joan@verdnatura.es>
Date: Thu, 27 Oct 2022 09:26:02 +0200
Subject: [PATCH 137/151] Fix error

---
 Jenkinsfile | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/Jenkinsfile b/Jenkinsfile
index 69cdc70b30..5a8ff39c5d 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -62,6 +62,14 @@ pipeline {
                         }
                     }
                 }
+            //     stage('Backend') {
+            //         steps {
+            //             nodejs('node-v14') {
+            //                 sh 'npm run test:back:ci'
+            //             }
+            //         }
+            //     }
+            }
         }
         stage('Build') {
             when { anyOf {

From 5c65314162a8e3d821cf9346ad454828306a7de1 Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Thu, 27 Oct 2022 09:27:50 +0200
Subject: [PATCH 138/151] use findById

---
 back/methods/account/privileges.js | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/back/methods/account/privileges.js b/back/methods/account/privileges.js
index f3f500e7d2..d3aa9bf599 100644
--- a/back/methods/account/privileges.js
+++ b/back/methods/account/privileges.js
@@ -44,16 +44,13 @@ module.exports = Self => {
         if (!user.hasGrant)
             throw new UserError(`You don't have grant privilege`);
 
-        const [userToUpdate] = await models.Account.find({
+        const userToUpdate = await models.Account.findById(id, {
             fields: ['id', 'name', 'hasGrant', 'roleFk', 'password'],
             include: {
                 relation: 'role',
                 scope: {
                     fields: ['name']
                 }
-            },
-            where: {
-                id: id
             }
         }, myOptions);
 

From 9225e8f176c192464bae875f4324ca393ab8734e Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Thu, 27 Oct 2022 15:11:57 +0200
Subject: [PATCH 139/151] fix tests

---
 back/methods/chat/sendCheckingPresence.js     |  4 ++
 .../10500-november/00-deletePickupContact.sql |  1 +
 db/dump/fixtures.sql                          |  8 ++--
 .../back/methods/claim/claimPickupEmail.js    | 41 +++++++++----------
 modules/claim/front/descriptor/index.js       |  5 +--
 modules/claim/front/descriptor/index.spec.js  | 12 +-----
 package.json                                  |  2 +-
 .../claim-pickup-order/claim-pickup-order.js  | 21 +++++-----
 .../email/claim-pickup-order/sql/ticket.sql   |  4 ++
 9 files changed, 47 insertions(+), 51 deletions(-)
 create mode 100644 db/changes/10500-november/00-deletePickupContact.sql
 create mode 100644 print/templates/email/claim-pickup-order/sql/ticket.sql

diff --git a/back/methods/chat/sendCheckingPresence.js b/back/methods/chat/sendCheckingPresence.js
index 3bc022429c..556a16260e 100644
--- a/back/methods/chat/sendCheckingPresence.js
+++ b/back/methods/chat/sendCheckingPresence.js
@@ -25,6 +25,7 @@ module.exports = Self => {
     });
 
     Self.sendCheckingPresence = async(ctx, recipientId, message, options) => {
+        console.log(ctx, recipientId, message, options);
         if (!recipientId) return false;
 
         const myOptions = {};
@@ -38,7 +39,10 @@ module.exports = Self => {
         const recipient = await models.Account.findById(recipientId, null, myOptions);
 
         // Prevent sending messages to yourself
+        console.log('llega');
+        console.log(recipientId, userId);
         if (recipientId == userId) return false;
+        console.log('llega2');
 
         if (!recipient)
             throw new Error(`Could not send message "${message}" to worker id ${recipientId} from user ${userId}`);
diff --git a/db/changes/10500-november/00-deletePickupContact.sql b/db/changes/10500-november/00-deletePickupContact.sql
new file mode 100644
index 0000000000..6bfa662c5e
--- /dev/null
+++ b/db/changes/10500-november/00-deletePickupContact.sql
@@ -0,0 +1 @@
+ALTER TABLE `vn`.`claimConfig` DROP COLUMN `pickupContact`;
diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql
index 9a0a1fff6e..34e592b9a0 100644
--- a/db/dump/fixtures.sql
+++ b/db/dump/fixtures.sql
@@ -1778,10 +1778,10 @@ INSERT INTO `vn`.`claimEnd`(`id`, `saleFk`, `claimFk`, `workerFk`, `claimDestina
         (1, 31, 4, 21, 2),
         (2, 32, 3, 21, 3);
 
-INSERT INTO `vn`.`claimConfig`(`id`, `pickupContact`, `maxResponsibility`)
+INSERT INTO `vn`.`claimConfig`(`id`, `maxResponsibility`)
     VALUES
-        (1, 'Contact description', 50),
-        (2, 'Contact description', 30);
+        (1, 50),
+        (2, 30);
 
 INSERT INTO `vn`.`claimRatio`(`clientFk`, `yearSale`, `claimAmount`, `claimingRate`, `priceIncreasing`, `packingRate`)
     VALUES
@@ -1791,7 +1791,7 @@ INSERT INTO `vn`.`claimRatio`(`clientFk`, `yearSale`, `claimAmount`, `claimingRa
         (1104, 2500, 150.00, 0.02, 0.10, 1.00);
 
 INSERT INTO vn.claimRma (`id`, `code`, `created`, `workerFk`)
-VALUES 
+    VALUES
         (1, '02676A049183', DEFAULT, 1106),
         (2, '02676A049183', DEFAULT, 1106),
         (3, '02676A049183', DEFAULT, 1107),
diff --git a/modules/claim/back/methods/claim/claimPickupEmail.js b/modules/claim/back/methods/claim/claimPickupEmail.js
index 4c9b865025..23f0e31ef7 100644
--- a/modules/claim/back/methods/claim/claimPickupEmail.js
+++ b/modules/claim/back/methods/claim/claimPickupEmail.js
@@ -9,7 +9,7 @@ module.exports = Self => {
                 arg: 'id',
                 type: 'number',
                 required: true,
-                description: 'The client id',
+                description: 'The claim id',
                 http: {source: 'path'}
             },
             {
@@ -29,24 +29,6 @@ module.exports = Self => {
                 type: 'number',
                 description: 'The recipient id to send to the recipient preferred language',
                 required: false
-            },
-            {
-                arg: 'ticketId',
-                type: 'number',
-                description: 'The ticket id',
-                required: true
-            },
-            {
-                arg: 'salesPersonId',
-                type: 'number',
-                description: 'The salesPerson id',
-                required: false
-            },
-            {
-                arg: 'clientName',
-                type: 'string',
-                description: 'The client name',
-                required: true
             }
         ],
         returns: {
@@ -75,14 +57,29 @@ module.exports = Self => {
         for (const param in args)
             params[param] = args[param];
 
+        const claim = await models.Claim.findById(args.id, {
+            fields: ['id', 'clientFk'],
+            include: {
+                relation: 'client',
+                scope: {
+                    fields: ['name', 'salesPersonFk']
+                }
+            }
+        });
+        console.log(claim);
+
         const message = $t('Claim pickup order sent', {
             claimId: args.id,
-            clientName: args.clientName,
+            clientName: claim.client.name,
             claimUrl: `${origin}/#!/claim/${args.id}/summary`,
         });
 
-        if (args.salesPersonId)
-            await models.Chat.sendCheckingPresence(ctx, args.salesPersonId, message);
+        console.log(claim.client());
+        const salesPersonId = claim.client().salesPersonFk;
+        if (claim.client().salesPersonFk)
+            console.log(await models.Chat.sendCheckingPresence(ctx, 25, message));
+
+        console.log(claim.client().salesPersonFk);
 
         await models.ClaimLog.create({
             originFk: args.id,
diff --git a/modules/claim/front/descriptor/index.js b/modules/claim/front/descriptor/index.js
index b36fae3211..0dddadbe14 100644
--- a/modules/claim/front/descriptor/index.js
+++ b/modules/claim/front/descriptor/index.js
@@ -19,10 +19,7 @@ class Controller extends Descriptor {
     sendPickupOrder() {
         return this.vnEmail.send(`Claims/${this.claim.id}/claim-pickup-email`, {
             recipient: this.claim.client.email,
-            recipientId: this.claim.clientFk,
-            clientName: this.claim.client.name,
-            ticketId: this.claim.ticket.id,
-            salesPersonId: this.claim.client.salesPersonFk
+            recipientId: this.claim.clientFk
         });
     }
 
diff --git a/modules/claim/front/descriptor/index.spec.js b/modules/claim/front/descriptor/index.spec.js
index 18ccdaff5e..e6785d3d8a 100644
--- a/modules/claim/front/descriptor/index.spec.js
+++ b/modules/claim/front/descriptor/index.spec.js
@@ -7,12 +7,7 @@ describe('Item Component vnClaimDescriptor', () => {
     const claim = {
         id: 2,
         clientFk: 1101,
-        client: {
-            email: 'client@email',
-            name: 'clientName',
-            salesPersonFk: 18
-        },
-        ticket: {id: 2}
+        client: {email: 'client@email'}
     };
 
     beforeEach(ngModule('claim'));
@@ -45,10 +40,7 @@ describe('Item Component vnClaimDescriptor', () => {
 
             const params = {
                 recipient: claim.client.email,
-                recipientId: claim.clientFk,
-                clientName: claim.client.name,
-                ticketId: claim.ticket.id,
-                salesPersonId: claim.client.salesPersonFk
+                recipientId: claim.clientFk
             };
             controller.sendPickupOrder();
 
diff --git a/package.json b/package.json
index 26c164832a..be6db46a82 100644
--- a/package.json
+++ b/package.json
@@ -38,7 +38,7 @@
         "node-ssh": "^11.0.0",
         "object-diff": "0.0.4",
         "object.pick": "^1.3.0",
-        "puppeteer": "^18.0.5",
+        "puppeteer": "^19.2.0",
         "read-chunk": "^3.2.0",
         "require-yaml": "0.0.1",
         "sharp": "^0.31.0",
diff --git a/print/templates/email/claim-pickup-order/claim-pickup-order.js b/print/templates/email/claim-pickup-order/claim-pickup-order.js
index 51db21cb52..b8804c6040 100755
--- a/print/templates/email/claim-pickup-order/claim-pickup-order.js
+++ b/print/templates/email/claim-pickup-order/claim-pickup-order.js
@@ -8,22 +8,23 @@ module.exports = {
         'email-header': emailHeader.build(),
         'email-footer': emailFooter.build()
     },
-    created() {
-        this.instructions = this.$t('description.instructions', [this.id, this.ticketId]);
+    async serverPrefetch() {
+        this.ticket = await this.fetchTicket(this.id);
+
+        if (!this.ticket)
+            throw new Error('Something went wrong');
+        console.log();
+        this.instructions = this.$t('description.instructions', [this.id, this.ticket.id]);
     },
-    data() {
-        return {
-            instructions: String
-        };
+    methods: {
+        fetchTicket(id) {
+            return this.findOneFromDef('ticket', [id]);
+        }
     },
     props: {
         id: {
             type: [Number, String],
             required: true
-        },
-        ticketId: {
-            type: [Number, String],
-            required: true
         }
     }
 };
diff --git a/print/templates/email/claim-pickup-order/sql/ticket.sql b/print/templates/email/claim-pickup-order/sql/ticket.sql
new file mode 100644
index 0000000000..28b78c9875
--- /dev/null
+++ b/print/templates/email/claim-pickup-order/sql/ticket.sql
@@ -0,0 +1,4 @@
+SELECT
+    c.ticketFk as id
+FROM claim c
+WHERE c.id = ?

From ad1b429d10d1d0d66373f54fbc9c6fafbae57600 Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Fri, 28 Oct 2022 08:09:47 +0200
Subject: [PATCH 140/151] check if user has role from userToUpdate

---
 back/methods/account/privileges.js            | 14 ++++++----
 back/methods/account/specs/privileges.spec.js | 28 +++++++++++++++----
 2 files changed, 31 insertions(+), 11 deletions(-)

diff --git a/back/methods/account/privileges.js b/back/methods/account/privileges.js
index d3aa9bf599..5c5e7409df 100644
--- a/back/methods/account/privileges.js
+++ b/back/methods/account/privileges.js
@@ -41,9 +41,6 @@ module.exports = Self => {
 
         const user = await models.Account.findById(userId, {fields: ['hasGrant']}, myOptions);
 
-        if (!user.hasGrant)
-            throw new UserError(`You don't have grant privilege`);
-
         const userToUpdate = await models.Account.findById(id, {
             fields: ['id', 'name', 'hasGrant', 'roleFk', 'password'],
             include: {
@@ -54,15 +51,22 @@ module.exports = Self => {
             }
         }, myOptions);
 
+        if (!user.hasGrant)
+            throw new UserError(`You don't have grant privilege`);
+
+        const hasRoleFromUser = await models.Account.hasRole(userId, userToUpdate.role().name, myOptions);
+
+        if (!hasRoleFromUser)
+            throw new UserError(`You don't own the role and you can't assign it to another user`);
+
         if (hasGrant != null)
             userToUpdate.hasGrant = hasGrant;
 
         if (roleFk) {
             const role = await models.Role.findById(roleFk, {fields: ['name']}, myOptions);
             const hasRole = await models.Account.hasRole(userId, role.name, myOptions);
-            const hasRoleFromUser = await models.Account.hasRole(userId, userToUpdate.role().name, myOptions);
 
-            if (!hasRole || !hasRoleFromUser)
+            if (!hasRole)
                 throw new UserError(`You don't own the role and you can't assign it to another user`);
 
             userToUpdate.roleFk = roleFk;
diff --git a/back/methods/account/specs/privileges.spec.js b/back/methods/account/specs/privileges.spec.js
index 959130e8b9..edfe0f03f2 100644
--- a/back/methods/account/specs/privileges.spec.js
+++ b/back/methods/account/specs/privileges.spec.js
@@ -4,6 +4,8 @@ describe('account privileges()', () => {
     const employeeId = 1;
     const developerId = 9;
     const sysadminId = 66;
+    const itBossId = 104;
+    const rootId = 100;
     const clarkKent = 1103;
 
     it('should throw an error when user not has privileges', async() => {
@@ -33,12 +35,26 @@ describe('account privileges()', () => {
         try {
             const options = {transaction: tx};
 
-            const root = await models.Role.findOne({
-                where: {
-                    name: 'root'
-                }
-            }, options);
-            await models.Account.privileges(ctx, employeeId, root.id, null, options);
+            await models.Account.privileges(ctx, employeeId, rootId, null, options);
+
+            await tx.rollback();
+        } catch (e) {
+            error = e;
+            await tx.rollback();
+        }
+
+        expect(error.message).toContain(`You don't own the role and you can't assign it to another user`);
+    });
+
+    it('should throw an error when user has privileges but not has the role from user', async() => {
+        const ctx = {req: {accessToken: {userId: sysadminId}}};
+        const tx = await models.Account.beginTransaction({});
+
+        let error;
+        try {
+            const options = {transaction: tx};
+
+            await models.Account.privileges(ctx, itBossId, developerId, null, options);
 
             await tx.rollback();
         } catch (e) {

From 9170c22d6f80515a3251ba003ac8494fc0c5b262 Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Fri, 28 Oct 2022 09:21:28 +0200
Subject: [PATCH 141/151] fix send email

---
 back/methods/chat/sendCheckingPresence.js              |  4 ----
 modules/claim/back/methods/claim/claimPickupEmail.js   | 10 +++-------
 .../email/claim-pickup-order/claim-pickup-order.js     |  2 +-
 3 files changed, 4 insertions(+), 12 deletions(-)

diff --git a/back/methods/chat/sendCheckingPresence.js b/back/methods/chat/sendCheckingPresence.js
index 556a16260e..3bc022429c 100644
--- a/back/methods/chat/sendCheckingPresence.js
+++ b/back/methods/chat/sendCheckingPresence.js
@@ -25,7 +25,6 @@ module.exports = Self => {
     });
 
     Self.sendCheckingPresence = async(ctx, recipientId, message, options) => {
-        console.log(ctx, recipientId, message, options);
         if (!recipientId) return false;
 
         const myOptions = {};
@@ -39,10 +38,7 @@ module.exports = Self => {
         const recipient = await models.Account.findById(recipientId, null, myOptions);
 
         // Prevent sending messages to yourself
-        console.log('llega');
-        console.log(recipientId, userId);
         if (recipientId == userId) return false;
-        console.log('llega2');
 
         if (!recipient)
             throw new Error(`Could not send message "${message}" to worker id ${recipientId} from user ${userId}`);
diff --git a/modules/claim/back/methods/claim/claimPickupEmail.js b/modules/claim/back/methods/claim/claimPickupEmail.js
index 23f0e31ef7..c688d6ded2 100644
--- a/modules/claim/back/methods/claim/claimPickupEmail.js
+++ b/modules/claim/back/methods/claim/claimPickupEmail.js
@@ -66,20 +66,16 @@ module.exports = Self => {
                 }
             }
         });
-        console.log(claim);
 
         const message = $t('Claim pickup order sent', {
             claimId: args.id,
-            clientName: claim.client.name,
+            clientName: claim.client().name,
             claimUrl: `${origin}/#!/claim/${args.id}/summary`,
         });
 
-        console.log(claim.client());
         const salesPersonId = claim.client().salesPersonFk;
-        if (claim.client().salesPersonFk)
-            console.log(await models.Chat.sendCheckingPresence(ctx, 25, message));
-
-        console.log(claim.client().salesPersonFk);
+        if (salesPersonId)
+            await models.Chat.sendCheckingPresence(ctx, salesPersonId, message);
 
         await models.ClaimLog.create({
             originFk: args.id,
diff --git a/print/templates/email/claim-pickup-order/claim-pickup-order.js b/print/templates/email/claim-pickup-order/claim-pickup-order.js
index b8804c6040..29f295b1ee 100755
--- a/print/templates/email/claim-pickup-order/claim-pickup-order.js
+++ b/print/templates/email/claim-pickup-order/claim-pickup-order.js
@@ -13,7 +13,7 @@ module.exports = {
 
         if (!this.ticket)
             throw new Error('Something went wrong');
-        console.log();
+
         this.instructions = this.$t('description.instructions', [this.id, this.ticket.id]);
     },
     methods: {

From 57e74fab38f00017cd2cc41621dfa475b5724e2a Mon Sep 17 00:00:00 2001
From: alexandre <alexandre@verdnatura.es>
Date: Fri, 28 Oct 2022 15:53:57 +0200
Subject: [PATCH 142/151] refs #4716 tipos actualizados

---
 print/templates/email/campaign-metrics/campaign-metrics.js    | 2 +-
 .../templates/email/claim-pickup-order/claim-pickup-order.js  | 2 +-
 .../email/client-debt-statement/client-debt-statement.js      | 2 +-
 print/templates/email/client-welcome/client-welcome.js        | 2 +-
 .../templates/email/delivery-note-link/delivery-note-link.js  | 2 +-
 print/templates/email/delivery-note/delivery-note.js          | 2 +-
 print/templates/email/driver-route/driver-route.js            | 2 +-
 .../email/incoterms-authorization/incoterms-authorization.js  | 4 ++--
 print/templates/email/invoice/invoice.js                      | 2 +-
 print/templates/email/letter-debtor-nd/letter-debtor-nd.js    | 4 ++--
 print/templates/email/letter-debtor-st/letter-debtor-st.js    | 4 ++--
 print/templates/email/payment-update/payment-update.js        | 2 +-
 print/templates/email/printer-setup/printer-setup.js          | 2 +-
 print/templates/email/sepa-core/sepa-core.js                  | 4 ++--
 .../supplier-campaign-metrics/supplier-campaign-metrics.js    | 2 +-
 print/templates/reports/campaign-metrics/campaign-metrics.js  | 2 +-
 .../reports/claim-pickup-order/claim-pickup-order.js          | 2 +-
 .../reports/client-debt-statement/client-debt-statement.js    | 2 +-
 print/templates/reports/delivery-note/delivery-note.js        | 2 +-
 print/templates/reports/driver-route/driver-route.js          | 2 +-
 print/templates/reports/entry-order/entry-order.js            | 2 +-
 print/templates/reports/exportation/exportation.js            | 2 +-
 .../incoterms-authorization/incoterms-authorization.js        | 4 ++--
 .../templates/reports/invoice-incoterms/invoice-incoterms.js  | 2 +-
 print/templates/reports/letter-debtor/letter-debtor.js        | 4 ++--
 print/templates/reports/receipt/receipt.js                    | 2 +-
 print/templates/reports/sepa-core/sepa-core.js                | 4 ++--
 .../supplier-campaign-metrics/supplier-campaign-metrics.js    | 2 +-
 print/templates/reports/zone/zone.js                          | 2 +-
 29 files changed, 36 insertions(+), 36 deletions(-)

diff --git a/print/templates/email/campaign-metrics/campaign-metrics.js b/print/templates/email/campaign-metrics/campaign-metrics.js
index 0c3a01991d..c3ff4a5cac 100755
--- a/print/templates/email/campaign-metrics/campaign-metrics.js
+++ b/print/templates/email/campaign-metrics/campaign-metrics.js
@@ -21,7 +21,7 @@ module.exports = {
     },
     props: {
         id: {
-            type: [Number, String],
+            type: Number,
             required: true
         },
         from: {
diff --git a/print/templates/email/claim-pickup-order/claim-pickup-order.js b/print/templates/email/claim-pickup-order/claim-pickup-order.js
index d3836db392..bdb3386283 100755
--- a/print/templates/email/claim-pickup-order/claim-pickup-order.js
+++ b/print/templates/email/claim-pickup-order/claim-pickup-order.js
@@ -10,7 +10,7 @@ module.exports = {
     },
     props: {
         id: {
-            type: [Number, String],
+            type: Number,
             required: true
         }
     }
diff --git a/print/templates/email/client-debt-statement/client-debt-statement.js b/print/templates/email/client-debt-statement/client-debt-statement.js
index 85b3c5cc3f..06b81199b0 100755
--- a/print/templates/email/client-debt-statement/client-debt-statement.js
+++ b/print/templates/email/client-debt-statement/client-debt-statement.js
@@ -23,7 +23,7 @@ module.exports = {
     },
     props: {
         id: {
-            type: [Number, String],
+            type: Number,
             required: true
         },
         from: {
diff --git a/print/templates/email/client-welcome/client-welcome.js b/print/templates/email/client-welcome/client-welcome.js
index 380837877c..8fcba39adc 100755
--- a/print/templates/email/client-welcome/client-welcome.js
+++ b/print/templates/email/client-welcome/client-welcome.js
@@ -18,7 +18,7 @@ module.exports = {
     },
     props: {
         id: {
-            type: [Number, String],
+            type: Number,
             required: true
         }
     }
diff --git a/print/templates/email/delivery-note-link/delivery-note-link.js b/print/templates/email/delivery-note-link/delivery-note-link.js
index 1804bf1446..8df9826c2f 100755
--- a/print/templates/email/delivery-note-link/delivery-note-link.js
+++ b/print/templates/email/delivery-note-link/delivery-note-link.js
@@ -10,7 +10,7 @@ module.exports = {
     },
     props: {
         id: {
-            type: [Number, String],
+            type: Number,
             required: true
         }
     }
diff --git a/print/templates/email/delivery-note/delivery-note.js b/print/templates/email/delivery-note/delivery-note.js
index ba3d440016..672f70b181 100755
--- a/print/templates/email/delivery-note/delivery-note.js
+++ b/print/templates/email/delivery-note/delivery-note.js
@@ -10,7 +10,7 @@ module.exports = {
     },
     props: {
         id: {
-            type: [Number, String],
+            type: Number,
             required: true
         }
     }
diff --git a/print/templates/email/driver-route/driver-route.js b/print/templates/email/driver-route/driver-route.js
index 0895ccc8c0..fb459fa935 100755
--- a/print/templates/email/driver-route/driver-route.js
+++ b/print/templates/email/driver-route/driver-route.js
@@ -10,7 +10,7 @@ module.exports = {
     },
     props: {
         id: {
-            type: [Number, String],
+            type: Number,
             required: true
         }
     }
diff --git a/print/templates/email/incoterms-authorization/incoterms-authorization.js b/print/templates/email/incoterms-authorization/incoterms-authorization.js
index b1c7286ddf..1665fb5805 100755
--- a/print/templates/email/incoterms-authorization/incoterms-authorization.js
+++ b/print/templates/email/incoterms-authorization/incoterms-authorization.js
@@ -23,12 +23,12 @@ module.exports = {
     },
     props: {
         id: {
-            type: [Number, String],
+            type: Number,
             required: true,
             description: 'The client id'
         },
         companyId: {
-            type: [Number, String],
+            type: Number,
             required: true
         }
     }
diff --git a/print/templates/email/invoice/invoice.js b/print/templates/email/invoice/invoice.js
index fe66062aa1..6720e7102e 100755
--- a/print/templates/email/invoice/invoice.js
+++ b/print/templates/email/invoice/invoice.js
@@ -18,7 +18,7 @@ module.exports = {
     },
     props: {
         reference: {
-            type: [Number, String],
+            type: Number,
             required: true
         }
     }
diff --git a/print/templates/email/letter-debtor-nd/letter-debtor-nd.js b/print/templates/email/letter-debtor-nd/letter-debtor-nd.js
index cf9cc7ddd5..35a7d86557 100755
--- a/print/templates/email/letter-debtor-nd/letter-debtor-nd.js
+++ b/print/templates/email/letter-debtor-nd/letter-debtor-nd.js
@@ -34,11 +34,11 @@ module.exports = {
     },
     props: {
         id: {
-            type: [Number, String],
+            type: Number,
             required: true
         },
         companyId: {
-            type: [Number, String],
+            type: Number,
             required: true
         }
     }
diff --git a/print/templates/email/letter-debtor-st/letter-debtor-st.js b/print/templates/email/letter-debtor-st/letter-debtor-st.js
index 1a65556734..0fd2b45c71 100755
--- a/print/templates/email/letter-debtor-st/letter-debtor-st.js
+++ b/print/templates/email/letter-debtor-st/letter-debtor-st.js
@@ -34,11 +34,11 @@ module.exports = {
     },
     props: {
         id: {
-            type: [Number, String],
+            type: Number,
             required: true
         },
         companyId: {
-            type: [Number, String],
+            type: Number,
             required: true
         },
     }
diff --git a/print/templates/email/payment-update/payment-update.js b/print/templates/email/payment-update/payment-update.js
index a9d99d4ef6..11ace34109 100755
--- a/print/templates/email/payment-update/payment-update.js
+++ b/print/templates/email/payment-update/payment-update.js
@@ -26,7 +26,7 @@ module.exports = {
     },
     props: {
         id: {
-            type: [Number, String],
+            type: Number,
             required: true,
             description: 'The client id'
         }
diff --git a/print/templates/email/printer-setup/printer-setup.js b/print/templates/email/printer-setup/printer-setup.js
index a7d3c40bf9..8de0fc54fc 100755
--- a/print/templates/email/printer-setup/printer-setup.js
+++ b/print/templates/email/printer-setup/printer-setup.js
@@ -24,7 +24,7 @@ module.exports = {
     },
     props: {
         id: {
-            type: [Number, String],
+            type: Number,
             required: true
         }
     }
diff --git a/print/templates/email/sepa-core/sepa-core.js b/print/templates/email/sepa-core/sepa-core.js
index 00cc527dc6..33eb86bce2 100755
--- a/print/templates/email/sepa-core/sepa-core.js
+++ b/print/templates/email/sepa-core/sepa-core.js
@@ -16,11 +16,11 @@ module.exports = {
     },
     props: {
         id: {
-            type: [Number, String],
+            type: Number,
             required: true
         },
         companyId: {
-            type: [Number, String],
+            type: Number,
             required: true
         }
     }
diff --git a/print/templates/email/supplier-campaign-metrics/supplier-campaign-metrics.js b/print/templates/email/supplier-campaign-metrics/supplier-campaign-metrics.js
index 9cb9210ef7..dee227ea2b 100755
--- a/print/templates/email/supplier-campaign-metrics/supplier-campaign-metrics.js
+++ b/print/templates/email/supplier-campaign-metrics/supplier-campaign-metrics.js
@@ -21,7 +21,7 @@ module.exports = {
     },
     props: {
         id: {
-            type: [Number, String],
+            type: Number,
             required: true
         },
         from: {
diff --git a/print/templates/reports/campaign-metrics/campaign-metrics.js b/print/templates/reports/campaign-metrics/campaign-metrics.js
index b60a2b7eb6..7c3913549a 100755
--- a/print/templates/reports/campaign-metrics/campaign-metrics.js
+++ b/print/templates/reports/campaign-metrics/campaign-metrics.js
@@ -25,7 +25,7 @@ module.exports = {
     },
     props: {
         id: {
-            type: [Number, String],
+            type: Number,
             required: true,
             description: 'The client id'
         },
diff --git a/print/templates/reports/claim-pickup-order/claim-pickup-order.js b/print/templates/reports/claim-pickup-order/claim-pickup-order.js
index f7d21a2d39..358adbadd0 100755
--- a/print/templates/reports/claim-pickup-order/claim-pickup-order.js
+++ b/print/templates/reports/claim-pickup-order/claim-pickup-order.js
@@ -36,7 +36,7 @@ module.exports = {
     },
     props: {
         id: {
-            type: [Number, String],
+            type: Number,
             required: true,
             description: 'The claim id'
         }
diff --git a/print/templates/reports/client-debt-statement/client-debt-statement.js b/print/templates/reports/client-debt-statement/client-debt-statement.js
index 80c83b4947..81e9d7f43b 100755
--- a/print/templates/reports/client-debt-statement/client-debt-statement.js
+++ b/print/templates/reports/client-debt-statement/client-debt-statement.js
@@ -69,7 +69,7 @@ module.exports = {
     },
     props: {
         id: {
-            type: [Number, String],
+            type: Number,
             required: true,
             description: 'The client id'
         },
diff --git a/print/templates/reports/delivery-note/delivery-note.js b/print/templates/reports/delivery-note/delivery-note.js
index 1037e51296..7045ef709a 100755
--- a/print/templates/reports/delivery-note/delivery-note.js
+++ b/print/templates/reports/delivery-note/delivery-note.js
@@ -127,7 +127,7 @@ module.exports = {
     },
     props: {
         id: {
-            type: [Number, String],
+            type: Number,
             required: true,
             description: 'The ticket id'
         },
diff --git a/print/templates/reports/driver-route/driver-route.js b/print/templates/reports/driver-route/driver-route.js
index 2de3d51924..0015379419 100755
--- a/print/templates/reports/driver-route/driver-route.js
+++ b/print/templates/reports/driver-route/driver-route.js
@@ -44,7 +44,7 @@ module.exports = {
     },
     props: {
         id: {
-            type: [Number, String],
+            type: Number,
             required: true,
             description: 'The route id'
         }
diff --git a/print/templates/reports/entry-order/entry-order.js b/print/templates/reports/entry-order/entry-order.js
index ff4a65e0cb..18fc4a5ea2 100755
--- a/print/templates/reports/entry-order/entry-order.js
+++ b/print/templates/reports/entry-order/entry-order.js
@@ -40,7 +40,7 @@ module.exports = {
     },
     props: {
         id: {
-            type: [Number, String],
+            type: Number,
             required: true,
             description: 'The entry id'
         }
diff --git a/print/templates/reports/exportation/exportation.js b/print/templates/reports/exportation/exportation.js
index 630baf421b..0aab05feec 100755
--- a/print/templates/reports/exportation/exportation.js
+++ b/print/templates/reports/exportation/exportation.js
@@ -30,7 +30,7 @@ module.exports = {
     },
     props: {
         reference: {
-            type: [Number, String],
+            type: Number,
             required: true,
             description: 'The invoice ref'
         }
diff --git a/print/templates/reports/incoterms-authorization/incoterms-authorization.js b/print/templates/reports/incoterms-authorization/incoterms-authorization.js
index 26637b8c21..3eb5b65ea7 100755
--- a/print/templates/reports/incoterms-authorization/incoterms-authorization.js
+++ b/print/templates/reports/incoterms-authorization/incoterms-authorization.js
@@ -21,12 +21,12 @@ module.exports = {
     },
     props: {
         id: {
-            type: [Number, String],
+            type: Number,
             required: true,
             description: 'The client id'
         },
         companyId: {
-            type: [Number, String],
+            type: Number,
             required: true
         }
     }
diff --git a/print/templates/reports/invoice-incoterms/invoice-incoterms.js b/print/templates/reports/invoice-incoterms/invoice-incoterms.js
index 3dbe76ac32..ba9981373d 100755
--- a/print/templates/reports/invoice-incoterms/invoice-incoterms.js
+++ b/print/templates/reports/invoice-incoterms/invoice-incoterms.js
@@ -32,7 +32,7 @@ module.exports = {
     },
     props: {
         reference: {
-            type: [Number, String],
+            type: Number,
             required: true,
             description: 'The invoice ref'
         }
diff --git a/print/templates/reports/letter-debtor/letter-debtor.js b/print/templates/reports/letter-debtor/letter-debtor.js
index 80d4cba9b6..083d9fd710 100755
--- a/print/templates/reports/letter-debtor/letter-debtor.js
+++ b/print/templates/reports/letter-debtor/letter-debtor.js
@@ -63,12 +63,12 @@ module.exports = {
     },
     props: {
         id: {
-            type: [Number, String],
+            type: Number,
             required: true,
             description: 'The client id'
         },
         companyId: {
-            type: [Number, String],
+            type: Number,
             required: true
         }
     }
diff --git a/print/templates/reports/receipt/receipt.js b/print/templates/reports/receipt/receipt.js
index 401aa1ef36..b368764b16 100755
--- a/print/templates/reports/receipt/receipt.js
+++ b/print/templates/reports/receipt/receipt.js
@@ -25,7 +25,7 @@ module.exports = {
     },
     props: {
         id: {
-            type: [Number, String],
+            type: Number,
             required: true,
             description: 'Receipt id'
         }
diff --git a/print/templates/reports/sepa-core/sepa-core.js b/print/templates/reports/sepa-core/sepa-core.js
index 73e0beaaa3..85121b3921 100755
--- a/print/templates/reports/sepa-core/sepa-core.js
+++ b/print/templates/reports/sepa-core/sepa-core.js
@@ -40,12 +40,12 @@ const rptSepaCore = {
     },
     props: {
         id: {
-            type: [Number, String],
+            type: Number,
             required: true,
             description: 'The client id'
         },
         companyId: {
-            type: [Number, String],
+            type: Number,
             required: true
         }
     }
diff --git a/print/templates/reports/supplier-campaign-metrics/supplier-campaign-metrics.js b/print/templates/reports/supplier-campaign-metrics/supplier-campaign-metrics.js
index 6a58cbd0e3..fee5796d22 100755
--- a/print/templates/reports/supplier-campaign-metrics/supplier-campaign-metrics.js
+++ b/print/templates/reports/supplier-campaign-metrics/supplier-campaign-metrics.js
@@ -49,7 +49,7 @@ module.exports = {
     },
     props: {
         id: {
-            type: [Number, String],
+            type: Number,
             required: true,
             description: 'The supplier id'
         },
diff --git a/print/templates/reports/zone/zone.js b/print/templates/reports/zone/zone.js
index bbce9df36a..d237c50c0c 100755
--- a/print/templates/reports/zone/zone.js
+++ b/print/templates/reports/zone/zone.js
@@ -13,7 +13,7 @@ module.exports = {
     },
     props: {
         id: {
-            type: [Number, String],
+            type: Number,
             required: true,
             description: 'The zone id'
         }

From b5889d2f404bbca837e666e1a0e6098d56c48ff2 Mon Sep 17 00:00:00 2001
From: alexandre <alexandre@verdnatura.es>
Date: Mon, 31 Oct 2022 10:35:43 +0100
Subject: [PATCH 143/151] =?UTF-8?q?refs=20#4497=20servicios=20a=C3=B1adido?=
 =?UTF-8?q?s?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 print/templates/reports/invoice/invoice.html      |  2 +-
 print/templates/reports/invoice/invoice.js        |  2 +-
 print/templates/reports/invoice/locale/en.yml     |  3 ++-
 print/templates/reports/invoice/locale/es.yml     |  3 ++-
 print/templates/reports/invoice/sql/intrastat.sql | 14 ++++++++++++--
 5 files changed, 18 insertions(+), 6 deletions(-)

diff --git a/print/templates/reports/invoice/invoice.html b/print/templates/reports/invoice/invoice.html
index 1d646a0db9..aed4b38f3f 100644
--- a/print/templates/reports/invoice/invoice.html
+++ b/print/templates/reports/invoice/invoice.html
@@ -264,7 +264,7 @@
                                         <tbody>
                                             <tr v-for="row in intrastat">
                                                 <td>{{row.code}}</td>
-                                                <td width="50%">{{row.description}}</td>
+                                                <td width="50%">{{row.description || $t('services') }}</td>
                                                 <td class="number">{{row.stems | number($i18n.locale)}}</td>
                                                 <td class="number">{{row.netKg | number($i18n.locale)}}</td>
                                                 <td class="number">{{row.subtotal | currency('EUR', $i18n.locale)}}</td>
diff --git a/print/templates/reports/invoice/invoice.js b/print/templates/reports/invoice/invoice.js
index db94a7a12e..31df7f7f59 100755
--- a/print/templates/reports/invoice/invoice.js
+++ b/print/templates/reports/invoice/invoice.js
@@ -81,7 +81,7 @@ module.exports = {
             return this.rawSqlFromDef(`taxes`, [reference]);
         },
         fetchIntrastat(reference) {
-            return this.rawSqlFromDef(`intrastat`, [reference, reference, reference]);
+            return this.rawSqlFromDef(`intrastat`, [reference, reference, reference, reference]);
         },
         fetchRectified(reference) {
             return this.rawSqlFromDef(`rectified`, [reference]);
diff --git a/print/templates/reports/invoice/locale/en.yml b/print/templates/reports/invoice/locale/en.yml
index 4e4688b554..336592f0c8 100644
--- a/print/templates/reports/invoice/locale/en.yml
+++ b/print/templates/reports/invoice/locale/en.yml
@@ -33,4 +33,5 @@ issued: Issued
 plantPassport: Plant passport
 observations: Observations
 wireTransfer: "Pay method: Transferencia"
-accountNumber: "Account number: {0}"
\ No newline at end of file
+accountNumber: "Account number: {0}"
+services: Services
\ No newline at end of file
diff --git a/print/templates/reports/invoice/locale/es.yml b/print/templates/reports/invoice/locale/es.yml
index d37e77943f..32f6fc7080 100644
--- a/print/templates/reports/invoice/locale/es.yml
+++ b/print/templates/reports/invoice/locale/es.yml
@@ -33,4 +33,5 @@ issued: F. emisión
 plantPassport: Pasaporte fitosanitario
 observations: Observaciones
 wireTransfer: "Forma de pago: Transferencia"
-accountNumber: "Número de cuenta: {0}"
\ No newline at end of file
+accountNumber: "Número de cuenta: {0}"
+services: Servicios
\ No newline at end of file
diff --git a/print/templates/reports/invoice/sql/intrastat.sql b/print/templates/reports/invoice/sql/intrastat.sql
index e2ee476678..5cc3ebd7f1 100644
--- a/print/templates/reports/invoice/sql/intrastat.sql
+++ b/print/templates/reports/invoice/sql/intrastat.sql
@@ -1,4 +1,4 @@
-SELECT   
+(SELECT   
     ir.id code,
     ir.description description,
     CAST(SUM(IFNULL(i.stems, 1) * s.quantity) AS DECIMAL(10,2)) stems,
@@ -19,4 +19,14 @@ SELECT
         WHERE t.refFk = ?
             AND i.intrastatFk     
         GROUP BY i.intrastatFk
-        ORDER BY i.intrastatFk; 
\ No newline at end of file
+        ORDER BY i.intrastatFk)
+UNION ALL
+(SELECT
+    NULL AS code,
+    NULL AS description,
+    0 AS stems,
+    0 AS netKg,
+    CAST(SUM((ts.quantity * ts.price)) AS DECIMAL(10,2)) AS subtotal
+    FROM vn.ticketService ts
+        JOIN vn.ticket t ON ts.ticketFk = t.id
+    WHERE t.refFk = ?);
\ No newline at end of file

From 463d3e6e1292431b89fb7e4ebc5c017dcfe5cadc Mon Sep 17 00:00:00 2001
From: joan <joan@verdnatura.es>
Date: Mon, 31 Oct 2022 12:39:26 +0100
Subject: [PATCH 144/151] Fixes

---
 modules/claim/back/models/claim-rma.json | 2 +-
 modules/claim/back/models/claim.json     | 8 ++++----
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/modules/claim/back/models/claim-rma.json b/modules/claim/back/models/claim-rma.json
index e3849422c2..27c3c9729e 100644
--- a/modules/claim/back/models/claim-rma.json
+++ b/modules/claim/back/models/claim-rma.json
@@ -8,8 +8,8 @@
     },
     "properties": {
         "id": {
-            "type": "number",
             "id": true,
+            "type": "number",
             "description": "Identifier"
         },
         "code": {
diff --git a/modules/claim/back/models/claim.json b/modules/claim/back/models/claim.json
index 76125c483c..14c4f34526 100644
--- a/modules/claim/back/models/claim.json
+++ b/modules/claim/back/models/claim.json
@@ -57,11 +57,11 @@
             "model": "ClaimState",
             "foreignKey": "claimStateFk"
         },
-        "claimRma": {
-            "type": "belongsTo",
+        "rmas": {
+            "type": "hasMany",
             "model": "ClaimRma",
-            "foreignKey": "rma",
-            "primaryKey": "code"
+            "foreignKey": "code",
+            "primaryKey": "rma"
         },
         "client": {
             "type": "belongsTo",

From ac6fbd07a9e51160d09ab0a694607e598fda740a Mon Sep 17 00:00:00 2001
From: joan <joan@verdnatura.es>
Date: Mon, 31 Oct 2022 13:24:39 +0100
Subject: [PATCH 145/151] Upgraded node version

---
 Dockerfile | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Dockerfile b/Dockerfile
index 9caaa30a1d..378a87f84e 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -13,7 +13,7 @@ RUN apt-get update \
       libgtk-3-0 libnspr4 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 \
       libxcomposite1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 \
       libxtst6 ca-certificates fonts-liberation libappindicator1 libnss3 lsb-release xdg-utils wget \
-    && curl -sL https://deb.nodesource.com/setup_12.x | bash - \
+    && curl -sL https://deb.nodesource.com/setup_14.x | bash - \
     && apt-get install -y --no-install-recommends \
         nodejs \
     && apt-get purge -y --auto-remove \

From a7b1ee85fec2bcd7eab29fed84c642de265224f7 Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Wed, 2 Nov 2022 07:27:57 +0100
Subject: [PATCH 146/151] fix changes folder

---
 .../{10490-goldenSummer => 10500-november}/00-aclNotification.sql | 0
 .../{10490-august => 10500-november}/00-packingSiteConfig.sql     | 0
 .../{10490-august => 10500-november}/00-packingSiteUpdate.sql     | 0
 db/changes/{10490-august => 10500-november}/00-salix_url.sql      | 0
 4 files changed, 0 insertions(+), 0 deletions(-)
 rename db/changes/{10490-goldenSummer => 10500-november}/00-aclNotification.sql (100%)
 rename db/changes/{10490-august => 10500-november}/00-packingSiteConfig.sql (100%)
 rename db/changes/{10490-august => 10500-november}/00-packingSiteUpdate.sql (100%)
 rename db/changes/{10490-august => 10500-november}/00-salix_url.sql (100%)

diff --git a/db/changes/10490-goldenSummer/00-aclNotification.sql b/db/changes/10500-november/00-aclNotification.sql
similarity index 100%
rename from db/changes/10490-goldenSummer/00-aclNotification.sql
rename to db/changes/10500-november/00-aclNotification.sql
diff --git a/db/changes/10490-august/00-packingSiteConfig.sql b/db/changes/10500-november/00-packingSiteConfig.sql
similarity index 100%
rename from db/changes/10490-august/00-packingSiteConfig.sql
rename to db/changes/10500-november/00-packingSiteConfig.sql
diff --git a/db/changes/10490-august/00-packingSiteUpdate.sql b/db/changes/10500-november/00-packingSiteUpdate.sql
similarity index 100%
rename from db/changes/10490-august/00-packingSiteUpdate.sql
rename to db/changes/10500-november/00-packingSiteUpdate.sql
diff --git a/db/changes/10490-august/00-salix_url.sql b/db/changes/10500-november/00-salix_url.sql
similarity index 100%
rename from db/changes/10490-august/00-salix_url.sql
rename to db/changes/10500-november/00-salix_url.sql

From 9891f7060d6d924015e18cf0034e0936daa577c6 Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Wed, 2 Nov 2022 09:40:09 +0100
Subject: [PATCH 147/151] fix(smart-table): monitor only ticketFilter use url
 and add ?q in routes

---
 front/core/components/searchbar/searchbar.js  |  2 +-
 front/core/components/smart-table/index.js    | 20 +++++++++++--------
 modules/claim/front/routes.json               |  6 +++---
 modules/client/front/routes.json              | 14 ++++++-------
 modules/item/front/fixed-price/index.html     | 14 ++++++-------
 modules/item/front/fixed-price/index.js       | 12 ++---------
 .../monitor/front/index/clients/index.html    | 16 ++++++++-------
 modules/route/front/routes.json               |  8 ++++----
 8 files changed, 45 insertions(+), 47 deletions(-)

diff --git a/front/core/components/searchbar/searchbar.js b/front/core/components/searchbar/searchbar.js
index dff4836dbd..10ec1f6085 100644
--- a/front/core/components/searchbar/searchbar.js
+++ b/front/core/components/searchbar/searchbar.js
@@ -290,7 +290,7 @@ export default class Searchbar extends Component {
         }
 
         let where = null;
-        let params = null;
+        let params = {};
 
         if (this.exprBuilder) {
             where = buildFilter(filter,
diff --git a/front/core/components/smart-table/index.js b/front/core/components/smart-table/index.js
index 31541143cc..8d2c3c1531 100644
--- a/front/core/components/smart-table/index.js
+++ b/front/core/components/smart-table/index.js
@@ -19,9 +19,11 @@ export default class SmartTable extends Component {
         this.transclude();
     }
 
-    $onInit() {
-        if (this.model)
+    $onChanges() {
+        if (this.model) {
             this.defaultFilter();
+            this.defaultOrder();
+        }
     }
 
     $onDestroy() {
@@ -53,11 +55,8 @@ export default class SmartTable extends Component {
 
     set model(value) {
         this._model = value;
-        if (value) {
+        if (value)
             this.$.model = value;
-            this.defaultFilter();
-            this.defaultOrder();
-        }
     }
 
     getDefaultViewConfig() {
@@ -168,7 +167,8 @@ export default class SmartTable extends Component {
     }
 
     defaultFilter() {
-        if (!this.$params.q) return;
+        if (this.disabledTableFilter || !this.$params.q) return;
+
         const stateFilter = JSON.parse(this.$params.q).tableQ;
         if (!stateFilter || !this.exprBuilder) return;
 
@@ -188,6 +188,8 @@ export default class SmartTable extends Component {
     }
 
     defaultOrder() {
+        if (this.disabledTableOrder) return;
+
         let stateOrder;
         if (this.$params.q)
             stateOrder = JSON.parse(this.$params.q).tableOrder;
@@ -607,6 +609,8 @@ ngModule.vnComponent('smartTable', {
         autoSave: '<?',
         exprBuilder: '&?',
         defaultNewData: '&?',
-        options: '<?'
+        options: '<?',
+        disabledTableFilter: '<?',
+        disabledTableOrder: '<?',
     }
 });
diff --git a/modules/claim/front/routes.json b/modules/claim/front/routes.json
index d02ea6f6c8..a8b958c5f2 100644
--- a/modules/claim/front/routes.json
+++ b/modules/claim/front/routes.json
@@ -73,7 +73,7 @@
         {
             "url": "/note",
             "state": "claim.card.note",
-            "component": "ui-view", 
+            "component": "ui-view",
             "abstract": true,
             "acl": ["salesPerson"]
         },
@@ -105,7 +105,7 @@
             "acl": ["claimManager"]
         },
         {
-            "url": "/action",
+            "url": "/action?q",
             "state": "claim.card.action",
             "component": "vn-claim-action",
             "description": "Action",
@@ -131,4 +131,4 @@
             "acl": ["claimManager"]
         }
     ]
-}
\ No newline at end of file
+}
diff --git a/modules/client/front/routes.json b/modules/client/front/routes.json
index c7462e46c1..406ca07d7e 100644
--- a/modules/client/front/routes.json
+++ b/modules/client/front/routes.json
@@ -20,7 +20,7 @@
             {"state": "client.card.credit.index", "icon": "credit_card"},
             {"state": "client.card.greuge.index", "icon": "work"},
             {"state": "client.card.balance.index", "icon": "icon-invoice"},
-            {"state": "client.card.recovery.index", "icon": "icon-recovery"}, 
+            {"state": "client.card.recovery.index", "icon": "icon-recovery"},
             {"state": "client.card.webAccess", "icon": "cloud"},
             {"state": "client.card.log", "icon": "history"},
             {
@@ -37,7 +37,7 @@
                     {"state": "client.card.unpaid", "icon": "icon-defaulter"}
                 ]
             }
-        ]  
+        ]
     },
     "keybindings": [
         {"key": "c", "state": "client.index"}
@@ -147,7 +147,7 @@
         {
             "url": "/note",
             "state": "client.card.note",
-            "component": "ui-view", 
+            "component": "ui-view",
             "abstract": true
         },
         {
@@ -236,7 +236,7 @@
                 "client": "$ctrl.client"
             }
         },
-        {            
+        {
             "url": "/create?payed&companyFk&bankFk&payedAmount",
             "state": "client.card.balance.create",
             "component": "vn-client-balance-create",
@@ -406,13 +406,13 @@
             }
         },
         {
-            "url": "/defaulter",
+            "url": "/defaulter?q",
             "state": "client.defaulter",
             "component": "vn-client-defaulter",
             "description": "Defaulter"
         },
         {
-            "url" : "/notification",
+            "url" : "/notification?q",
             "state": "client.notification",
             "component": "vn-client-notification",
             "description": "Notifications"
@@ -424,7 +424,7 @@
             "description": "Unpaid"
         },
         {
-            "url": "/extended-list",
+            "url": "/extended-list?q",
             "state": "client.extendedList",
             "component": "vn-client-extended-list",
             "description": "Extended list"
diff --git a/modules/item/front/fixed-price/index.html b/modules/item/front/fixed-price/index.html
index 8127a76dc1..9498bf96f9 100644
--- a/modules/item/front/fixed-price/index.html
+++ b/modules/item/front/fixed-price/index.html
@@ -23,9 +23,9 @@
 </vn-portal>
 <div class="vn-w-xl">
     <vn-card>
-        <smart-table 
+        <smart-table
             model="model"
-            options="$ctrl.smartTableOptions" 
+            options="$ctrl.smartTableOptions"
             expr-builder="$ctrl.exprBuilder(param, value)">
             <slot-table>
                 <table>
@@ -34,18 +34,18 @@
                             <th field="itemFk">
                                 <span translate>Item ID</span>
                             </th>
-                            <th field="itemName">
+                            <th field="name">
                                 <span translate>Description</span>
                             </th>
                             <th field="warehouseFk">
                                 <span translate>Warehouse</span>
                             </th>
-                            <th 
+                            <th
                                 field="rate2"
                                 vn-tooltip="Price By Unit">
                                 <span translate>P.P.U.</span>
                             </th>
-                            <th 
+                            <th
                                 field="rate3"
                                 vn-tooltip="Price By Package">
                                 <span translate>P.P.P.</span>
@@ -170,7 +170,7 @@
                     </vn-icon-button>
                 </div>
             </slot-table>
-        </smart-table>  
+        </smart-table>
     </vn-card>
 </div>
 <vn-item-descriptor-popover
@@ -182,4 +182,4 @@
     on-accept="$ctrl.removePrice($data.$index)"
     question="Are you sure you want to continue?"
     message="This row will be removed">
-</vn-confirm>
\ No newline at end of file
+</vn-confirm>
diff --git a/modules/item/front/fixed-price/index.js b/modules/item/front/fixed-price/index.js
index b84c2cc2da..89ce0b1728 100644
--- a/modules/item/front/fixed-price/index.js
+++ b/modules/item/front/fixed-price/index.js
@@ -12,14 +12,6 @@ export default class Controller extends Section {
             },
             defaultSearch: true,
             columns: [
-                {
-                    field: 'itemName',
-                    autocomplete: {
-                        url: 'Items',
-                        showField: 'name',
-                        valueField: 'id'
-                    }
-                },
                 {
                     field: 'warehouseFk',
                     autocomplete: {
@@ -105,8 +97,8 @@ export default class Controller extends Section {
 
     exprBuilder(param, value) {
         switch (param) {
-        case 'itemName':
-            return {'i.id': value};
+        case 'name':
+            return {'i.name': {like: `%${value}%`}};
         case 'itemFk':
         case 'warehouseFk':
         case 'rate2':
diff --git a/modules/monitor/front/index/clients/index.html b/modules/monitor/front/index/clients/index.html
index eafc2256ee..381c0e1ae5 100644
--- a/modules/monitor/front/index/clients/index.html
+++ b/modules/monitor/front/index/clients/index.html
@@ -19,22 +19,24 @@
     </vn-none>
 </vn-horizontal>
 <vn-card vn-id="card">
-    <smart-table 
-        model="model" 
-        options="$ctrl.smartTableOptions" 
+    <smart-table
+        model="model"
+        options="$ctrl.smartTableOptions"
         expr-builder="$ctrl.exprBuilder(param, value)"
+        disabled-table-filter="true"
+        disabled-table-order="true"
         class="scrollable sm">
         <slot-actions>
             <vn-horizontal>
                 <vn-date-picker
                     class="vn-pa-xs"
-                    label="From" 
+                    label="From"
                     ng-model="$ctrl.dateFrom"
                     on-change="$ctrl.addFilterDate()">
                 </vn-date-picker>
                 <vn-date-picker
                     class="vn-pa-xs"
-                    label="To" 
+                    label="To"
                     ng-model="$ctrl.dateTo"
                     on-change="$ctrl.addFilterDate()">
                 </vn-date-picker>
@@ -100,9 +102,9 @@
         </slot-pagination>
     </smart-table>
 </vn-card>
-<vn-worker-descriptor-popover 
+<vn-worker-descriptor-popover
     vn-id="workerDescriptor">
 </vn-worker-descriptor-popover>
 <vn-client-descriptor-popover
     vn-id="clientDescriptor">
-</vn-client-descriptor-popover>
\ No newline at end of file
+</vn-client-descriptor-popover>
diff --git a/modules/route/front/routes.json b/modules/route/front/routes.json
index f5e7d9ae85..75e1fdc576 100644
--- a/modules/route/front/routes.json
+++ b/modules/route/front/routes.json
@@ -39,7 +39,7 @@
             "abstract": true,
             "component": "vn-route-card"
         }, {
-            "url": "/agency-term",
+            "url": "/agency-term?q",
             "abstract": true,
             "state": "route.agencyTerm",
             "component": "ui-view"
@@ -49,12 +49,12 @@
             "component": "vn-agency-term-index",
             "description": "Autonomous",
             "acl": ["administrative"]
-        },{            
+        },{
             "url": "/createInvoiceIn?q",
             "state": "route.agencyTerm.createInvoiceIn",
             "component": "vn-agency-term-create-invoice-in",
             "description": "File management",
-            "params": { 
+            "params": {
                 "route": "$ctrl.route"
             },
             "acl": ["administrative"]
@@ -92,4 +92,4 @@
             "acl": ["delivery"]
         }
     ]
-}
\ No newline at end of file
+}

From dc3ee2c30d244caee1df896d893150caeffc3124 Mon Sep 17 00:00:00 2001
From: alexandre <alexandre@verdnatura.es>
Date: Wed, 2 Nov 2022 10:18:38 +0100
Subject: [PATCH 148/151] =?UTF-8?q?refs=20#2818=20sincronizaci=C3=B3n=20qu?=
 =?UTF-8?q?itada=20en=20test?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 modules/account/back/models/ldap-config.js  | 31 +++++++++++++--------
 modules/account/back/models/samba-config.js |  9 ++++--
 2 files changed, 26 insertions(+), 14 deletions(-)

diff --git a/modules/account/back/models/ldap-config.js b/modules/account/back/models/ldap-config.js
index 819659066d..a2a2684a9a 100644
--- a/modules/account/back/models/ldap-config.js
+++ b/modules/account/back/models/ldap-config.js
@@ -5,6 +5,8 @@ const crypto = require('crypto');
 const nthash = require('smbhash').nthash;
 
 module.exports = Self => {
+    const shouldSync = process.env.NODE_ENV !== 'test';
+
     Self.getSynchronizer = async function() {
         return await Self.findOne({
             fields: [
@@ -30,6 +32,7 @@ module.exports = Self => {
         },
 
         async syncUser(userName, info, password) {
+
             let {
                 client,
                 accountConfig
@@ -130,13 +133,14 @@ module.exports = Self => {
                         }));
                     }
 
-                    if (changes.length)
+                    if (shouldSync && changes.length)
                         await client.modify(dn, changes);
-                } else
+                } else if (shouldSync)
                     await client.add(dn, newEntry);
             } else {
                 try {
-                    await client.del(dn);
+                    if (shouldSync)
+                        await client.del(dn);
                     console.log(` -> User '${userName}' removed from LDAP`);
                 } catch (e) {
                     if (e.name !== 'NoSuchObjectError') throw e;
@@ -196,17 +200,19 @@ module.exports = Self => {
                 for (let group of groups) {
                     try {
                         let dn = `cn=${group},${groupDn}`;
-                        await client.modify(dn, new ldap.Change({
-                            operation,
-                            modification: {memberUid: userName}
-                        }));
+                        if (shouldSync) {
+                            await client.modify(dn, new ldap.Change({
+                                operation,
+                                modification: {memberUid: userName}
+                            }));
+                        }
                     } catch (err) {
                         if (err.name !== 'NoSuchObjectError')
                             throw err;
                     }
                 }
             }
-
+            
             await applyOperations(deleteGroups, 'delete');
             await applyOperations(addGroups, 'add');
         },
@@ -266,8 +272,10 @@ module.exports = Self => {
                 filter: 'objectClass=posixGroup'
             };
             let reqs = [];
-            await client.searchForeach(this.groupDn, opts,
-                o => reqs.push(client.del(o.dn)));
+            await client.searchForeach(this.groupDn, opts, object => {
+                if (shouldSync)
+                    reqs.push(client.del(object.dn));
+            });
             await Promise.all(reqs);
 
             // Recreate roles
@@ -291,7 +299,8 @@ module.exports = Self => {
                 }
 
                 let dn = `cn=${role.name},${this.groupDn}`;
-                reqs.push(client.add(dn, newEntry));
+                if (shouldSync)
+                    reqs.push(client.add(dn, newEntry));
             }
             await Promise.all(reqs);
         }
diff --git a/modules/account/back/models/samba-config.js b/modules/account/back/models/samba-config.js
index 5fd62a68b1..168b5ffb47 100644
--- a/modules/account/back/models/samba-config.js
+++ b/modules/account/back/models/samba-config.js
@@ -60,16 +60,19 @@ module.exports = Self => {
             return `cn=Users,${dnBase}`;
         },
 
-        async syncUser(userName, info, password) {
+        async syncUser(userName, info, password) {  
             let {sshClient} = this;
-
+            
             let sambaUser = await this.adClient.searchOne(this.usersDn(), {
                 scope: 'sub',
                 attributes: ['userAccountControl'],
                 filter: `(&(objectClass=user)(sAMAccountName=${userName}))`
             });
             let isEnabled = sambaUser
-                && !(sambaUser.userAccountControl & UserAccountControlFlags.ACCOUNTDISABLE);
+            && !(sambaUser.userAccountControl & UserAccountControlFlags.ACCOUNTDISABLE);
+            
+            if (process.env.NODE_ENV === 'test')
+                return;
 
             if (info.hasAccount) {
                 if (!sambaUser) {

From 59e66e1f49f5445097bbcd343b3a86be95c52b55 Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Wed, 2 Nov 2022 13:55:06 +0100
Subject: [PATCH 149/151] typo

---
 modules/invoiceIn/back/methods/invoice-in/invoiceInPdf.js | 4 ++--
 print/templates/reports/invoiceIn/invoiceIn.js            | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/modules/invoiceIn/back/methods/invoice-in/invoiceInPdf.js b/modules/invoiceIn/back/methods/invoice-in/invoiceInPdf.js
index f1d17dce76..e7962c93f9 100644
--- a/modules/invoiceIn/back/methods/invoice-in/invoiceInPdf.js
+++ b/modules/invoiceIn/back/methods/invoice-in/invoiceInPdf.js
@@ -2,14 +2,14 @@ const {Report} = require('vn-print');
 
 module.exports = Self => {
     Self.remoteMethodCtx('invoiceInPdf', {
-        description: 'Returns the delivery note pdf',
+        description: 'Returns the invoiceIn pdf',
         accessType: 'READ',
         accepts: [
             {
                 arg: 'id',
                 type: 'number',
                 required: true,
-                description: 'The ticket id',
+                description: 'The invoiceIn id',
                 http: {source: 'path'}
             }
         ],
diff --git a/print/templates/reports/invoiceIn/invoiceIn.js b/print/templates/reports/invoiceIn/invoiceIn.js
index cfad062ed9..526c40fc66 100755
--- a/print/templates/reports/invoiceIn/invoiceIn.js
+++ b/print/templates/reports/invoiceIn/invoiceIn.js
@@ -87,7 +87,7 @@ module.exports = {
     },
     props: {
         id: {
-            type: [Number, String],
+            type: Number,
             description: 'The invoice id'
         }
     }

From 6d85cf7cf5bc57cd9e0e0240c7d8e921eb570dcb Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Thu, 3 Nov 2022 08:21:03 +0100
Subject: [PATCH 150/151] translations

---
 modules/invoiceIn/front/descriptor/index.html | 4 ++--
 modules/invoiceIn/front/locale/es.yml         | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/modules/invoiceIn/front/descriptor/index.html b/modules/invoiceIn/front/descriptor/index.html
index 095bbd8e71..819615c20b 100644
--- a/modules/invoiceIn/front/descriptor/index.html
+++ b/modules/invoiceIn/front/descriptor/index.html
@@ -28,12 +28,12 @@
         <vn-item
             ng-click="$ctrl.showPdfInvoice()"
             translate>
-            Show Invoice as PDF
+            Show agricultural invoice as PDF
         </vn-item>
         <vn-item
             ng-click="sendPdfConfirmation.show({email: $ctrl.entity.supplierContact[0].email})"
             translate>
-            Send Invoice as PDF
+            Send agricultural invoice as PDF
         </vn-item>
     </slot-menu>
     <slot-body>
diff --git a/modules/invoiceIn/front/locale/es.yml b/modules/invoiceIn/front/locale/es.yml
index 8cdea3323a..1deff32d32 100644
--- a/modules/invoiceIn/front/locale/es.yml
+++ b/modules/invoiceIn/front/locale/es.yml
@@ -19,5 +19,5 @@ To book: Contabilizar
 Total amount: Total importe
 Total net: Total neto
 Total stems: Total tallos
-Show Invoice as PDF: Ver Factura Agrícola como PDF
-Send Invoice as PDF: Enviar Factura Agrícola como PDF
+Show agricultural invoice as PDF: Ver factura agrícola como PDF
+Send agricultural invoice as PDF: Enviar factura agrícola como PDF

From 8e5f518eb6e60622fefa777bddc5b8c22e40b932 Mon Sep 17 00:00:00 2001
From: alexandre <alexandre@verdnatura.es>
Date: Thu, 3 Nov 2022 14:16:11 +0100
Subject: [PATCH 151/151] refs #4753 texto y fecha sms cambiados

---
 modules/ticket/front/sale/index.js      | 1 +
 modules/ticket/front/sale/locale/en.yml | 2 +-
 modules/ticket/front/sale/locale/es.yml | 2 +-
 3 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/modules/ticket/front/sale/index.js b/modules/ticket/front/sale/index.js
index 6e11b6f4b9..85a862bbb4 100644
--- a/modules/ticket/front/sale/index.js
+++ b/modules/ticket/front/sale/index.js
@@ -377,6 +377,7 @@ class Controller extends Section {
         const params = {
             ticketFk: this.ticket.id,
             created: this.ticket.updated,
+            landed: this.ticket.landed,
             notAvailables
         };
         this.newSMS = {
diff --git a/modules/ticket/front/sale/locale/en.yml b/modules/ticket/front/sale/locale/en.yml
index ec7f541609..b418c086cb 100644
--- a/modules/ticket/front/sale/locale/en.yml
+++ b/modules/ticket/front/sale/locale/en.yml
@@ -1,3 +1,3 @@
 Product not available: >-
-    Verdnatura communicates: Your order {{ticketFk}} created on {{created | date: "dd/MM/yyyy"}}. 
+    Verdnatura communicates: Your order {{ticketFk}} with reception date on {{landed | date: "dd/MM/yyyy"}}. 
     {{notAvailables}} not available. Sorry for the inconvenience.
\ No newline at end of file
diff --git a/modules/ticket/front/sale/locale/es.yml b/modules/ticket/front/sale/locale/es.yml
index aab8ff493d..072e57534d 100644
--- a/modules/ticket/front/sale/locale/es.yml
+++ b/modules/ticket/front/sale/locale/es.yml
@@ -26,7 +26,7 @@ Destination ticket: Ticket destinatario
 Change ticket state to 'Ok': Cambiar estado del ticket a 'Ok'
 Reserved: Reservado
 Send shortage SMS: Enviar SMS faltas
-Product not available: "Verdnatura le comunica:\rPedido {{ticketFk}} día {{created | date: 'dd/MM/yyyy'}}.\r{{notAvailables}} no disponible/s.\rDisculpe las molestias."
+Product not available: "Verdnatura le comunica:\rPedido {{ticketFk}} con fecha recepción {{landed | date: 'dd/MM/yyyy'}}.\r{{notAvailables}} no disponible/s.\rDisculpe las molestias."
 Continue anyway?: ¿Continuar de todas formas?
 This ticket is now empty: El ticket ha quedado vacio
 Do you want to delete it?: ¿Quieres eliminarlo?