diff --git a/Jenkinsfile b/Jenkinsfile
index d3dbfeddb..1e8f3e87f 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -24,6 +24,7 @@ node {
FROM_GIT = env.JOB_NAME.startsWith('gitea/')
RUN_TESTS = !PROTECTED_BRANCH && FROM_GIT
RUN_BUILD = PROTECTED_BRANCH && FROM_GIT
+
// https://www.jenkins.io/doc/book/pipeline/jenkinsfile/#using-environment-variables
echo "NODE_NAME: ${env.NODE_NAME}"
echo "WORKSPACE: ${env.WORKSPACE}"
@@ -206,9 +207,6 @@ pipeline {
when {
expression { FROM_GIT }
}
- environment {
- DOCKER_HOST = "${env.SWARM_HOST}"
- }
steps {
script {
def packageJson = readJSON file: 'package.json'
diff --git a/README.md b/README.md
index 53478f425..b052bd8bf 100644
--- a/README.md
+++ b/README.md
@@ -11,11 +11,16 @@ Required applications.
* Node.js
* Docker
* Git
+* MYT
You will need to install globally the following items.
```
$ sudo npm install -g jest gulp-cli
```
+After installing MYT you will need the following item.
+```
+$ apt install libkrb5-dev libssl-dev
+```
## Installing dependencies and launching
diff --git a/back/methods/chat/sendCheckingPresence.js b/back/methods/chat/sendCheckingPresence.js
index 85b66e94b..7ab5d63fe 100644
--- a/back/methods/chat/sendCheckingPresence.js
+++ b/back/methods/chat/sendCheckingPresence.js
@@ -1,3 +1,5 @@
+const isProduction = require('vn-loopback/server/boot/isProduction');
+
module.exports = Self => {
Self.remoteMethodCtx('sendCheckingPresence', {
description: 'Creates a message in the chat model checking the user status',
@@ -37,7 +39,7 @@ module.exports = Self => {
if (!recipient)
throw new Error(`Could not send message "${message}" to worker id ${recipientId} from user ${userId}`);
- if (process.env.NODE_ENV == 'test')
+ if (!isProduction())
message = `[Test:Environment to user ${userId}] ` + message;
const chat = await models.Chat.create({
diff --git a/back/methods/chat/sendQueued.js b/back/methods/chat/sendQueued.js
index 9a23af379..abda2ddc1 100644
--- a/back/methods/chat/sendQueued.js
+++ b/back/methods/chat/sendQueued.js
@@ -1,4 +1,6 @@
const axios = require('axios');
+const isProduction = require('vn-loopback/server/boot/isProduction');
+
module.exports = Self => {
Self.remoteMethodCtx('sendQueued', {
description: 'Send a RocketChat message',
@@ -94,7 +96,7 @@ module.exports = Self => {
* @return {Promise} - The request promise
*/
Self.sendMessage = async function sendMessage(senderFk, recipient, message) {
- if (process.env.NODE_ENV !== 'production') {
+ if (!isProduction(false)) {
return new Promise(resolve => {
return resolve({
statusCode: 200,
@@ -149,7 +151,7 @@ module.exports = Self => {
* @return {Promise} - The request promise
*/
Self.getUserStatus = async function getUserStatus(username) {
- if (process.env.NODE_ENV !== 'production') {
+ if (!isProduction(false)) {
return new Promise(resolve => {
return resolve({
data: {
diff --git a/back/methods/dms/deleteTrashFiles.js b/back/methods/dms/deleteTrashFiles.js
index 239d654ef..e07f93c90 100644
--- a/back/methods/dms/deleteTrashFiles.js
+++ b/back/methods/dms/deleteTrashFiles.js
@@ -1,6 +1,7 @@
const UserError = require('vn-loopback/util/user-error');
const fs = require('fs-extra');
const path = require('path');
+const isProduction = require('vn-loopback/server/boot/isProduction');
module.exports = Self => {
Self.remoteMethod('deleteTrashFiles', {
@@ -22,7 +23,7 @@ module.exports = Self => {
if (typeof options == 'object')
Object.assign(myOptions, options);
- if (process.env.NODE_ENV == 'test')
+ if (!isProduction())
throw new UserError(`Action not allowed on the test environment`);
const models = Self.app.models;
diff --git a/back/methods/docuware/upload.js b/back/methods/docuware/upload.js
index 27be72295..0102911e0 100644
--- a/back/methods/docuware/upload.js
+++ b/back/methods/docuware/upload.js
@@ -1,5 +1,6 @@
const UserError = require('vn-loopback/util/user-error');
const axios = require('axios');
+const isProduction = require('vn-loopback/server/boot/isProduction');
module.exports = Self => {
Self.remoteMethodCtx('upload', {
@@ -119,7 +120,7 @@ module.exports = Self => {
]
};
- if (process.env.NODE_ENV != 'production')
+ if (!isProduction(false))
throw new UserError('Action not allowed on the test environment');
// delete old
diff --git a/back/methods/image/scrub.js b/back/methods/image/scrub.js
index 99c6bcbf3..3c83b3be7 100644
--- a/back/methods/image/scrub.js
+++ b/back/methods/image/scrub.js
@@ -1,6 +1,7 @@
const fs = require('fs-extra');
const path = require('path');
const UserError = require('vn-loopback/util/user-error');
+const isProduction = require('vn-loopback/server/boot/isProduction');
module.exports = Self => {
Self.remoteMethod('scrub', {
@@ -43,8 +44,7 @@ module.exports = Self => {
Self.scrub = async function(collection, remove, limit, dryRun, skipLock) {
const $ = Self.app.models;
- const env = process.env.NODE_ENV;
- dryRun = dryRun || (env && env !== 'production');
+ dryRun = dryRun || !isProduction(false);
const instance = await $.ImageCollection.findOne({
fields: ['id'],
diff --git a/back/methods/image/upload.js b/back/methods/image/upload.js
index 51da327f6..b3cdfb88b 100644
--- a/back/methods/image/upload.js
+++ b/back/methods/image/upload.js
@@ -1,6 +1,7 @@
const UserError = require('vn-loopback/util/user-error');
const fs = require('fs/promises');
const path = require('path');
+const isProduction = require('vn-loopback/server/boot/isProduction');
module.exports = Self => {
Self.remoteMethodCtx('upload', {
@@ -41,7 +42,7 @@ module.exports = Self => {
if (!hasWriteRole)
throw new UserError(`You don't have enough privileges`);
- if (process.env.NODE_ENV == 'test')
+ if (!isProduction())
throw new UserError(`Action not allowed on the test environment`);
// Upload file to temporary path
diff --git a/back/methods/notification/send.js b/back/methods/notification/send.js
index b2748477d..1bff7f686 100644
--- a/back/methods/notification/send.js
+++ b/back/methods/notification/send.js
@@ -1,4 +1,5 @@
const {Email} = require('vn-print');
+const isProduction = require('vn-loopback/server/boot/isProduction');
module.exports = Self => {
Self.remoteMethod('send', {
@@ -70,7 +71,7 @@ module.exports = Self => {
const newParams = Object.assign({}, queueParams, sendParams);
const email = new Email(queueName, newParams);
- if (process.env.NODE_ENV != 'test')
+ if (isProduction())
await email.send();
await queue.updateAttribute('status', statusSent);
diff --git a/back/methods/vn-user/renew-token.js b/back/methods/vn-user/renew-token.js
index 8e5ffc095..5581d19ac 100644
--- a/back/methods/vn-user/renew-token.js
+++ b/back/methods/vn-user/renew-token.js
@@ -18,15 +18,10 @@ module.exports = Self => {
Self.renewToken = async function(ctx) {
const {accessToken: token} = ctx.req;
- // Check if current token is valid
-
- const {renewPeriod, courtesyTime} = await models.AccessTokenConfig.findOne({
- fields: ['renewPeriod', 'courtesyTime']
+ const {courtesyTime} = await models.AccessTokenConfig.findOne({
+ fields: ['courtesyTime']
});
- const now = Date.now();
- const differenceMilliseconds = now - token.created;
- const differenceSeconds = Math.floor(differenceMilliseconds / 1000);
- const isNotExceeded = differenceSeconds < renewPeriod - courtesyTime;
+ const isNotExceeded = await Self.validateToken(ctx);
if (isNotExceeded)
return token;
diff --git a/back/methods/vn-user/validate-token.js b/back/methods/vn-user/validate-token.js
new file mode 100644
index 000000000..3b75c7c34
--- /dev/null
+++ b/back/methods/vn-user/validate-token.js
@@ -0,0 +1,30 @@
+const {models} = require('vn-loopback/server/server');
+module.exports = Self => {
+ Self.remoteMethodCtx('validateToken', {
+ description: 'Validates the current logged user token',
+ accepts: [],
+ accessType: 'READ',
+ returns: {
+ type: 'Boolean',
+ root: true
+ },
+ http: {
+ path: `/validateToken`,
+ verb: 'GET'
+ }
+ });
+
+ Self.validateToken = async function(ctx) {
+ const {accessToken: token} = ctx.req;
+
+ // Check if current token is valid
+ const {renewPeriod, courtesyTime} = await models.AccessTokenConfig.findOne({
+ fields: ['renewPeriod', 'courtesyTime']
+ });
+ const now = Date.now();
+ const differenceMilliseconds = now - token.created;
+ const differenceSeconds = Math.floor(differenceMilliseconds / 1000);
+ const isNotExceeded = differenceSeconds < renewPeriod - courtesyTime;
+ return isNotExceeded;
+ };
+};
diff --git a/back/model-config.json b/back/model-config.json
index e64386300..b643ab54f 100644
--- a/back/model-config.json
+++ b/back/model-config.json
@@ -186,5 +186,8 @@
},
"AgencyWorkCenter": {
"dataSource": "vn"
+ },
+ "RouteConfig": {
+ "dataSource": "vn"
}
}
diff --git a/back/models/collection.json b/back/models/collection.json
index cb8dc3d7c..8a8afeb89 100644
--- a/back/models/collection.json
+++ b/back/models/collection.json
@@ -1,6 +1,16 @@
{
"name": "Collection",
"base": "VnModel",
+ "properties": {
+ "id": {
+ "id": true,
+ "type": "number",
+ "required": true
+ },
+ "workerFk": {
+ "type": "number"
+ }
+ },
"options": {
"mysql": {
"table": "collection"
diff --git a/back/models/routeConfig.json b/back/models/routeConfig.json
new file mode 100644
index 000000000..f3d929749
--- /dev/null
+++ b/back/models/routeConfig.json
@@ -0,0 +1,18 @@
+{
+ "name": "RouteConfig",
+ "base": "VnModel",
+ "options": {
+ "mysql": {
+ "table": "routeConfig"
+ }
+ },
+ "properties": {
+ "id": {
+ "type": "number",
+ "description": "Identifier"
+ },
+ "kmMax": {
+ "type": "number"
+ }
+ }
+}
diff --git a/back/models/vn-user.js b/back/models/vn-user.js
index b59f13ffa..d38fe5a92 100644
--- a/back/models/vn-user.js
+++ b/back/models/vn-user.js
@@ -15,6 +15,7 @@ module.exports = function(Self) {
require('../methods/vn-user/renew-token')(Self);
require('../methods/vn-user/share-token')(Self);
require('../methods/vn-user/update-user')(Self);
+ require('../methods/vn-user/validate-token')(Self);
Self.definition.settings.acls = Self.definition.settings.acls.filter(acl => acl.property !== 'create');
diff --git a/back/models/vn-user.json b/back/models/vn-user.json
index 5f6ac3f47..8e3304085 100644
--- a/back/models/vn-user.json
+++ b/back/models/vn-user.json
@@ -113,6 +113,13 @@
"principalId": "$everyone",
"permission": "ALLOW"
},
+ {
+ "property": "validateToken",
+ "accessType": "EXECUTE",
+ "principalType": "ROLE",
+ "principalId": "$authenticated",
+ "permission": "ALLOW"
+ },
{
"property": "privileges",
"accessType": "*",
diff --git a/db/dump/fixtures.before.sql b/db/dump/fixtures.before.sql
index 49cb17f0f..6818e7200 100644
--- a/db/dump/fixtures.before.sql
+++ b/db/dump/fixtures.before.sql
@@ -762,7 +762,12 @@ INSERT INTO `vn`.`ticket`(`id`, `priority`, `agencyModeFk`,`warehouseFk`,`routeF
(30, 1, 8, 1, 1, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1103, 'Phone Box', 123, NULL, 0, 1, 5, 1, util.VN_CURDATE(), NULL, NULL),
(31, 1, 8, 1, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), DATE_ADD(util.VN_CURDATE(), INTERVAL + 2 DAY), 1103, 'Phone Box', 123, NULL, 0, 1, 5, 1, util.VN_CURDATE(), NULL, NULL),
(32, 1, 8, 1, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), DATE_ADD(util.VN_CURDATE(), INTERVAL + 2 DAY), 1103, 'Phone Box', 123, NULL, 0, 1, 5, 1, util.VN_CURDATE(), NULL, NULL),
- (33, 1, 7, 1, 6, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1102, 'NY roofs', 122, NULL, 0, 3, 5, 1, util.VN_CURDATE(), NULL, NULL);
+ (33, 1, 7, 1, 6, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1102, 'NY roofs', 122, NULL, 0, 3, 5, 1, util.VN_CURDATE(), NULL, NULL),
+ (34, 1, 1, 1, 3, util.VN_CURDATE(), util.VN_CURDATE(), 1103, 'BEJAR', 123, NULL, 0, 1, 16, 0, util.VN_CURDATE(), NULL, NULL),
+ (35, 1, 1, 1, 3, util.VN_CURDATE(), util.VN_CURDATE(), 1102, 'Somewhere in Philippines', 123, NULL, 0, 1, 16, 0, util.VN_CURDATE(), NULL, NULL),
+ (36, 1, 1, 1, 3, util.VN_CURDATE(), util.VN_CURDATE(), 1102, 'Ant-Man Adventure', 123, NULL, 0, 1, 16, 0, util.VN_CURDATE(), NULL, NULL),
+ (37, 1, 1, 1, 3, util.VN_CURDATE(), util.VN_CURDATE(), 1110, 'Deadpool swords', 123, NULL, 0, 1, 16, 0, util.VN_CURDATE(), NULL, NULL);
+
INSERT INTO `vn`.`ticketObservation`(`id`, `ticketFk`, `observationTypeFk`, `description`)
VALUES
(1, 11, 1, 'ready'),
@@ -808,7 +813,10 @@ INSERT INTO `vn`.`ticketTracking`(`ticketFk`, `stateFk`, `userFk`, `created`)
(21, 1, 19, DATE_ADD(util.VN_NOW(), INTERVAL +1 MONTH)),
(22, 1, 19, DATE_ADD(util.VN_NOW(), INTERVAL +1 MONTH)),
(23, 16, 21, util.VN_NOW()),
- (24, 16, 21, util.VN_NOW());
+ (24, 16, 21, util.VN_NOW()),
+ (34, 14, 49, util.VN_NOW()),
+ (35, 14, 18, util.VN_NOW()),
+ (36, 14, 18, util.VN_NOW());
INSERT INTO `vn`.`deliveryPoint` (`id`, `name`, `ubication`)
VALUES
@@ -1068,7 +1076,10 @@ INSERT INTO `vn`.`sale`(`id`, `itemFk`, `ticketFk`, `concept`, `quantity`, `pric
(37, 4, 31, 'Melee weapon heavy shield 100cm', 20, 1.72, 0, 0, 0, util.VN_CURDATE()),
(36, 4, 30, 'Melee weapon heavy shield 100cm', 20, 1.72, 0, 0, 0, util.VN_CURDATE()),
(38, 2, 32, 'Melee weapon combat fist 15cm', 30, 7.07, 0, 0, 0, DATE_ADD(util.VN_CURDATE(), INTERVAL +1 MONTH)),
- (39, 1, 32, 'Ranged weapon longbow 200cm', 2, 103.49, 0, 0, 0, util.VN_CURDATE());
+ (39, 1, 32, 'Ranged weapon longbow 200cm', 2, 103.49, 0, 0, 0, util.VN_CURDATE()),
+ (40, 2, 34, 'Melee weapon combat fist 15cm', 10.00, 3.91, 0, 0, 0, util.VN_CURDATE()),
+ (41, 2, 35, 'Melee weapon combat fist 15cm', 8.00, 3.01, 0, 0, 0, util.VN_CURDATE()),
+ (42, 2, 36, 'Melee weapon combat fist 15cm', 6.00, 2.50, 0, 0, 0, util.VN_CURDATE());
INSERT INTO `vn`.`saleComponent`(`saleFk`, `componentFk`, `value`)
VALUES
@@ -1205,11 +1216,11 @@ INSERT INTO `vn`.`saleComponent`(`saleFk`, `componentFk`, `value`)
(32, 36, -92.324),
(32, 39, 0.994);
-INSERT INTO `vn`.`itemShelving` (`itemFk`, `shelvingFk`, `visible`, `grouping`, `packing`, `userFk`)
+INSERT INTO `vn`.`itemShelving` (`itemFk`, `shelvingFk`, `visible`, `grouping`, `packing`,`buyFk`, `userFk`)
VALUES
- (2, 'GVC', 1, 1, 1, 1106),
- (4, 'HEJ', 1, 1, 1, 1106),
- (1, 'UXN', 2, 12, 12, 1106);
+ (2, 'GVC', 1, 1, 1, 2,1106),
+ (4, 'HEJ', 1, 1, 1, NULL,1106),
+ (1, 'UXN', 2, 12, 12, NULL,1106);
INSERT INTO `vn`.`itemShelvingSale` (`itemShelvingFk`, `saleFk`, `quantity`, `created`, `userFk`)
VALUES
@@ -1247,14 +1258,20 @@ INSERT INTO `vn`.`operator` (`workerFk`, `numberOfWagons`, `trainFk`, `itemPacki
INSERT INTO `vn`.`collection`(`id`, `workerFk`, `stateFk`, `created`, `trainFk`)
VALUES
(1, 1106, 5, DATE_ADD(util.VN_CURDATE(),INTERVAL +1 DAY), 1),
- (2, 1106, 14, util.VN_CURDATE(), 1);
+ (2, 1106, 14, util.VN_CURDATE(), 1),
+ (4, 49, 5, util.VN_CURDATE(), 1),
+ (5, 18, 5, util.VN_CURDATE(), 1),
+ (6, 18, 5, util.VN_CURDATE(), 1);
INSERT INTO `vn`.`ticketCollection`(`ticketFk`, `collectionFk`, `level`)
VALUES
(1, 1, 1),
(2, 1, NULL),
(3, 2, NULL),
- (23, 1, NULL);
+ (23, 1, NULL),
+ (34, 4, 1),
+ (35, 5, 1),
+ (8, 6, 1);
INSERT INTO `vn`.`genus`(`id`, `name`)
VALUES
@@ -3705,7 +3722,8 @@ INSERT IGNORE INTO vn.saleGroup
SET id = 4,
userFk = 1,
parkingFk = 9,
- sectorFk = 9992;
+ sectorFk = 9992,
+ ticketFk = 36;
INSERT IGNORE INTO vn.sectorCollectionSaleGroup
SET id = 9999,
@@ -3807,3 +3825,27 @@ INSERT INTO `vn`.`ledgerCompany` SET
INSERT INTO `vn`.`ledgerConfig` SET
maxTolerance = 0.01;
+
+INSERT INTO vn.sectorCollection
+ SET id = 2,
+ userFk = 18,
+ sectorFk = 1;
+
+INSERT INTO vn.sectorCollectionSaleGroup
+ SET id = 8,
+ sectorCollectionFk = 2,
+ saleGroupFk = 4;
+
+INSERT INTO vn.saleGroup (userFk, parkingFk, sectorFk, ticketFk)
+ VALUES
+ (1, 1, 1, 37);
+
+INSERT INTO vn.sectorCollection
+ SET id = 3,
+ userFk = 18,
+ sectorFk = 1;
+
+INSERT INTO vn.sectorCollectionSaleGroup
+ SET id = 9,
+ sectorCollectionFk = 3,
+ saleGroupFk = 6;
\ No newline at end of file
diff --git a/db/routines/edi/procedures/ekt_scan.sql b/db/routines/edi/procedures/ekt_scan.sql
index b0b75a6a7..0cf8bb466 100644
--- a/db/routines/edi/procedures/ekt_scan.sql
+++ b/db/routines/edi/procedures/ekt_scan.sql
@@ -23,42 +23,39 @@ BEGIN
DECLARE vXtraLongAgj INT;
DECLARE vDefaultKlo INT;
- SELECT
- ec.usefulAuctionLeftSegmentLength,
- ec.standardBarcodeLength,
- ec.floridayBarcodeLength,
- ec.floramondoBarcodeLength,
- ec.defaultKlo
- INTO
- vUsefulAuctionLeftSegmentLength,
+ SELECT usefulAuctionLeftSegmentLength,
+ standardBarcodeLength,
+ floridayBarcodeLength,
+ floramondoBarcodeLength,
+ defaultKlo
+ INTO vUsefulAuctionLeftSegmentLength,
vStandardBarcodeLength,
vFloridayBarcodeLength,
vFloramondoBarcodeLength,
vDefaultKlo
- FROM edi.ektConfig ec;
+ FROM ektConfig;
- DROP TEMPORARY TABLE IF EXISTS tmp.ekt;
- CREATE TEMPORARY TABLE tmp.ekt
+ CREATE OR REPLACE TEMPORARY TABLE tmp.ekt
ENGINE = MEMORY
SELECT id ektFk FROM ekt LIMIT 0;
- CASE
+ CASE
WHEN LENGTH(vBarcode) <= vFloridayBarcodeLength THEN
INSERT INTO tmp.ekt
SELECT id
- FROM edi.ektRecent e
+ FROM ektRecent e
WHERE e.cps = vBarcode
OR e.batchNumber = vBarcode;
WHEN LENGTH(vBarcode) = vFloramondoBarcodeLength THEN
INSERT INTO tmp.ekt
SELECT e.id
- FROM edi.ektRecent e
+ FROM ektRecent e
WHERE e.pro = MID(vBarcode,2,6)
- AND CAST(e.ptd AS SIGNED) = MID(vBarcode,8,5);
+ AND CAST(e.ptd AS SIGNED) = MID(vBarcode, 8, 5);
ELSE
- SET vBarcode = LPAD(vBarcode,vStandardBarcodeLength,'0');
+ SET vBarcode = LPAD(vBarcode, vStandardBarcodeLength, '0');
SET vAuction = MID(vBarcode, 1, 3);
SET vKlo = MID(vBarcode, 4, 2);
SET vFec = MAKEDATE(YEAR(util.VN_CURDATE()), MID(vBarcode, 6, 3));
@@ -69,21 +66,23 @@ BEGIN
-- Clásico de subasta
-- Trade standard
-- Trade que construye como la subasta
- -- Trade como el anterior pero sin trade code
+ -- Trade como el anterior pero sin trade code
INSERT INTO tmp.ekt
SELECT id
FROM ekt
WHERE fec >= vFec - INTERVAL 1 DAY
- AND ((
- vKlo = vDefaultKlo
+ AND (
+ (vKlo = vDefaultKlo
AND (klo = vKlo OR klo IS NULL OR klo = 0)
- AND agj IN (vShortAgj, vLongAgj, vXtraLongAgj))
- OR (klo = vKlo
+ AND agj IN (vShortAgj, vLongAgj, vXtraLongAgj)
+ ) OR (
+ klo = vKlo
AND auction = vAuction
- AND agj = vShortAgj)
+ AND agj = vShortAgj
+ )
)
- ORDER BY agj DESC, fec DESC
- LIMIT 1;
+ ORDER BY agj DESC, fec DESC
+ LIMIT 1;
SELECT COUNT(*) FROM tmp.ekt INTO vIsFound;
@@ -91,9 +90,11 @@ BEGIN
IF NOT vIsFound THEN
INSERT INTO tmp.ekt
SELECT id
- FROM edi.ektRecent e
- WHERE e.batchNumber
- = LEFT(vBarcode,vUsefulAuctionLeftSegmentLength)
+ FROM ektRecent e
+ WHERE e.batchNumber = LEFT(
+ vBarcode,
+ vUsefulAuctionLeftSegmentLength
+ )
AND e.batchNumber > 0;
SELECT COUNT(*) FROM tmp.ekt INTO vIsFound;
@@ -103,7 +104,7 @@ BEGIN
IF NOT vIsFound THEN
INSERT INTO tmp.ekt
SELECT id
- FROM edi.ektRecent e
+ FROM ektRecent e
WHERE e.putOrderFk = vBarcode;
SELECT COUNT(*) FROM tmp.ekt INTO vIsFound;
@@ -113,18 +114,28 @@ BEGIN
IF NOT vIsFound THEN
INSERT INTO tmp.ekt
SELECT id
- FROM edi.ektRecent e
- WHERE e.deliveryNumber
- = MID(vBarcode, 4, 13)
+ FROM ektRecent e
+ WHERE e.deliveryNumber = MID(vBarcode, 4, 13)
AND e.deliveryNumber > 0;
SELECT COUNT(*) FROM tmp.ekt INTO vIsFound;
END IF;
+
+ -- Solo campo agj
+ IF NOT vIsFound THEN
+ INSERT INTO tmp.ekt
+ SELECT id
+ FROM ektRecent
+ WHERE agj = vShortAgj;
+
+ SELECT COUNT(*) FROM tmp.ekt INTO vIsFound;
+ END IF;
+
END CASE;
IF vIsFound THEN
UPDATE ekt e
- JOIN tmp.ekt t ON t.ektFk = e.id
+ JOIN tmp.ekt t ON t.ektFk = e.id
SET e.scanned = TRUE;
END IF;
END$$
diff --git a/db/routines/floranet/procedures/catalogue_get.sql b/db/routines/floranet/procedures/catalogue_get.sql
index 32624f383..7ce32cfac 100644
--- a/db/routines/floranet/procedures/catalogue_get.sql
+++ b/db/routines/floranet/procedures/catalogue_get.sql
@@ -40,19 +40,28 @@ proc:BEGIN
postalCode,
`type`,
image,
- description
+ description,
+ addressFk
)
- SELECT i.name,
- i.`size`,
- i.id,
+ SELECT CONCAT(i.name, ' by ',a.nickname),
+ r.price + apc.deliveryCost,
+ r.itemFk,
vLanded,
vPostalCode,
it.name,
CONCAT('https://cdn.verdnatura.es/image/catalog/1600x900/', i.image),
- i.description
+ i.description,
+ apc.addressFk
FROM vn.item i
+ JOIN (SELECT itemFk, SUM(quantity * cost) price
+ FROM recipe
+ GROUP BY itemFk) r ON r.itemFk = i.id
JOIN vn.itemType it ON it.id = i.typeFk
- WHERE it.code IN ('FNR','FNP');
+ JOIN addressPostCode apc
+ ON apc.dayOfWeek = dayOfWeek(vLanded)
+ AND NOW() < vLanded - INTERVAL apc.hoursInAdvance HOUR
+ AND apc.postCode = vPostalCode
+ JOIN vn.address a ON a.id = apc.addressFk;
SELECT *
FROM catalogue
diff --git a/db/routines/floranet/procedures/contact_request.sql b/db/routines/floranet/procedures/contact_request.sql
index 2ca25b87d..2132a86fc 100644
--- a/db/routines/floranet/procedures/contact_request.sql
+++ b/db/routines/floranet/procedures/contact_request.sql
@@ -13,8 +13,17 @@ BEGIN
/**
* Set actions for contact request
*
- * @param vPostalCode Delivery address postal code
+ * @param vName Name
+ * @param vPhone Phone number
+ * @param vEmail e-mail
+ * @param vMessage text of the message
*/
-
+
+ CALL vn.mail_insert(
+ 'floranet@verdnatura.es',
+ vEmail,
+ 'Contact request',
+ CONCAT('Phone: ',vPhone, ' Message: ', vMessage)
+ );
END$$
DELIMITER ;
\ No newline at end of file
diff --git a/db/routines/floranet/procedures/deliveryDate_get.sql b/db/routines/floranet/procedures/deliveryDate_get.sql
index 75e9d6257..a235e8c31 100644
--- a/db/routines/floranet/procedures/deliveryDate_get.sql
+++ b/db/routines/floranet/procedures/deliveryDate_get.sql
@@ -21,7 +21,7 @@ BEGIN
apc.dayOfWeek - vCurrentDayOfWeek,
7 - apc.dayOfWeek
) DAY nextDay,
- NOW() + INTERVAL apc.hoursInAdvance - 12 HOUR minDeliveryTime
+ NOW() + INTERVAL apc.hoursInAdvance HOUR minDeliveryTime
FROM addressPostCode apc
WHERE apc.postCode = vPostalCode
HAVING nextDay > minDeliveryTime) sub;
diff --git a/db/routines/floranet/procedures/order_confirm.sql b/db/routines/floranet/procedures/order_confirm.sql
index b6aec033d..3b9413da9 100644
--- a/db/routines/floranet/procedures/order_confirm.sql
+++ b/db/routines/floranet/procedures/order_confirm.sql
@@ -1,25 +1,167 @@
-DROP PROCEDURE IF EXISTS floranet.order_confirm;
-
DELIMITER $$
$$
-CREATE DEFINER=`root`@`localhost`PROCEDURE floranet.order_confirm(vCatalogueFk INT)
+CREATE OR REPLACE DEFINER=`root`@`localhost`PROCEDURE floranet.order_confirm(vCatalogueFk INT)
READS SQL DATA
-BEGIN
-/** Update order.isPaid field.
+proc:BEGIN
+/** Update order.isPaid field, and makes the ticket
*
* @param vCatalogueFk floranet.catalogue.id
*
* @returns floranet.order.isPaid
*/
+ DECLARE vNewTicketFk INT;
+ DECLARE vCustomerEmail VARCHAR(255);
+ DECLARE vFloranetEmail VARCHAR(255);
+ DECLARE vSubjectEmail VARCHAR(100);
+ DECLARE vBodyEmail TEXT;
+ DECLARE vZoneFk INT;
+
+ DECLARE exit handler FOR SQLEXCEPTION
+ BEGIN
+ ROLLBACK;
+
+ GET DIAGNOSTICS CONDITION 2 @errno = MYSQL_ERRNO, @text = MESSAGE_TEXT;
+
+ SELECT CONCAT('ERROR ', IFNULL(@errno,0), ': ', ifnull(@text,'texto')) AS `SQLEXCEPTION`;
+
+ CALL vn.mail_insert(
+ 'floranet@verdnatura.es,pako@verdnatura.es',
+ 'noreply@verdnatura.es',
+ 'Floranet.order_confirm failure',
+ CONCAT('CatalogueFk: ', vCatalogueFk, '\n','ERROR ', IFNULL(@errno, 0), ': ', ifnull(@text, 'texto'))
+ );
+ END;
+
+ IF (SELECT isPaid FROM `order` WHERE catalogueFk = vCatalogueFk) THEN
+ SELECT CONCAT('CatalogueFk: ', vCatalogueFk, ' Esta orden ya está confirmada') AS `ERROR`;
+ LEAVE proc;
+ END IF;
+
+ START TRANSACTION;
+
UPDATE `order`
SET isPaid = TRUE,
payed = NOW()
WHERE catalogueFk = vCatalogueFk;
- SELECT isPaid
+ SELECT zoneFk
+ INTO vZoneFk
+ FROM (
+ SELECT zoneFk, COUNT(*) totalCount
+ FROM vn.ticket t
+ JOIN catalogue c ON c.id = vCatalogueFk
+ WHERE t.shipped > util.VN_CURDATE() - INTERVAL 1 YEAR
+ AND t.addressFk = c.addressFk
+ GROUP BY zoneFk
+ ORDER BY totalCount DESC
+ LIMIT 10000000000000000000
+ ) sub
+ LIMIT 1;
+
+ INSERT INTO vn.ticket (
+ clientFk,
+ shipped,
+ addressFk,
+ agencyModeFk,
+ nickname,
+ warehouseFk,
+ routeFk,
+ companyFk,
+ landed,
+ zoneFk
+ )
+ SELECT a.clientFk,
+ c.dated - INTERVAL 1 DAY,
+ c.addressFk,
+ a.agencyModeFk,
+ a.nickname,
+ ag.warehouseFk,
+ NULL,
+ co.id,
+ c.dated,
+ vZoneFk
+ FROM vn.address a
+ JOIN vn.agencyMode am ON am.id = a.agencyModeFk
+ JOIN vn.agency ag ON ag.id = am.agencyFk
+ JOIN catalogue c ON c.addressFk = a.id
+ JOIN vn.company co ON co.code = 'VNL'
+ WHERE c.id = vCatalogueFk;
+
+ SET vNewTicketFk = LAST_INSERT_ID();
+
+ INSERT INTO vn.sale(
+ ticketFk,
+ itemFk,
+ concept,
+ price,
+ quantity)
+ SELECT
+ vNewTicketFk,
+ c.itemFk,
+ CONCAT('Entrega: ',c.name),
+ - c.price,
+ 1
+ FROM catalogue c
+ JOIN addressPostCode apc
+ ON apc.addressFk = c.addressFk
+ AND apc.dayOfWeek = dayOfWeek(c.dated)
+ WHERE c.id = vCatalogueFk;
+
+ INSERT INTO vn.sale(
+ ticketFk,
+ itemFk,
+ concept,
+ price,
+ quantity)
+ SELECT
+ vNewTicketFk,
+ r.elementFk,
+ i.longName,
+ r.cost,
+ r.quantity
+ FROM catalogue c
+ JOIN recipe r ON r.itemFk = c.itemFk
+ JOIN vn.item i ON i.id = r.elementFk
+ WHERE c.id = vCatalogueFk;
+
+ SELECT cl.email,
+ cf.email,
+ CONCAT('Nuevo pedido FLORANET para entrega el ',c.dated),
+ CONCAT_WS('\n',
+ CONCAT('Producto: ', c.name),
+ CONCAT('Fecha de entrega: ',c.dated),
+ CONCAT('Destinatario: ', o.deliveryName),
+ CONCAT('Dirección: ', o.address),
+ CONCAT('CP: ', c.postalCode),
+ CONCAT('Foto: ', c.image),
+ CONCAT('Mensaje: ', IFNULL(o.message,"Ninguno.")),
+ CONCAT('Teléfono: ',IFNULL(o.deliveryPhone,"--")),
+ CONCAT('Observaciones: ', IFNULL(o.observations,"No hay."))
+ )
+ INTO vCustomerEmail,
+ vFloranetEmail,
+ vSubjectEmail,
+ vBodyEmail
+ FROM vn.client cl
+ JOIN vn.address a ON a.clientFk = cl.id
+ JOIN catalogue c ON c.addressFk = a.id
+ JOIN `order` o ON o.catalogueFk = c.id
+ JOIN config cf
+ WHERE c.id = vCatalogueFk;
+
+ CALL vn.mail_insert(
+ vCustomerEmail,
+ vFloranetEmail,
+ vSubjectEmail,
+ vBodyEmail);
+
+ SELECT isPaid, vNewTicketFk
FROM `order`
WHERE catalogueFk = vCatalogueFk;
+
+ COMMIT;
+
END$$
DELIMITER ;
\ No newline at end of file
diff --git a/db/routines/floranet/procedures/order_put.sql b/db/routines/floranet/procedures/order_put.sql
index 979588f8f..c5eb71472 100644
--- a/db/routines/floranet/procedures/order_put.sql
+++ b/db/routines/floranet/procedures/order_put.sql
@@ -7,7 +7,7 @@ BEGIN
*
* @param vJsonData The order data in json format
*/
- INSERT INTO `order`
+ REPLACE `order`
SET catalogueFk = JSON_UNQUOTE(JSON_EXTRACT(vJsonData, '$.customer.customerData.products[0].id')),
customerName = JSON_UNQUOTE(JSON_EXTRACT(vJsonData, '$.customer.customerData.customerName')),
email = JSON_UNQUOTE(JSON_EXTRACT(vJsonData, '$.customer.customerData.email')),
@@ -15,7 +15,8 @@ BEGIN
message= JSON_UNQUOTE(JSON_EXTRACT(vJsonData, '$.customer.customerData.message')),
deliveryName = JSON_UNQUOTE(JSON_EXTRACT(vJsonData, '$.customer.customerData.deliveryName')),
address = JSON_UNQUOTE(JSON_EXTRACT(vJsonData, '$.customer.customerData.address')),
- deliveryPhone = JSON_UNQUOTE(JSON_EXTRACT(vJsonData, '$.customer.customerData.deliveryPhone'));
+ deliveryPhone = JSON_UNQUOTE(JSON_EXTRACT(vJsonData, '$.customer.customerData.deliveryPhone')),
+ observations = JSON_UNQUOTE(JSON_EXTRACT(vJsonData, '$.customer.customerData.observations'));
SELECT LAST_INSERT_ID() orderFk;
END$$
diff --git a/db/routines/floranet/procedures/sliders_get.sql b/db/routines/floranet/procedures/sliders_get.sql
index 0e4aa297a..bafda4732 100644
--- a/db/routines/floranet/procedures/sliders_get.sql
+++ b/db/routines/floranet/procedures/sliders_get.sql
@@ -9,12 +9,11 @@ BEGIN
* Returns list of url for sliders.
*/
SELECT
- CONCAT('https://cdn.verdnatura.es/image/catalog/1600x900/', i.image) url,
- i.longName
- FROM vn.item i
- JOIN vn.itemType it ON it.id = i.typeFk
- WHERE it.code IN ('FNR','FNP')
- LIMIT 3;
-
+ CONCAT('https://cdn.verdnatura.es/image/catalog/1600x900/', i.image) url,
+ i.longName
+ FROM vn.item i
+ JOIN vn.itemType it ON it.id = i.typeFk
+ WHERE it.code IN ('FNR','FNP')
+ LIMIT 3;
END$$
DELIMITER ;
\ No newline at end of file
diff --git a/db/routines/vn/procedures/itemShelvingTransfer.sql b/db/routines/vn/procedures/itemShelvingTransfer.sql
index 326f8108b..ae82bfe9d 100644
--- a/db/routines/vn/procedures/itemShelvingTransfer.sql
+++ b/db/routines/vn/procedures/itemShelvingTransfer.sql
@@ -17,13 +17,15 @@ BEGIN
SELECT
itemFk,
packing,
- created
+ created,
+ buyFk
FROM itemShelving
WHERE id = vItemShelvingFk
) ish2
ON ish2.itemFk = ish.itemFk
AND ish2.packing = ish.packing
AND date(ish2.created) = date(ish.created)
+ AND ish2.buyFk = ish.buyFk
WHERE ish.shelvingFk = vShelvingFk COLLATE utf8_unicode_ci;
IF vNewItemShelvingFk THEN
diff --git a/db/routines/vn/procedures/itemShelving_add.sql b/db/routines/vn/procedures/itemShelving_add.sql
index d3e0f6a90..9395f5d80 100644
--- a/db/routines/vn/procedures/itemShelving_add.sql
+++ b/db/routines/vn/procedures/itemShelving_add.sql
@@ -2,7 +2,6 @@ DELIMITER $$
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`itemShelving_add`(IN vShelvingFk VARCHAR(8), IN vBarcode VARCHAR(22), IN vQuantity INT, IN vPackagingFk VARCHAR(10), IN vGrouping INT, IN vPacking INT, IN vWarehouseFk INT)
BEGIN
-
/**
* Añade registro o lo actualiza si ya existe.
*
@@ -15,11 +14,23 @@ BEGIN
* @param vWarehouseFk indica el sector
*
**/
-
DECLARE vItemFk INT;
+ DECLARE vBuyFk INT;
+
+ SELECT id INTO vBuyFk
+ FROM buy WHERE id = vBarcode;
SELECT barcodeToItem(vBarcode) INTO vItemFk;
+ IF vBuyFk IS NULL THEN
+ CALL cache.last_buy_refresh(FALSE);
+
+ SELECT buy_id INTO vBuyFk
+ FROM cache.last_buy
+ WHERE item_id = vItemFk
+ AND warehouse_id = vWarehouseFk;
+ END IF;
+
IF vPacking IS NULL
THEN
SET vPacking = itemPacking(vBarcode, vWarehouseFk);
@@ -29,31 +40,32 @@ BEGIN
IF (SELECT COUNT(*) FROM itemShelving
WHERE shelvingFk COLLATE utf8_unicode_ci = vShelvingFk
AND itemFk = vItemFk
- AND packing = vPacking) = 1 THEN
+ AND packing = vPacking
+ AND buyFk = vBuyFk) THEN
UPDATE itemShelving
- SET visible = visible+vQuantity
+ SET visible = visible + vQuantity
WHERE shelvingFk COLLATE utf8_unicode_ci = vShelvingFk AND itemFk = vItemFk AND packing = vPacking;
ELSE
- CALL cache.last_buy_refresh(FALSE);
- INSERT INTO itemShelving( itemFk,
- shelvingFk,
- visible,
- grouping,
- packing,
- packagingFk)
- SELECT vItemFk,
- vShelvingFk,
- vQuantity,
- IFNULL(vGrouping, b.grouping),
- IFNULL(vPacking, b.packing),
- IFNULL(vPackagingFk, b.packagingFk)
- FROM item i
- LEFT JOIN cache.last_buy lb ON i.id = lb.item_id AND lb.warehouse_id = vWarehouseFk
- LEFT JOIN buy b ON b.id = lb.buy_id
- WHERE i.id = vItemFk;
+ INSERT INTO itemShelving(
+ itemFk,
+ shelvingFk,
+ visible,
+ grouping,
+ packing,
+ packagingFk,
+ buyFk)
+ SELECT vItemFk,
+ vShelvingFk,
+ vQuantity,
+ IFNULL(vGrouping, b.grouping),
+ IFNULL(vPacking, b.packing),
+ IFNULL(vPackagingFk, b.packagingFk),
+ id
+ FROM buy b
+ WHERE id = vBuyFk;
END IF;
END$$
DELIMITER ;
diff --git a/db/routines/vn/procedures/item_comparative.sql b/db/routines/vn/procedures/item_comparative.sql
index e72188363..d429cf009 100644
--- a/db/routines/vn/procedures/item_comparative.sql
+++ b/db/routines/vn/procedures/item_comparative.sql
@@ -6,7 +6,7 @@ CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`item_comparative`(
vAvailableSince DATE,
vBuyerFk INT,
vIsFloramondo BOOL,
- vCountryFk INT
+ vCountryFk INT
)
proc: BEGIN
/**
@@ -23,7 +23,6 @@ proc: BEGIN
* @param tmp.comparativeFilterType(filterFk INT ,itemTypeFk INT)
* @return tmp.comparative
*/
-
DECLARE vDayRangeStart DATE;
DECLARE vDayRangeEnd DATE;
DECLARE w1, w2, w3, w4, w5, w6, w7 INT;
@@ -59,14 +58,14 @@ proc: BEGIN
END IF;
SELECT MIN(dated) INTO vDayRangeStart
- FROM vn.time
+ FROM `time`
WHERE dated <= vDate
GROUP BY period
ORDER BY dated desc
LIMIT 1 OFFSET vWeekRange;
SELECT MAX(dated) INTO vDayRangeEnd
- FROM vn.time
+ FROM `time`
WHERE dated >= vDate
GROUP BY period
ORDER BY dated ASC
@@ -83,12 +82,11 @@ proc: BEGIN
JOIN itemType t ON t.id = i.typeFk
JOIN itemCategory c ON c.id = t.categoryFk
LEFT JOIN worker w ON w.id = t.workerFk
- WHERE (NOT vHasTypeFilter
- OR t.id IN (SELECT itemTypeFk FROM tmp.comparativeFilterType))
- AND (vBuyerFk IS NULL
- OR t.workerFk = vBuyerFk)
- AND (vIsFloramondo IS NULL
- OR i.isFloramondo = vIsFloramondo);
+ WHERE (NOT vHasTypeFilter OR t.id IN (
+ SELECT itemTypeFk FROM tmp.comparativeFilterType
+ ))
+ AND (vBuyerFk IS NULL OR t.workerFk = vBuyerFk)
+ AND (vIsFloramondo IS NULL OR i.isFloramondo = vIsFloramondo);
IF vDate < util.VN_CURDATE() THEN
ALTER TABLE tmp.itemInventory
@@ -115,10 +113,11 @@ proc: BEGIN
SET i = i + 1;
SELECT t.period INTO vPeriod
- FROM vn.`time` t
+ FROM `time` t
WHERE t.dated = vDayRangeStart + INTERVAL (vWeekCount * (i - 1)) DAY;
- INSERT IGNORE INTO tTable(cy, ly, zy) VALUES(vPeriod, vPeriod - 100, vPeriod - 200);
+ INSERT IGNORE INTO tTable(cy, ly, zy)
+ VALUES(vPeriod, vPeriod - 100, vPeriod - 200);
UNTIL i = vWeekCount END REPEAT;
SELECT cy, ly, zy INTO w1, y1, z1 FROM tTable LIMIT 1;
@@ -130,7 +129,6 @@ proc: BEGIN
SELECT cy, ly, zy INTO w7, y7, z7 FROM tTable WHERE cy > w6 LIMIT 1;
-- Genera una tabla con los datos del año pasado.
-
CREATE OR REPLACE TEMPORARY TABLE tLastYear
(KEY (lItemFk))
ENGINE = MEMORY
@@ -151,15 +149,14 @@ proc: BEGIN
SUM(IF(c.timePeriod = y7, c.price, 0)) lprice7
FROM tmp.itemInventory ai
JOIN comparative c ON c.itemFk = ai.id
- JOIN warehouse w on w.id = c.warehouseFk
+ JOIN warehouse w ON w.id = c.warehouseFk
JOIN tTable wt ON c.timePeriod = wt.ly
- WHERE IFNULL(vWarehouseFk, c.warehouseFk) = c.warehouseFk
+ WHERE (vWarehouseFk IS NULL OR vWarehouseFk = c.warehouseFk)
AND w.isComparative
AND (vCountryFk IS NULL OR c.countryFk = vCountryFk)
GROUP BY ai.id;
- -- Genera una tabla con los datos de hace DOS años.
-
+ -- Genera una tabla con los datos de hace 2 años
CREATE OR REPLACE TEMPORARY TABLE tTwoYearsAgo
(KEY (tItemFk))
ENGINE = MEMORY
@@ -180,73 +177,72 @@ proc: BEGIN
SUM(IF(c.timePeriod = z7, c.price, 0)) vlprice7
FROM tmp.itemInventory ai
JOIN comparative c ON c.itemFk = ai.id
- JOIN warehouse w on w.id = c.warehouseFk
+ JOIN warehouse w ON w.id = c.warehouseFk
JOIN tTable wt ON c.timePeriod = wt.zy
- WHERE IFNULL(vWarehouseFk, c.warehouseFk) = c.warehouseFk
+ WHERE (vWarehouseFk IS NULL OR vWarehouseFk = c.warehouseFk)
AND w.isComparative
AND (vCountryFk IS NULL OR c.countryFk = vCountryFk)
GROUP BY ai.id;
- -- Genera una tabla con los datos de este año.ss
-
+ -- Genera una tabla con los datos de este año
CREATE OR REPLACE TEMPORARY TABLE tCurrentYear
(KEY (cItemFk))
ENGINE = MEMORY
SELECT t.itemFk cItemFk,
- SUM(IF(week = w1, total, 0)) cweek1,
- SUM(IF(week = w2, total, 0)) cweek2,
- SUM(IF(week = w3, total, 0)) cweek3,
- SUM(IF(week = w4, total, 0)) cweek4,
- SUM(IF(week = w5, total, 0)) cweek5,
- SUM(IF(week = w6, total, 0)) cweek6,
- SUM(IF(week = w7, total, 0)) cweek7,
- SUM(IF(week = w1, price, 0)) cprice1,
- SUM(IF(week = w2, price, 0)) cprice2,
- SUM(IF(week = w3, price, 0)) cprice3,
- SUM(IF(week = w4, price, 0)) cprice4,
- SUM(IF(week = w5, price, 0)) cprice5,
- SUM(IF(week = w6, price, 0)) cprice6,
- SUM(IF(week = w7, price, 0)) cprice7
+ SUM(IF(`week` = w1, total, 0)) cweek1,
+ SUM(IF(`week` = w2, total, 0)) cweek2,
+ SUM(IF(`week` = w3, total, 0)) cweek3,
+ SUM(IF(`week` = w4, total, 0)) cweek4,
+ SUM(IF(`week` = w5, total, 0)) cweek5,
+ SUM(IF(`week` = w6, total, 0)) cweek6,
+ SUM(IF(`week` = w7, total, 0)) cweek7,
+ SUM(IF(`week` = w1, price, 0)) cprice1,
+ SUM(IF(`week` = w2, price, 0)) cprice2,
+ SUM(IF(`week` = w3, price, 0)) cprice3,
+ SUM(IF(`week` = w4, price, 0)) cprice4,
+ SUM(IF(`week` = w5, price, 0)) cprice5,
+ SUM(IF(`week` = w6, price, 0)) cprice6,
+ SUM(IF(`week` = w7, price, 0)) cprice7
FROM (
SELECT s.itemFk,
ti.period `week`,
SUM(s.quantity) total,
- TRUNCATE(SUM(s.quantity * s.priceFixed),0) price
- FROM ticket t
+ TRUNCATE(SUM(s.quantity * s.priceFixed), 0) price
+ FROM ticket t FORCE INDEX (Fecha)
JOIN sale s ON t.id = s.ticketFk
- JOIN tmp.itemInventory it ON it.id = s.itemFk
- JOIN time ti ON ti.dated = DATE(t.shipped)
+ JOIN tmp.itemInventory it ON it.id = s.itemFk
+ JOIN `time` ti ON ti.dated = DATE(t.shipped)
JOIN item i ON i.id = s.itemFk
JOIN itemType tp ON tp.id = i.typeFk
JOIN itemCategory ic ON ic.id = tp.categoryFk
JOIN warehouse w ON w.id = t.warehouseFk
- STRAIGHT_JOIN address ad ON ad.id = t.addressFk
- JOIN province p ON p.id = ad.provinceFk
+ JOIN `address` ad ON ad.id = t.addressFk
+ JOIN province p ON p.id = ad.provinceFk
JOIN `client` c ON c.id = ad.clientFk
WHERE t.shipped BETWEEN vDayRangeStart AND util.dayEnd(vDayRangeEnd)
- AND c.typeFk IN ('Normal','handMaking')
- AND w.id = COALESCE(vWarehouseFk, w.id)
+ AND c.typeFk IN ('normal', 'handMaking')
+ AND (vWarehouseFk IS NULL OR vWarehouseFk = w.id)
+ AND (vCountryFk IS NULL OR p.countryFk = vCountryFk)
AND w.isComparative
- AND (vCountryFk IS NULL OR p.countryFk = vCountryFk)
- GROUP BY i.id, week
+ GROUP BY i.id, `week`
) t
GROUP BY t.itemFk;
- -- Genera la tabla con la comparativa.
+ -- Genera la tabla con la comparativa
CREATE OR REPLACE TEMPORARY TABLE tmp.comparative
ENGINE = MEMORY
- SELECT it.subName productor,
- b.packing,
+ SELECT it.subName productor,
+ b.packing,
b.buyingValue costefijo,
b.groupingMode caja,
it.image ArticleImage,
- IFNULL(it.inkFk,"?") color,
+ IFNULL(it.inkFk, '?') color,
tp.code tipo,
it.typeFk tipo_id,
o.code origen,
it.category categoria,
it.stems tallos,
- it.size medida,
+ it.`size` medida,
it.name article,
w.code codigoTrabajador,
tp.categoryFk reino_id,
@@ -257,24 +253,27 @@ proc: BEGIN
it.id Id_Article,
i.buy_id,
tp.life,
- IFNULL(i.sd,0) sd,
+ IFNULL(i.sd, 0) sd,
i.avalaible,
i.visible,
i.buy_date,
e.id provider_id,
it.comment comments,
it.description itemDescription,
- IF(cy.cItemFk IS NULL AND i.visible = 0 AND i.avalaible = 0
- AND IFNULL(i.sd, 0) = 0, FALSE, TRUE) filtret,
+ IF(cy.cItemFk IS NULL AND i.visible = 0
+ AND i.avalaible = 0 AND (i.sd IS NULL OR i.sd = 0),
+ FALSE,
+ TRUE
+ ) filtret,
IF(it.hasMinPrice, FORMAT(it.minPrice, 2), "") pvp,
s.company_name
FROM tmp.itemInventory i
JOIN item it ON it.id = i.id
- LEFT JOIN itemType tp ON tp.id = it.typeFk
- LEFT JOIN worker w ON w.id = tp.workerFk
+ JOIN itemType tp ON tp.id = it.typeFk
+ JOIN worker w ON w.id = tp.workerFk
LEFT JOIN buy b ON b.id = i.buy_id
- LEFT JOIN entry e ON e.id = b.entryFk
- LEFT JOIN origin o ON o.id = it.originFk
+ LEFT JOIN `entry` e ON e.id = b.entryFk
+ JOIN origin o ON o.id = it.originFk
LEFT JOIN tLastYear ly ON ly.lItemFk = it.id
LEFT JOIN tCurrentYear cy ON cy.cItemFk = it.id
LEFT JOIN tTwoYearsAgo zy ON zy.tItemFk = it.id
@@ -287,8 +286,8 @@ proc: BEGIN
OR ly.lweek1 OR ly.lweek2 OR ly.lweek3 OR ly.lweek4 OR ly.lweek5 OR ly.lweek6 OR ly.lweek7
OR zy.vlweek1 OR zy.vlweek2 OR zy.vlweek3 OR zy.vlweek4 OR zy.vlweek5 OR zy.vlweek6 OR zy.vlweek7;
- -- Elimina las tablas temporales creadas...
- DROP TEMPORARY TABLE IF EXISTS tmp.itemInventory,
+ DROP TEMPORARY TABLE IF EXISTS
+ tmp.itemInventory,
tTwoYearsAgo,
tLastYear,
tCurrentYear,
diff --git a/db/routines/vn/procedures/item_ValuateInventory.sql b/db/routines/vn/procedures/item_valuateInventory.sql
similarity index 74%
rename from db/routines/vn/procedures/item_ValuateInventory.sql
rename to db/routines/vn/procedures/item_valuateInventory.sql
index bfd96fa82..18aefdf7b 100644
--- a/db/routines/vn/procedures/item_ValuateInventory.sql
+++ b/db/routines/vn/procedures/item_valuateInventory.sql
@@ -1,5 +1,7 @@
DELIMITER $$
-CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`item_ValuateInventory`(vDated DATE, vIsDetailed BOOLEAN)
+CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`item_valuateInventory`(
+ vDated DATE
+)
BEGIN
DECLARE vInventoried DATE;
DECLARE vHasNotInventory BOOLEAN DEFAULT FALSE;
@@ -15,8 +17,7 @@ BEGIN
SELECT tr.landed INTO vInventoried
FROM travel tr
JOIN `entry` e ON e.travelFk = tr.id
- JOIN entryConfig ec
- WHERE landed <= vDateDayEnd
+ WHERE tr.landed <= vDateDayEnd
AND e.supplierFk = vInventorySupplierFk
ORDER BY tr.landed DESC
LIMIT 1;
@@ -27,8 +28,7 @@ BEGIN
SELECT landed INTO vInventoryClone
FROM travel tr
JOIN `entry` e ON e.travelFk = tr.id
- JOIN entryConfig ec
- WHERE landed >= vDated
+ WHERE tr.landed >= vDated
AND e.supplierFk = vInventorySupplierFk
ORDER BY landed ASC
LIMIT 1;
@@ -38,13 +38,14 @@ BEGIN
END IF;
CREATE OR REPLACE TEMPORARY TABLE tInventory(
- warehouseFk SMALLINT,
- itemFk BIGINT,
- quantity INT,
- cost DOUBLE DEFAULT 0,
- total DOUBLE DEFAULT 0,
- warehouseInventory VARCHAR(20),
- PRIMARY KEY (warehouseInventory, itemFk) USING HASH
+ warehouseFk SMALLINT,
+ itemFk BIGINT,
+ quantity INT,
+ volume DECIMAL(10,2),
+ cost DOUBLE DEFAULT 0,
+ total DOUBLE DEFAULT 0,
+ warehouseInventory VARCHAR(20),
+ PRIMARY KEY (warehouseInventory, itemFk) USING HASH
)
ENGINE = MEMORY;
@@ -60,9 +61,8 @@ BEGIN
JOIN `entry` e ON e.id = b.entryFk
JOIN travel tr ON tr.id = e.travelFk
JOIN itemType t ON t.id = i.typeFk
- JOIN warehouse w ON w.id = warehouseInFk
- JOIN entryConfig ec
- WHERE landed = vDateDayEnd
+ JOIN warehouse w ON w.id = tr.warehouseInFk
+ WHERE tr.landed = vDateDayEnd
AND e.supplierFk = vInventorySupplierFk
AND w.valuatedInventory
AND t.isInventory
@@ -78,9 +78,8 @@ BEGIN
JOIN `entry` e ON e.id = b.entryFk
JOIN travel tr ON tr.id = e.travelFk
JOIN itemType t ON t.id = i.typeFk
- JOIN warehouse w ON w.id = warehouseInFk
- JOIN entryConfig ec
- WHERE landed = vInventoried
+ JOIN warehouse w ON w.id = tr.warehouseInFk
+ WHERE tr.landed = vInventoried
AND e.supplierFk = vInventorySupplierFk
AND w.valuatedInventory
AND t.isInventory
@@ -99,7 +98,6 @@ BEGIN
JOIN travel tr ON tr.id = e.travelFk
JOIN itemType t ON t.id = i.typeFk
JOIN warehouse w ON w.id = tr.warehouseInFk
- JOIN entryConfig ec
WHERE tr.landed BETWEEN vInventoried AND vDateDayEnd
AND IF(tr.landed = util.VN_CURDATE(), tr.isReceived, TRUE)
AND NOT e.isRaid
@@ -183,52 +181,37 @@ BEGIN
AND e.isConfirmed
ON DUPLICATE KEY UPDATE tInventory.quantity = tInventory.quantity + (b.quantity);
- CALL vn.buyUltimate(NULL, vDateDayEnd);
+ CALL buyUltimate(NULL, vDateDayEnd);
+
+ DELETE FROM tInventory WHERE quantity IS NULL OR NOT quantity;
UPDATE tInventory i
JOIN tmp.buyUltimate bu ON i.warehouseFk = bu.warehouseFk AND i.itemFk = bu.itemFk
JOIN buy b ON b.id = bu.buyFk
- SET total = i.quantity * (IFNULL(b.buyingValue, 0) + IFNULL(b.packageValue, 0) + IFNULL(b.freightValue, 0) + IFNULL(b.comissionValue, 0)),
- cost = IFNULL(b.buyingValue, 0) + IFNULL(b.packageValue, 0) + IFNULL(b.freightValue, 0) + IFNULL(b.comissionValue, 0)
- WHERE i.quantity;
+ LEFT JOIN itemCost ic ON ic.itemFk = i.itemFk
+ AND ic.warehouseFk = i.warehouseFk
+ SET i.total = i.quantity * (IFNULL(b.buyingValue, 0) + IFNULL(b.packageValue, 0) + IFNULL(b.freightValue, 0) + IFNULL(b.comissionValue, 0)),
+ i.cost = IFNULL(b.buyingValue, 0) + IFNULL(b.packageValue, 0) + IFNULL(b.freightValue, 0) + IFNULL(b.comissionValue, 0),
+ i.volume = i.quantity * ic.cm3delivery / 1000000;
- DELETE FROM tInventory
- WHERE quantity IS NULL OR NOT quantity;
-
- IF vIsDetailed THEN
- SELECT ti.warehouseFk,
- i.id itemFk,
- i.longName,
- i.size,
- ti.quantity,
- tp.name Tipo,
- ic.name Reino,
- ti.cost,
- CAST(ti.total AS DECIMAL(10, 2)) total,
- ti.warehouseInventory almacen
- FROM tInventory ti
- JOIN warehouse w ON w.id = warehouseFk
- JOIN item i ON i.id = ti.itemFk
- JOIN itemType tp ON tp.id = i.typeFk
- JOIN itemCategory ic ON ic.id = tp.categoryFk
- WHERE w.valuatedInventory
- AND ti.total > 0
- ORDER BY ti.total DESC;
- ELSE
- SELECT i.warehouseInventory Almacen,
- ic.name Reino,
- CAST(i.total AS DECIMAL(10, 2)) Euros,
- w.code Comprador,
- it.id
- FROM tInventory i
- JOIN warehouse wh ON wh.id = warehouseFk
- JOIN item it ON it.id = i.itemFk
- JOIN itemType itp ON itp.id = it.typeFk
- LEFT JOIN worker w ON w.id = itp.workerFk
- JOIN itemCategory ic ON ic.id = itp.categoryFk
- WHERE wh.valuatedInventory
- AND i.total > 0;
- END IF;
+ SELECT ti.warehouseFk,
+ i.id,
+ i.longName,
+ i.size,
+ ti.quantity,
+ ti.volume,
+ tp.name itemTypeName,
+ ic.name itemCategoryName,
+ ti.cost,
+ ti.total,
+ ti.warehouseInventory
+ FROM tInventory ti
+ JOIN warehouse w ON w.id = warehouseFk
+ JOIN item i ON i.id = ti.itemFk
+ JOIN itemType tp ON tp.id = i.typeFk
+ JOIN itemCategory ic ON ic.id = tp.categoryFk
+ WHERE w.valuatedInventory
+ AND ti.total > 0;
DROP TEMPORARY TABLE
tmp.buyUltimate,
diff --git a/db/routines/vn/procedures/ticketPackaging_add.sql b/db/routines/vn/procedures/ticketPackaging_add.sql
index d669b95f5..f96068b56 100644
--- a/db/routines/vn/procedures/ticketPackaging_add.sql
+++ b/db/routines/vn/procedures/ticketPackaging_add.sql
@@ -27,7 +27,10 @@ BEGIN
SELECT DISTINCT clientFk
FROM (
SELECT clientFk, SUM(quantity) totalQuantity
- FROM tmp.packagingToInvoice
+ FROM tmp.packagingToInvoice tpi
+ JOIN client c ON c.id = tpi.clientFk
+ LEFT JOIN supplier s ON s.nif = c.fi
+ WHERE s.id IS NULL
GROUP BY itemFk, clientFk
HAVING totalQuantity > 0)sub;
diff --git a/db/routines/vn/procedures/travel_throwAwb.sql b/db/routines/vn/procedures/travel_throwAwb.sql
new file mode 100644
index 000000000..1b54f8532
--- /dev/null
+++ b/db/routines/vn/procedures/travel_throwAwb.sql
@@ -0,0 +1,14 @@
+DELIMITER $$
+CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`travel_throwAwb`(vSelf INT)
+BEGIN
+/**
+ * Throws an error if travel does not have a logical AWB
+ * or there are several AWBs associated with the same DUA
+ *
+ * @param vSelf The travel id
+ */
+ IF NOT travel_hasUniqueAwb(vSelf) THEN
+ CALL util.throw('A different AWB is found in the entries');
+ END IF;
+END$$
+DELIMITER ;
\ No newline at end of file
diff --git a/db/routines/vn/triggers/entry_beforeInsert.sql b/db/routines/vn/triggers/entry_beforeInsert.sql
index c0c0aa28c..17831f1b8 100644
--- a/db/routines/vn/triggers/entry_beforeInsert.sql
+++ b/db/routines/vn/triggers/entry_beforeInsert.sql
@@ -7,8 +7,8 @@ BEGIN
CALL supplier_checkIsActive(NEW.supplierFk);
SET NEW.currencyFk = entry_getCurrency(NEW.currencyFk, NEW.supplierFk);
SET NEW.commission = entry_getCommission(NEW.travelFk, NEW.currencyFk,NEW.supplierFk);
- IF NEW.travelFk IS NOT NULL AND NOT travel_hasUniqueAwb(NEW.travelFk) THEN
- CALL util.throw('The travel is incorrect, there is a different AWB in the associated entries');
+ IF NEW.travelFk IS NOT NULL THEN
+ CALL travel_throwAwb(NEW.travelFk);
END IF;
END$$
DELIMITER ;
diff --git a/db/routines/vn/triggers/entry_beforeUpdate.sql b/db/routines/vn/triggers/entry_beforeUpdate.sql
index d56db5e01..e99eb087d 100644
--- a/db/routines/vn/triggers/entry_beforeUpdate.sql
+++ b/db/routines/vn/triggers/entry_beforeUpdate.sql
@@ -25,8 +25,8 @@ BEGIN
IF NOT (NEW.travelFk <=> OLD.travelFk) THEN
- IF NEW.travelFk IS NOT NULL AND NOT travel_hasUniqueAwb(NEW.travelFk) THEN
- CALL util.throw('The travel is incorrect, there is a different AWB in the associated entries');
+ IF NEW.travelFk IS NOT NULL THEN
+ CALL travel_throwAwb(NEW.travelFk);
END IF;
SELECT COUNT(*) > 0 INTO vIsVirtual
diff --git a/db/routines/vn/triggers/travel_beforeInsert.sql b/db/routines/vn/triggers/travel_beforeInsert.sql
index 817bd69bb..e54a5d08b 100644
--- a/db/routines/vn/triggers/travel_beforeInsert.sql
+++ b/db/routines/vn/triggers/travel_beforeInsert.sql
@@ -9,8 +9,8 @@ BEGIN
CALL travel_checkWarehouseIsFeedStock(NEW.warehouseInFk);
- IF NEW.awbFk IS NOT NULL AND NOT travel_hasUniqueAwb(NEW.id) THEN
- CALL util.throw('The AWB is incorrect, there is a different AWB in the associated entries');
+ IF NEW.awbFk IS NOT NULL THEN
+ CALL travel_throwAwb(NEW.id);
END IF;
END$$
DELIMITER ;
diff --git a/db/routines/vn/triggers/travel_beforeUpdate.sql b/db/routines/vn/triggers/travel_beforeUpdate.sql
index 5e43c8761..5e64ad5b3 100644
--- a/db/routines/vn/triggers/travel_beforeUpdate.sql
+++ b/db/routines/vn/triggers/travel_beforeUpdate.sql
@@ -33,8 +33,8 @@ BEGIN
END IF;
END IF;
- IF (NOT(NEW.awbFk <=> OLD.awbFk)) AND NEW.awbFk IS NOT NULL AND NOT travel_hasUniqueAwb(NEW.id) THEN
- CALL util.throw('The AWB is incorrect, there is a different AWB in the associated entries');
+ IF (NOT(NEW.awbFk <=> OLD.awbFk)) AND NEW.awbFk IS NOT NULL THEN
+ CALL travel_throwAwb(NEW.id);
END IF;
END$$
DELIMITER ;
diff --git a/db/versions/10978-wheatMoss/00-firstScript.sql b/db/versions/10978-wheatMoss/00-firstScript.sql
new file mode 100644
index 000000000..39bf1c318
--- /dev/null
+++ b/db/versions/10978-wheatMoss/00-firstScript.sql
@@ -0,0 +1,4 @@
+-- Place your SQL code here
+INSERT INTO salix.defaultViewConfig
+(tableCode, `columns`)
+VALUES('routesList', '{"ID":true,"worker":true,"agency":true,"vehicle":true,"date":true,"volume":true,"description":true,"started":true,"finished":true,"actions":true}');
diff --git a/db/versions/11015-silverBamboo/00-photoMotivation.sql b/db/versions/11015-silverBamboo/00-photoMotivation.sql
new file mode 100644
index 000000000..366694e12
--- /dev/null
+++ b/db/versions/11015-silverBamboo/00-photoMotivation.sql
@@ -0,0 +1 @@
+ALTER TABLE vn.item ADD COLUMN photoMotivation VARCHAR(255);
\ No newline at end of file
diff --git a/db/versions/11050-wheatAnthurium/00-firstScript.sql b/db/versions/11050-wheatAnthurium/00-firstScript.sql
new file mode 100644
index 000000000..cb8034ff5
--- /dev/null
+++ b/db/versions/11050-wheatAnthurium/00-firstScript.sql
@@ -0,0 +1,4 @@
+-- Place your SQL code here
+
+ALTER TABLE floranet.catalogue ADD addressFk int(11) NOT NULL;
+ALTER TABLE floranet.catalogue ADD CONSTRAINT catalogue_address_FK FOREIGN KEY (addressFk) REFERENCES vn.address(id) ON DELETE CASCADE ON UPDATE CASCADE;
diff --git a/db/versions/11050-wheatAnthurium/01-elementFilter.sql b/db/versions/11050-wheatAnthurium/01-elementFilter.sql
new file mode 100644
index 000000000..3f2bb78ac
--- /dev/null
+++ b/db/versions/11050-wheatAnthurium/01-elementFilter.sql
@@ -0,0 +1,6 @@
+ALTER TABLE floranet.builder DROP FOREIGN KEY builder_FK_1;
+ALTER TABLE floranet.`element` DROP PRIMARY KEY;
+ALTER TABLE floranet.`element` ADD id INT NOT NULL;
+ALTER TABLE floranet.`element` ADD CONSTRAINT element_pk PRIMARY KEY (id);
+ALTER TABLE floranet.builder ADD CONSTRAINT builder_element_FK FOREIGN KEY (elementFk) REFERENCES floranet.`element`(id) ON DELETE CASCADE ON UPDATE CASCADE;
+
diff --git a/db/versions/11059-crimsonAnthurium/00-firstScript.sql b/db/versions/11059-crimsonAnthurium/00-firstScript.sql
new file mode 100644
index 000000000..b0eade302
--- /dev/null
+++ b/db/versions/11059-crimsonAnthurium/00-firstScript.sql
@@ -0,0 +1,3 @@
+-- Place your SQL code here
+INSERT INTO salix.ACL (model,property,accessType,permission,principalType,principalId)
+ VALUES ('RouteConfig','*','READ','ALLOW','ROLE','employee');
diff --git a/db/versions/11060-tealGalax/00-createRoleReviewer.sql b/db/versions/11060-tealGalax/00-createRoleReviewer.sql
new file mode 100644
index 000000000..bf2984702
--- /dev/null
+++ b/db/versions/11060-tealGalax/00-createRoleReviewer.sql
@@ -0,0 +1,46 @@
+use account;
+
+INSERT INTO role
+ SET name = 'reviewer',
+ description = 'Revisor de producción',
+ hasLogin = TRUE,
+ created = util.VN_CURDATE(),
+ modified = util.VN_CURDATE(),
+ editorFk = NULL;
+
+INSERT INTO roleInherit(
+ role,
+ inheritsFrom
+)
+ SELECT r1.id,
+ r2.id
+ FROM role r1
+ JOIN role r2
+ WHERE r1.name = 'reviewer'
+ AND r2.name = 'production'
+ UNION
+ SELECT ri.role,
+ r2.id
+ FROM roleInherit ri
+ JOIN role r1 ON r1.id = ri.role
+ JOIN role r2 ON r2.name = 'reviewer'
+ WHERE r1.name IN ('claimManager', 'productionBoss')
+ GROUP BY ri.role;
+
+DELETE ri
+ FROM roleInherit ri
+ JOIN role r1 ON ri.role = r1.id
+ JOIN role r2 ON ri.inheritsFrom = r2.id
+ WHERE r1.name = 'replenisher'
+ AND r2.name = 'buyer';
+
+UPDATE salix.ACL
+ SET principalId = 'reviewer'
+ WHERE property = 'isInPreparing';
+
+UPDATE user u
+ JOIN vn.workerDepartment wd ON wd.workerFk = u.id
+ JOIN vn.department d ON wd.departmentFk = d.id
+ JOIN role r ON r.name = 'reviewer'
+ SET u.role = r.id
+ WHERE d.name IN ('REVISION', 'PREVIA');
\ No newline at end of file
diff --git a/db/versions/11065-yellowChrysanthemum/00-modifyInvoiceInPrivileges.sql b/db/versions/11065-yellowChrysanthemum/00-modifyInvoiceInPrivileges.sql
new file mode 100644
index 000000000..b65ca1c17
--- /dev/null
+++ b/db/versions/11065-yellowChrysanthemum/00-modifyInvoiceInPrivileges.sql
@@ -0,0 +1,24 @@
+REVOKE UPDATE ON vn. invoiceIn FROM administrative, hrBoss, buyer, logistic;
+GRANT UPDATE (id,
+ serialNumber,
+ serial,
+ supplierFk,
+ issued,
+ supplierRef,
+ currencyFk,
+ created,
+ companyFk,
+ docFk,
+ booked,
+ operated,
+ siiTypeInvoiceInFk,
+ cplusRectificationTypeFk,
+ cplusSubjectOpFk,
+ cplusTaxBreakFk,
+ siiTrascendencyInvoiceInFk,
+ bookEntried,
+ isVatDeductible,
+ withholdingSageFk,
+ expenseFkDeductible,
+ editorFk
+) ON vn.invoiceIn TO administrative, hrBoss, buyer, logistic;
\ No newline at end of file
diff --git a/db/versions/11065-yellowChrysanthemum/01-modifyInvoiceInAcls.sql b/db/versions/11065-yellowChrysanthemum/01-modifyInvoiceInAcls.sql
new file mode 100644
index 000000000..5475b70ac
--- /dev/null
+++ b/db/versions/11065-yellowChrysanthemum/01-modifyInvoiceInAcls.sql
@@ -0,0 +1,23 @@
+UPDATE salix.ACL
+ SET accessType = 'READ'
+ WHERE principalId IN ('administrative','buyer')
+ AND model = 'invoiceIn'
+ AND property = '*';
+
+INSERT INTO salix.ACL (model, property, accessType, permission, principalType, principalId)
+VALUES
+ ('InvoiceIn', 'updateInvoiceIn', 'WRITE', 'ALLOW', 'ROLE', 'administrative'),
+ ('InvoiceIn', 'clone', 'WRITE', 'ALLOW', 'ROLE', 'administrative'),
+ ('InvoiceIn', 'corrective', 'WRITE', 'ALLOW', 'ROLE', 'administrative'),
+ ('InvoiceIn', 'exchangeRateUpdate', 'WRITE', 'ALLOW', 'ROLE', 'administrative'),
+ ('InvoiceIn', 'invoiceInEmail', 'WRITE', 'ALLOW', 'ROLE', 'administrative'),
+ ('InvoiceIn', 'toBook', 'WRITE', 'ALLOW', 'ROLE', 'administrative'),
+ ('InvoiceIn', 'toUnbook', 'WRITE', 'ALLOW', 'ROLE', 'administrative'),
+ ('InvoiceIn', 'deleteById', 'WRITE', 'ALLOW', 'ROLE', 'administrative'),
+ ('InvoiceIn', 'updateInvoiceIn', 'WRITE', 'ALLOW', 'ROLE', 'buyer'),
+ ('InvoiceIn', 'clone', 'WRITE', 'ALLOW', 'ROLE', 'buyer'),
+ ('InvoiceIn', 'corrective', 'WRITE', 'ALLOW', 'ROLE', 'buyer'),
+ ('InvoiceIn', 'exchangeRateUpdate', 'WRITE', 'ALLOW', 'ROLE', 'buyer'),
+ ('InvoiceIn', 'invoiceInEmail', 'WRITE', 'ALLOW', 'ROLE', 'buyer'),
+ ('InvoiceIn', 'toBook', 'WRITE', 'ALLOW', 'ROLE', 'buyer'),
+ ('InvoiceIn', 'deleteById', 'WRITE', 'ALLOW', 'ROLE', 'buyer');
diff --git a/db/versions/11068-blueGerbera/00-firstScript.sql b/db/versions/11068-blueGerbera/00-firstScript.sql
new file mode 100644
index 000000000..6342981a7
--- /dev/null
+++ b/db/versions/11068-blueGerbera/00-firstScript.sql
@@ -0,0 +1,9 @@
+-- Place your SQL code here
+CREATE OR REPLACE TABLE floranet.config (
+ email varchar(255) DEFAULT 'floranet@verdnatura.es' NOT NULL
+)
+ENGINE=InnoDB
+DEFAULT CHARSET=utf8mb3
+COLLATE=utf8mb3_unicode_ci;
+
+
diff --git a/db/versions/11069-brownChrysanthemum/00-firstScript.sql b/db/versions/11069-brownChrysanthemum/00-firstScript.sql
new file mode 100644
index 000000000..3220d1257
--- /dev/null
+++ b/db/versions/11069-brownChrysanthemum/00-firstScript.sql
@@ -0,0 +1,35 @@
+-- Place your SQL code here
+DROP TABLE IF EXISTS floranet.builder;
+
+CREATE OR REPLACE TABLE floranet.`element` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `name` varchar(30) NOT NULL,
+ `itemFk` int(11) DEFAULT NULL,
+ `longNameFilter` varchar(30) DEFAULT NULL,
+ `typeFk` smallint(5) unsigned DEFAULT NULL,
+ `minSize` int(10) unsigned DEFAULT NULL,
+ `maxSize` int(10) unsigned DEFAULT NULL,
+ `inkFk` char(3) CHARACTER SET utf8mb3 COLLATE utf8mb3_unicode_ci DEFAULT NULL,
+ `originFk` tinyint(2) unsigned DEFAULT NULL,
+ PRIMARY KEY (`id`),
+ KEY `element_FK` (`itemFk`),
+ KEY `element_FK_1` (`typeFk`),
+ KEY `element_FK_2` (`inkFk`),
+ KEY `element_FK_3` (`originFk`),
+ CONSTRAINT `element_FK` FOREIGN KEY (`itemFk`) REFERENCES `vn`.`item` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
+ CONSTRAINT `element_FK_1` FOREIGN KEY (`typeFk`) REFERENCES `vn`.`itemType` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
+ CONSTRAINT `element_FK_2` FOREIGN KEY (`inkFk`) REFERENCES `vn`.`ink` (`id`) ON UPDATE CASCADE,
+ CONSTRAINT `element_FK_3` FOREIGN KEY (`originFk`) REFERENCES `vn`.`origin` (`id`) ON UPDATE CASCADE
+) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='Filtro para localizar posibles items que coincidan con la descripción';
+
+CREATE OR REPLACE TABLE floranet.`recipe` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `itemFk` int(11) NOT NULL,
+ `elementFk` int(11) NOT NULL,
+ `quantity` int(10) unsigned NOT NULL DEFAULT 1,
+ PRIMARY KEY (`id`),
+ KEY `recipe_FK` (`itemFk`),
+ KEY `recipe_FK_1` (`elementFk`),
+ CONSTRAINT `recipe_FK` FOREIGN KEY (`itemFk`) REFERENCES `vn`.`item` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
+ CONSTRAINT `recipe_element_FK` FOREIGN KEY (`elementFk`) REFERENCES `element` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='Links handmade products with their elements';
diff --git a/db/versions/11074-brownRuscus/00-firstScript.sql b/db/versions/11074-brownRuscus/00-firstScript.sql
new file mode 100644
index 000000000..f78ba98ae
--- /dev/null
+++ b/db/versions/11074-brownRuscus/00-firstScript.sql
@@ -0,0 +1,20 @@
+-- Place your SQL code here
+
+
+-- floranet.recipe definition
+
+CREATE OR REPLACE TABLE floranet.`recipe`
+ (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `itemFk` int(11) NOT NULL COMMENT 'Bouquet or plant name',
+ `elementFk` int(11) NOT NULL COMMENT 'Item detail for bouquet''s composition',
+ `quantity` int(10) unsigned NOT NULL DEFAULT 1,
+ `cost` decimal(10,2) NOT NULL DEFAULT 1.00,
+ PRIMARY KEY (`id`),
+ KEY `recipe_FK` (`itemFk`),
+ KEY `recipe_FK_1` (`elementFk`),
+ CONSTRAINT `recipe_FK` FOREIGN KEY (`itemFk`) REFERENCES `vn`.`item` (`id`) ON UPDATE CASCADE,
+ CONSTRAINT `recipe_item_FK` FOREIGN KEY (`elementFk`) REFERENCES `vn`.`item` (`id`) ON UPDATE CASCADE
+) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='Links handmade products with their elements';
+
+DROP TABLE IF EXISTS floranet.`element`;
\ No newline at end of file
diff --git a/db/versions/11078-goldenFern/00-firstScript.sql b/db/versions/11078-goldenFern/00-firstScript.sql
new file mode 100644
index 000000000..63888a1bb
--- /dev/null
+++ b/db/versions/11078-goldenFern/00-firstScript.sql
@@ -0,0 +1,2 @@
+ALTER TABLE vn.productionConfig ADD scannablePreviusCodeType enum('qr','barcode')
+ CHARACTER SET utf8mb3 COLLATE utf8mb3_unicode_ci DEFAULT 'barcode' NOT NULL;
\ No newline at end of file
diff --git a/e2e/paths/02-client/05_add_address.spec.js b/e2e/paths/02-client/05_add_address.spec.js
index 0581635d0..4f809a716 100644
--- a/e2e/paths/02-client/05_add_address.spec.js
+++ b/e2e/paths/02-client/05_add_address.spec.js
@@ -51,7 +51,7 @@ describe('Client Add address path', () => {
await page.waitToClick(selectors.clientAddresses.saveButton);
const message = await page.waitForSnackbar();
- expect(message.text).toContain('Incoterms is required for a non UEE member');
+ expect(message.text).toContain('Incoterms and Customs agent are required for a non UEE member');
});
it(`should receive an error after clicking save button as customsAgent is empty`, async() => {
@@ -59,7 +59,7 @@ describe('Client Add address path', () => {
await page.waitToClick(selectors.clientAddresses.saveButton);
const message = await page.waitForSnackbar();
- expect(message.text).toContain('Customs agent is required for a non UEE member');
+ expect(message.text).toContain('Incoterms and Customs agent are required for a non UEE member');
});
it(`should create a new custom agent and then save the address`, async() => {
diff --git a/e2e/paths/05-ticket/01-sale/02_edit_sale.spec.js b/e2e/paths/05-ticket/01-sale/02_edit_sale.spec.js
index 4f54ad860..e0f32fc3a 100644
--- a/e2e/paths/05-ticket/01-sale/02_edit_sale.spec.js
+++ b/e2e/paths/05-ticket/01-sale/02_edit_sale.spec.js
@@ -225,7 +225,7 @@ describe('Ticket Edit sale path', () => {
});
it('should show error trying to delete a ticket with a refund', async() => {
- await page.loginAndModule('production', 'ticket');
+ await page.loginAndModule('salesPerson', 'ticket');
await page.accessToSearchResult('8');
await page.waitToClick(selectors.ticketDescriptor.moreMenu);
await page.waitToClick(selectors.ticketDescriptor.moreMenuDeleteTicket);
diff --git a/front/core/locale/es.yml b/front/core/locale/es.yml
index 17e955ff5..7fcb8c16b 100644
--- a/front/core/locale/es.yml
+++ b/front/core/locale/es.yml
@@ -69,3 +69,4 @@ Send cau: Enviar cau
By sending this ticket, all the data related to the error, the section, the user, etc., are already sent.: Al enviar este cau ya se envían todos los datos relacionados con el error, la sección, el usuario, etc
ExplainReason: Explique el motivo por el que no deberia aparecer este fallo
You already have the mailAlias: Ya tienes este alias de correo
+Error loading ACLs: Error al cargar los ACLs
diff --git a/front/core/services/auth.js b/front/core/services/auth.js
index 753bc3fba..0cae4bae8 100644
--- a/front/core/services/auth.js
+++ b/front/core/services/auth.js
@@ -7,16 +7,17 @@ import UserError from 'core/lib/user-error';
* @property {Boolean} loggedIn Whether the user is currently logged
*/
export default class Auth {
- constructor($http, $q, $state, $transitions, $window, vnToken, vnModules, aclService) {
+ constructor($http, $q, vnApp, $translate, $state, $transitions, $window, vnToken, vnModules) {
Object.assign(this, {
$http,
$q,
+ vnApp,
+ $translate,
$state,
$transitions,
$window,
vnToken,
vnModules,
- aclService,
loggedIn: false
});
}
@@ -39,9 +40,26 @@ export default class Auth {
};
if (this.vnToken.token) {
- return this.loadAcls()
- .then(() => true)
- .catch(redirectToLogin);
+ const loadWithRetry = () => {
+ return this.validateToken()
+ .then(() => true)
+ .catch(err => {
+ switch (err.status) {
+ case 400:
+ case 401:
+ return redirectToLogin();
+ default:
+ return new Promise(resolve => {
+ setTimeout(() => {
+ this.vnApp.showMessage(this.$translate.instant('Loading...'));
+
+ resolve(loadWithRetry());
+ }, 2000);
+ });
+ }
+ });
+ };
+ return loadWithRetry();
} else
return redirectToLogin();
});
@@ -87,13 +105,11 @@ export default class Auth {
headers: {Authorization: json.data.token}
}).then(({data}) => {
this.vnToken.set(json.data.token, data.multimediaToken.id, now, json.data.ttl, remember);
- this.loadAcls().then(() => {
- let continueHash = this.$state.params.continue;
- if (continueHash)
- this.$window.location = continueHash;
- else
- this.$state.go('home');
- });
+ let continueHash = this.$state.params.continue;
+ if (continueHash)
+ this.$window.location = continueHash;
+ else
+ this.$state.go('home');
}).catch(() => {});
}
@@ -107,24 +123,25 @@ export default class Auth {
this.vnToken.unset();
this.loggedIn = false;
this.vnModules.reset();
- this.aclService.reset();
+ this.vnModules.aclService.reset();
this.$state.go('login');
return promise;
}
- loadAcls() {
- return this.aclService.load()
+ validateToken() {
+ return this.$http.get('VnUsers/validateToken')
.then(() => {
this.loggedIn = true;
this.vnModules.reset();
})
.catch(err => {
- this.vnToken.unset();
throw err;
});
}
}
-Auth.$inject = ['$http', '$q', '$state', '$transitions', '$window', 'vnToken', 'vnModules', 'aclService'];
+Auth.$inject = [
+ '$http', '$q', 'vnApp', '$translate', '$state',
+ '$transitions', '$window', 'vnToken', 'vnModules'];
ngModule.service('vnAuth', Auth);
diff --git a/front/salix/components/upload-photo/index.js b/front/salix/components/upload-photo/index.js
index c9774d037..7779c81e1 100644
--- a/front/salix/components/upload-photo/index.js
+++ b/front/salix/components/upload-photo/index.js
@@ -164,6 +164,7 @@ export default class UploadPhoto extends Component {
const options = {
type: 'blob',
+ size: 'original'
};
return this.editor.result(options)
.then(blob => this.newPhoto.blob = blob)
diff --git a/front/salix/routes.js b/front/salix/routes.js
index 8621f83c7..be210b749 100644
--- a/front/salix/routes.js
+++ b/front/salix/routes.js
@@ -12,7 +12,8 @@ function config($stateProvider, $urlRouterProvider) {
template: '',
resolve: {
config: ['vnConfig', vnConfig => vnConfig.initialize()],
- token: ['vnToken', vnToken => vnToken.fetchConfig()]
+ token: ['vnToken', vnToken => vnToken.fetchConfig()],
+ acl: ['aclService', aclService => aclService.load()]
}
})
.state('outLayout', {
diff --git a/loopback/common/models/application.js b/loopback/common/models/application.js
index 6bdc2c13a..80c58ddc1 100644
--- a/loopback/common/models/application.js
+++ b/loopback/common/models/application.js
@@ -1,4 +1,3 @@
-
module.exports = function(Self) {
require('../methods/application/status')(Self);
require('../methods/application/post')(Self);
diff --git a/loopback/locale/en.json b/loopback/locale/en.json
index 551b544b6..cb9e1d12c 100644
--- a/loopback/locale/en.json
+++ b/loopback/locale/en.json
@@ -61,7 +61,8 @@
"Changed sale discount": "I have changed the following lines discounts from the ticket [{{ticketId}}]({{{ticketUrl}}}): {{{changes}}}",
"Created claim": "I have created the claim [{{claimId}}]({{{claimUrl}}}) for the following lines from the ticket [{{ticketId}}]({{{ticketUrl}}}): {{{changes}}}",
"Changed sale price": "I have changed the price of [{{itemId}} {{concept}}]({{{itemUrl}}}) ({{quantity}}) from {{oldPrice}}€ ➔ *{{newPrice}}€* of the ticket [{{ticketId}}]({{{ticketUrl}}})",
- "Changed sale quantity": "I have changed the quantity of [{{itemId}} {{concept}}]({{{itemUrl}}}) from {{oldQuantity}} ➔ *{{newQuantity}}* of the ticket [{{ticketId}}]({{{ticketUrl}}})",
+ "Changed sale quantity": "I have changed {{changes}} of the ticket [{{ticketId}}]({{{ticketUrl}}})",
+ "Changes in sales": "the quantity of [{{itemId}} {{concept}}]({{{itemUrl}}}) from {{oldQuantity}} ➔ *{{newQuantity}}*",
"Changed sale reserved state": "I have changed the following lines reserved state from the ticket [{{ticketId}}]({{{ticketUrl}}}): {{{changes}}}",
"Bought units from buy request": "Bought {{quantity}} units of [{{itemId}} {{concept}}]({{{urlItem}}}) for the ticket id [{{ticketId}}]({{{url}}})",
"MESSAGE_INSURANCE_CHANGE": "I have changed the insurence credit of client [{{clientName}} ({{clientId}})]({{{url}}}) to *{{credit}} €*",
@@ -227,5 +228,6 @@
"They're not your subordinate": "They're not your subordinate",
"InvoiceIn is already booked": "InvoiceIn is already booked",
"This workCenter is already assigned to this agency": "This workCenter is already assigned to this agency",
- "You can only have one PDA": "You can only have one PDA"
-}
\ No newline at end of file
+ "You can only have one PDA": "You can only have one PDA",
+ "Incoterms and Customs agent are required for a non UEE member": "Incoterms and Customs agent are required for a non UEE member"
+}
diff --git a/loopback/locale/es.json b/loopback/locale/es.json
index 4a7e1505c..f94e21d7b 100644
--- a/loopback/locale/es.json
+++ b/loopback/locale/es.json
@@ -124,7 +124,8 @@
"Changed sale discount": "He cambiado el descuento de las siguientes lineas al ticket [{{ticketId}}]({{{ticketUrl}}}): {{{changes}}}",
"Created claim": "He creado la reclamación [{{claimId}}]({{{claimUrl}}}) de las siguientes lineas del ticket [{{ticketId}}]({{{ticketUrl}}}): {{{changes}}}",
"Changed sale price": "He cambiado el precio de [{{itemId}} {{concept}}]({{{itemUrl}}}) ({{quantity}}) de {{oldPrice}}€ ➔ *{{newPrice}}€* del ticket [{{ticketId}}]({{{ticketUrl}}})",
- "Changed sale quantity": "He cambiado la cantidad de [{{itemId}} {{concept}}]({{{itemUrl}}}) de {{oldQuantity}} ➔ *{{newQuantity}}* del ticket [{{ticketId}}]({{{ticketUrl}}})",
+ "Changed sale quantity": "He cambiado {{changes}} del ticket [{{ticketId}}]({{{ticketUrl}}})",
+ "Changes in sales": "la cantidad de [{{itemId}} {{concept}}]({{{itemUrl}}}) de {{oldQuantity}} ➔ *{{newQuantity}}*",
"State": "Estado",
"regular": "normal",
"reserved": "reservado",
@@ -358,6 +359,8 @@
"Select ticket or client": "Elija un ticket o un client",
"It was not able to create the invoice": "No se pudo crear la factura",
"ticketCommercial": "El ticket {{ ticket }} para el vendedor {{ salesMan }} está en preparación. (mensaje generado automáticamente)",
- "This PDA is already assigned to another user": "Este PDA ya está asignado a otro usuario",
- "You can only have one PDA": "Solo puedes tener un PDA"
-}
\ No newline at end of file
+ "This PDA is already assigned to another user": "Esta PDA ya está asignado a otro usuario",
+ "You can only have one PDA": "Solo puedes tener una PDA",
+ "Incoterms and Customs agent are required for a non UEE member": "Se requieren Incoterms y agente de aduanas para un no miembro de la UEE",
+ "You can not use the same password": "No puedes usar la misma contraseña"
+}
diff --git a/loopback/locale/fr.json b/loopback/locale/fr.json
index 44f5e35d3..6f3919e18 100644
--- a/loopback/locale/fr.json
+++ b/loopback/locale/fr.json
@@ -123,8 +123,9 @@
"Added sale to ticket": "J'ai ajouté la ligne suivante au ticket [{{ticketId}}]({{{ticketUrl}}}): {{{addition}}}",
"Changed sale discount": "J'ai changé le rabais des lignes suivantes du ticket [{{ticketId}}]({{{ticketUrl}}}): {{{changes}}}",
"Created claim": "J'ai créé la réclamation [{{claimId}}]({{{claimUrl}}}) des lignes suivantes du ticket [{{ticketId}}]({{{ticketUrl}}}): {{{changes}}}",
- "Changed sale price": "J'ai changé le prix de [{{itemId}} {{concept}}]({{{itemUrl}}}) ({{quantity}}) de {{oldPrice}}€ ➔ *{{newPrice}}€* du ticket [{{ticketId}}]({{{ticketUrl}}})",
- "Changed sale quantity": "J'ai changé la quantité de {{itemId}} {{concept}} de {{oldQuantity}} ➔ {{newQuantity}} du ticket [{{ticketId}}]({{{ticketUrl}}})",
+ "Changed sale price": " le prix de [{{itemId}} {{concept}}]({{{itemUrl}}}) ({{quantity}}) de {{oldPrice}}€ ➔ *{{newPrice}}€* du ticket [{{ticketId}}]({{{ticketUrl}}})",,
+ "Changed sale quantity": "J'ai changé {{changes}} du ticket [{{ticketId}}]({{{ticketUrl}}})",
+ "Changes in sales": "la quantité de {{itemId}} {{concept}} de {{oldQuantity}} ➔ {{newQuantity}}",
"State": "État",
"regular": "normal",
"reserved": "réservé",
@@ -357,4 +358,4 @@
"This workCenter is already assigned to this agency": "Ce centre de travail est déjà assigné à cette agence",
"Select ticket or client": "Choisissez un ticket ou un client",
"It was not able to create the invoice": "Il n'a pas été possible de créer la facture"
-}
\ No newline at end of file
+}
diff --git a/loopback/locale/pt.json b/loopback/locale/pt.json
index b11eeefc6..3c156506c 100644
--- a/loopback/locale/pt.json
+++ b/loopback/locale/pt.json
@@ -124,7 +124,8 @@
"Changed sale discount": "Desconto da venda alterado no ticket [{{ticketId}}]({{{ticketUrl}}}): {{{changes}}}",
"Created claim": "Reclamação criada [{{claimId}}]({{{claimUrl}}}) no ticket [{{ticketId}}]({{{ticketUrl}}}): {{{changes}}}",
"Changed sale price": "Preço da venda alterado para [{{itemId}} {{concept}}]({{{itemUrl}}}) ({{quantity}}) de {{oldPrice}}€ ➔ *{{newPrice}}€* no ticket [{{ticketId}}]({{{ticketUrl}}})",
- "Changed sale quantity": "Quantidade da venda alterada para [{{itemId}} {{concept}}]({{{itemUrl}}}) de {{oldQuantity}} ➔ *{{newQuantity}}* no ticket [{{ticketId}}]({{{ticketUrl}}})",
+ "Changed sale quantity": "Quantidade da venda alterada para {{changes}} no ticket [{{ticketId}}]({{{ticketUrl}}})",
+ "Changes in sales": " [{{itemId}} {{concept}}]({{{itemUrl}}}) de {{oldQuantity}} ➔ *{{newQuantity}}* ",
"State": "Estado",
"regular": "normal",
"reserved": "reservado",
@@ -357,4 +358,4 @@
"This workCenter is already assigned to this agency": "Este centro de trabalho já está atribuído a esta agência",
"Select ticket or client": "Selecione um ticket ou cliente",
"It was not able to create the invoice": "Não foi possível criar a fatura"
-}
\ No newline at end of file
+}
diff --git a/loopback/server/boot/isProduction.js b/loopback/server/boot/isProduction.js
new file mode 100644
index 000000000..151afa9cb
--- /dev/null
+++ b/loopback/server/boot/isProduction.js
@@ -0,0 +1,3 @@
+module.exports = (localAsProduction = true) => {
+ return (!process.env.NODE_ENV && localAsProduction) || process.env.NODE_ENV == 'production';
+};
diff --git a/modules/account/back/models/ldap-config.js b/modules/account/back/models/ldap-config.js
index 89f0add48..583ce084b 100644
--- a/modules/account/back/models/ldap-config.js
+++ b/modules/account/back/models/ldap-config.js
@@ -3,9 +3,10 @@ const app = require('vn-loopback/server/server');
const ldap = require('../util/ldapjs-extra');
const crypto = require('crypto');
const nthash = require('smbhash').nthash;
+const isProduction = require('vn-loopback/server/boot/isProduction');
module.exports = Self => {
- const shouldSync = process.env.NODE_ENV !== 'test';
+ const shouldSync = isProduction();
Self.getLinker = async function() {
return await Self.findOne({
diff --git a/modules/account/back/models/samba-config.js b/modules/account/back/models/samba-config.js
index 927510a29..359b4b187 100644
--- a/modules/account/back/models/samba-config.js
+++ b/modules/account/back/models/samba-config.js
@@ -1,6 +1,7 @@
const ldap = require('../util/ldapjs-extra');
const execFile = require('child_process').execFile;
+const isProduction = require('vn-loopback/server/boot/isProduction');
/**
* Summary of userAccountControl flags:
@@ -12,7 +13,7 @@ const UserAccountControlFlags = {
};
module.exports = Self => {
- const shouldSync = process.env.NODE_ENV !== 'test';
+ const shouldSync = isProduction();
Self.getLinker = async function() {
return await Self.findOne({
diff --git a/modules/claim/back/methods/claim-beginning/importToNewRefundTicket.spec.js b/modules/claim/back/methods/claim-beginning/importToNewRefundTicket.spec.js
index b05b2ac15..156caaeec 100644
--- a/modules/claim/back/methods/claim-beginning/importToNewRefundTicket.spec.js
+++ b/modules/claim/back/methods/claim-beginning/importToNewRefundTicket.spec.js
@@ -6,6 +6,7 @@ describe('claimBeginning', () => {
const claimManagerId = 72;
const activeCtx = {
accessToken: {userId: claimManagerId},
+ __: value => value
};
const ctx = {req: activeCtx};
diff --git a/modules/client/back/methods/client/createAddress.js b/modules/client/back/methods/client/createAddress.js
index 8e6db2a22..2709632cb 100644
--- a/modules/client/back/methods/client/createAddress.js
+++ b/modules/client/back/methods/client/createAddress.js
@@ -92,11 +92,8 @@ module.exports = function(Self) {
}, myOptions);
const isUeeMember = province.country().isUeeMember;
- if (!isUeeMember && !args.incotermsFk)
- throw new UserError(`Incoterms is required for a non UEE member`);
-
- if (!isUeeMember && !args.customsAgentFk)
- throw new UserError(`Customs agent is required for a non UEE member`);
+ if (!isUeeMember && (!args.incotermsFk || !args.customsAgentFk))
+ throw new UserError(`Incoterms and Customs agent are required for a non UEE member`);
delete args.ctx; // Remove unwanted properties
const newAddress = await models.Address.create(args, myOptions);
diff --git a/modules/client/back/methods/client/specs/createAddress.spec.js b/modules/client/back/methods/client/specs/createAddress.spec.js
index 0841ad98c..ae179cf6c 100644
--- a/modules/client/back/methods/client/specs/createAddress.spec.js
+++ b/modules/client/back/methods/client/specs/createAddress.spec.js
@@ -50,7 +50,7 @@ describe('Address createAddress', () => {
}
expect(error).toBeDefined();
- expect(error.message).toEqual('Incoterms is required for a non UEE member');
+ expect(error.message).toEqual('Incoterms and Customs agent are required for a non UEE member');
});
it('should throw a non uee member error if no customsAgent is defined', async() => {
@@ -81,7 +81,7 @@ describe('Address createAddress', () => {
}
expect(error).toBeDefined();
- expect(error.message).toEqual('Customs agent is required for a non UEE member');
+ expect(error.message).toEqual('Incoterms and Customs agent are required for a non UEE member');
});
it('should create a new address and set as a client default address', async() => {
diff --git a/modules/client/back/methods/sms/send.js b/modules/client/back/methods/sms/send.js
index 94b2b6c27..2b5674f86 100644
--- a/modules/client/back/methods/sms/send.js
+++ b/modules/client/back/methods/sms/send.js
@@ -1,5 +1,6 @@
const got = require('got');
const UserError = require('vn-loopback/util/user-error');
+const isProduction = require('vn-loopback/server/boot/isProduction');
module.exports = Self => {
Self.remoteMethod('send', {
@@ -47,7 +48,7 @@ module.exports = Self => {
let response;
try {
- if (process.env.NODE_ENV !== 'production')
+ if (!isProduction(false))
response = {result: [{status: 'ok'}]};
else {
const jsonTest = {
diff --git a/modules/client/back/models/XDiario.json b/modules/client/back/models/XDiario.json
index be543393d..5c277783a 100644
--- a/modules/client/back/models/XDiario.json
+++ b/modules/client/back/models/XDiario.json
@@ -76,7 +76,16 @@
},
"enlazadoSage": {
"type": "boolean"
- }
+ },
+ "enlazado": {
+ "type": "boolean"
+ },
+ "key": {
+ "type": "number",
+ "mysql": {
+ "columnName": "CLAVE"
+ }
+ }
},
"relations": {
"company": {
diff --git a/modules/entry/back/model-config.json b/modules/entry/back/model-config.json
index 7b6e23685..dc7fd86be 100644
--- a/modules/entry/back/model-config.json
+++ b/modules/entry/back/model-config.json
@@ -22,5 +22,8 @@
},
"EntryObservation": {
"dataSource": "vn"
+ },
+ "EntryType": {
+ "dataSource": "vn"
}
-}
+}
\ No newline at end of file
diff --git a/modules/entry/back/models/entry-type.json b/modules/entry/back/models/entry-type.json
new file mode 100644
index 000000000..989aa3a8a
--- /dev/null
+++ b/modules/entry/back/models/entry-type.json
@@ -0,0 +1,25 @@
+{
+ "name": "EntryType",
+ "base": "VnModel",
+ "mixins": {
+ "Loggable": true
+ },
+ "options": {
+ "mysql": {
+ "table": "entryType"
+ }
+ },
+ "properties": {
+ "code": {
+ "type": "string",
+ "id": true,
+ "description": "Identifier"
+ },
+ "description": {
+ "type": "string"
+ },
+ "isInformal": {
+ "type": "boolean"
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/entry/back/models/entry.json b/modules/entry/back/models/entry.json
index ab451219e..833edf14d 100644
--- a/modules/entry/back/models/entry.json
+++ b/modules/entry/back/models/entry.json
@@ -35,9 +35,9 @@
},
"isVirtual": {
"type": "boolean",
- "mysql": {
- "columnName": "isRaid"
- }
+ "mysql": {
+ "columnName": "isRaid"
+ }
},
"isRaid": {
"type": "boolean"
@@ -53,9 +53,9 @@
},
"observation": {
"type": "string",
- "mysql": {
- "columnName": "evaNotes"
- }
+ "mysql": {
+ "columnName": "evaNotes"
+ }
},
"loadPriority": {
"type": "number"
@@ -101,6 +101,11 @@
"type": "belongsTo",
"model": "Account",
"foreignKey": "observationEditorFk"
+ },
+ "entryType": {
+ "type": "belongsTo",
+ "model": "EntryType",
+ "foreignKey": "typeFk"
}
}
-}
+}
\ No newline at end of file
diff --git a/modules/invoiceIn/back/methods/invoice-in/exchangeRateUpdate.js b/modules/invoiceIn/back/methods/invoice-in/exchangeRateUpdate.js
index 3ad06b242..989b1d4a2 100644
--- a/modules/invoiceIn/back/methods/invoice-in/exchangeRateUpdate.js
+++ b/modules/invoiceIn/back/methods/invoice-in/exchangeRateUpdate.js
@@ -54,6 +54,20 @@ module.exports = Self => {
value: rate
});
}
+ const monday = 1;
+ if (xmlDateWithoutTime.getDay() === monday) {
+ const saturday = new Date(xmlDateWithoutTime);
+ saturday.setDate(xmlDateWithoutTime.getDate() - 2);
+ const sunday = new Date(xmlDateWithoutTime);
+ sunday.setDate(xmlDateWithoutTime.getDate() - 1);
+
+ for (const date of [saturday, sunday]) {
+ await models.ReferenceRate.upsertWithWhere(
+ {currencyFk: currency.id, dated: date},
+ {currencyFk: currency.id, dated: date, value: rate}
+ );
+ }
+ }
}
}
}
diff --git a/modules/invoiceIn/back/methods/invoice-in/specs/toUnbook.spec.js b/modules/invoiceIn/back/methods/invoice-in/specs/toUnbook.spec.js
new file mode 100644
index 000000000..b7d98e307
--- /dev/null
+++ b/modules/invoiceIn/back/methods/invoice-in/specs/toUnbook.spec.js
@@ -0,0 +1,32 @@
+const models = require('vn-loopback/server/server').models;
+
+describe('invoiceIn toUnbook()', () => {
+ it('should check that invoiceIn is unbooked', async() => {
+ const userId = 1;
+ const ctx = {
+ req: {
+
+ accessToken: {userId: userId},
+ headers: {origin: 'http://localhost:5000'},
+ }
+ };
+ const invoiceInId = 1;
+ const tx = await models.InvoiceIn.beginTransaction({});
+ const options = {transaction: tx};
+
+ try {
+ await models.InvoiceIn.toBook(ctx, invoiceInId, options);
+ const bookEntry = await models.InvoiceIn.toUnbook(ctx, invoiceInId, options);
+ const invoiceIn = await models.InvoiceIn.findById(invoiceInId, null, options);
+
+ expect(bookEntry.accountingEntries).toEqual(4);
+ expect(bookEntry.isLinked).toBeFalsy();
+ expect(invoiceIn.isBooked).toEqual(false);
+
+ await tx.rollback();
+ } catch (e) {
+ await tx.rollback();
+ throw e;
+ }
+ });
+});
diff --git a/modules/invoiceIn/back/methods/invoice-in/toUnbook.js b/modules/invoiceIn/back/methods/invoice-in/toUnbook.js
new file mode 100644
index 000000000..a697e9ddc
--- /dev/null
+++ b/modules/invoiceIn/back/methods/invoice-in/toUnbook.js
@@ -0,0 +1,80 @@
+module.exports = Self => {
+ Self.remoteMethodCtx('toUnbook', {
+ description: 'To unbook the invoiceIn',
+ accessType: 'WRITE',
+ accepts: {
+ arg: 'id',
+ type: 'number',
+ required: true,
+ description: 'The invoiceIn id',
+ http: {source: 'path'}
+ },
+ returns: {
+ type: 'object',
+ root: true
+ },
+ http: {
+ path: '/:id/toUnbook',
+ verb: 'POST'
+ }
+ });
+
+ Self.toUnbook = async(ctx, invoiceInId, options) => {
+ let tx;
+ const models = Self.app.models;
+ const myOptions = {userId: ctx.req.accessToken.userId};
+
+ if (typeof options == 'object')
+ Object.assign(myOptions, options);
+
+ if (!myOptions.transaction) {
+ tx = await Self.beginTransaction({});
+ myOptions.transaction = tx;
+ }
+
+ try {
+ let isLinked;
+ let accountingEntries;
+
+ let bookEntry = await models.Xdiario.findOne({
+ fields: ['ASIEN'],
+ where: {
+ and: [
+ {key: invoiceInId},
+ {enlazado: false},
+ {enlazadoSage: false}
+ ]
+ }
+ }, myOptions);
+
+ let asien = bookEntry?.ASIEN;
+ if (asien) {
+ accountingEntries = await models.Xdiario.count({ASIEN: asien}, myOptions);
+
+ await models.Xdiario.destroyAll({ASIEN: asien}, myOptions);
+ await Self.updateAll({id: invoiceInId}, {isBooked: false}, myOptions);
+ } else {
+ const linkedBookEntry = await models.Xdiario.findOne({
+ fields: ['ASIEN'],
+ where: {
+ key: invoiceInId,
+ and: [{or: [{enlazado: true, enlazadoSage: true}]}]
+ }
+ }, myOptions);
+
+ asien = linkedBookEntry?.ASIEN;
+ isLinked = true;
+ }
+ if (tx) await tx.commit();
+
+ return {
+ isLinked,
+ bookEntry: asien,
+ accountingEntries
+ };
+ } catch (e) {
+ if (tx) await tx.rollback();
+ throw e;
+ }
+ };
+};
diff --git a/modules/invoiceIn/back/methods/invoice-in/updateInvoiceIn.js b/modules/invoiceIn/back/methods/invoice-in/updateInvoiceIn.js
new file mode 100644
index 000000000..92a1ba8ee
--- /dev/null
+++ b/modules/invoiceIn/back/methods/invoice-in/updateInvoiceIn.js
@@ -0,0 +1,104 @@
+module.exports = Self => {
+ Self.remoteMethodCtx('updateInvoiceIn', {
+ description: 'To update the invoiceIn attributes',
+ accessType: 'WRITE',
+ accepts: [{
+ arg: 'id',
+ type: 'number',
+ required: true,
+ description: 'The invoiceIn id',
+ http: {source: 'path'}
+ }, {
+ arg: 'supplierFk',
+ type: 'number',
+ required: true
+ }, {
+ arg: 'supplierRef',
+ type: 'any',
+ }, {
+ arg: 'issued',
+ type: 'any',
+ }, {
+ arg: 'operated',
+ type: 'any',
+ }, {
+ arg: 'deductibleExpenseFk',
+ type: 'any',
+ }, {
+ arg: 'dmsFk',
+ type: 'any',
+ }, {
+ arg: 'bookEntried',
+ type: 'any',
+ }, {
+ arg: 'booked',
+ type: 'any',
+ }, {
+ arg: 'currencyFk',
+ type: 'number',
+ required: true
+ }, {
+ arg: 'companyFk',
+ type: 'any',
+ }, {
+ arg: 'withholdingSageFk',
+ type: 'any',
+ },
+ ],
+ returns: {
+ type: 'object',
+ root: true
+ },
+ http: {
+ path: '/:id/updateInvoiceIn',
+ verb: 'PATCH'
+ }
+ });
+
+ Self.updateInvoiceIn = async(ctx,
+ id,
+ supplierFk,
+ supplierRef,
+ issued,
+ operated,
+ deductibleExpenseFk,
+ dmsFk,
+ bookEntried,
+ booked,
+ currencyFk,
+ companyFk,
+ withholdingSageFk,
+ options
+ ) => {
+ let tx;
+ const myOptions = {userId: ctx.req.accessToken.userId};
+
+ if (typeof options == 'object') Object.assign(myOptions, options);
+
+ if (!myOptions.transaction) {
+ tx = await Self.beginTransaction({});
+ myOptions.transaction = tx;
+ }
+
+ try {
+ const invoiceIn = await Self.findById(id, null, myOptions);
+ invoiceIn.updateAttributes({supplierFk,
+ supplierRef,
+ issued,
+ operated,
+ deductibleExpenseFk,
+ dmsFk,
+ bookEntried,
+ booked,
+ currencyFk,
+ companyFk,
+ withholdingSageFk
+ }, myOptions);
+ if (tx) await tx.commit();
+ return invoiceIn;
+ } catch (e) {
+ if (tx) await tx.rollback();
+ throw e;
+ }
+ };
+};
diff --git a/modules/invoiceIn/back/models/invoice-in.js b/modules/invoiceIn/back/models/invoice-in.js
index 31cdc1abe..1e69c0ef8 100644
--- a/modules/invoiceIn/back/models/invoice-in.js
+++ b/modules/invoiceIn/back/models/invoice-in.js
@@ -11,6 +11,8 @@ module.exports = Self => {
require('../methods/invoice-in/getSerial')(Self);
require('../methods/invoice-in/corrective')(Self);
require('../methods/invoice-in/exchangeRateUpdate')(Self);
+ require('../methods/invoice-in/toUnbook')(Self);
+ require('../methods/invoice-in/updateInvoiceIn')(Self);
Self.rewriteDbError(function(err) {
if (err.code === 'ER_ROW_IS_REFERENCED_2' && err.sqlMessage.includes('vehicleInvoiceIn'))
diff --git a/modules/invoiceIn/front/basic-data/index.html b/modules/invoiceIn/front/basic-data/index.html
index a22abbb33..fbb9b05a2 100644
--- a/modules/invoiceIn/front/basic-data/index.html
+++ b/modules/invoiceIn/front/basic-data/index.html
@@ -1,4 +1,4 @@
-
+
{
Self.remoteMethodCtx('download', {
@@ -66,7 +67,7 @@ module.exports = Self => {
console.error(err);
});
- if (process.env.NODE_ENV == 'test') {
+ if (!isProduction()) {
try {
await fs.access(file.path);
} catch (error) {
diff --git a/modules/invoiceOut/back/models/invoice-out.js b/modules/invoiceOut/back/models/invoice-out.js
index e4fcc1a69..b0e05b626 100644
--- a/modules/invoiceOut/back/models/invoice-out.js
+++ b/modules/invoiceOut/back/models/invoice-out.js
@@ -1,6 +1,7 @@
const print = require('vn-print');
const path = require('path');
const UserError = require('vn-loopback/util/user-error');
+const isProduction = require('vn-loopback/server/boot/isProduction');
module.exports = Self => {
require('../methods/invoiceOut/filter')(Self);
@@ -59,7 +60,7 @@ module.exports = Self => {
hasPdf: true
}, options);
- if (process.env.NODE_ENV !== 'test') {
+ if (isProduction()) {
await print.storage.write(buffer, {
type: 'invoice',
path: pdfFile.path,
diff --git a/modules/invoiceOut/front/index/manual/index.html b/modules/invoiceOut/front/index/manual/index.html
index 5872911e4..3b991618d 100644
--- a/modules/invoiceOut/front/index/manual/index.html
+++ b/modules/invoiceOut/front/index/manual/index.html
@@ -27,7 +27,7 @@
{
accessType: 'READ',
accepts: [{
arg: 'barcode',
- type: 'number',
+ type: 'string',
required: true,
description: 'barcode'
}],
@@ -18,7 +18,7 @@ module.exports = Self => {
}
});
- Self.toItem = async(barcode, options) => {
+ Self.toItem = async (barcode, options) => {
const myOptions = {};
if (typeof options == 'object')
diff --git a/modules/item/back/methods/item/specs/getBalance.spec.js b/modules/item/back/methods/item/specs/getBalance.spec.js
index 5e5148595..728b5f33e 100644
--- a/modules/item/back/methods/item/specs/getBalance.spec.js
+++ b/modules/item/back/methods/item/specs/getBalance.spec.js
@@ -64,7 +64,7 @@ describe('item getBalance()', () => {
const secondItemBalance = await models.Item.getBalance(ctx, secondFilter, options);
expect(firstItemBalance[9].claimFk).toEqual(null);
- expect(secondItemBalance[4].claimFk).toEqual(2);
+ expect(secondItemBalance[7].claimFk).toEqual(2);
await tx.rollback();
} catch (e) {
diff --git a/modules/item/back/models/expense.json b/modules/item/back/models/expense.json
index 468063602..e661cbc66 100644
--- a/modules/item/back/models/expense.json
+++ b/modules/item/back/models/expense.json
@@ -9,7 +9,7 @@
"properties": {
"id": {
"id": true,
- "type": "number",
+ "type": "string",
"description": "Identifier"
},
"name": {
diff --git a/modules/item/back/models/item.json b/modules/item/back/models/item.json
index 9d48dcbfb..10cff3e04 100644
--- a/modules/item/back/models/item.json
+++ b/modules/item/back/models/item.json
@@ -155,6 +155,9 @@
"minQuantity": {
"type": "number",
"description": "Min quantity"
+ },
+ "photoMotivation": {
+ "type": "string"
}
},
"relations": {
diff --git a/modules/mdb/back/methods/mdbVersion/upload.js b/modules/mdb/back/methods/mdbVersion/upload.js
index 58fc46abb..64de72679 100644
--- a/modules/mdb/back/methods/mdbVersion/upload.js
+++ b/modules/mdb/back/methods/mdbVersion/upload.js
@@ -1,6 +1,7 @@
const fs = require('fs-extra');
const path = require('path');
const UserError = require('vn-loopback/util/user-error');
+const isProduction = require('vn-loopback/server/boot/isProduction');
module.exports = Self => {
Self.remoteMethodCtx('upload', {
@@ -111,7 +112,7 @@ module.exports = Self => {
const destinationFile = path.join(
accessContainer.client.root, accessContainer.name, appName, `${toVersion}.7z`);
- if (process.env.NODE_ENV == 'test')
+ if (!isProduction())
await fs.unlink(srcFile);
else {
await fs.move(srcFile, destinationFile, {
diff --git a/modules/monitor/back/methods/sales-monitor/specs/salesFilter.spec.js b/modules/monitor/back/methods/sales-monitor/specs/salesFilter.spec.js
index bdafd14e2..c3da7f08b 100644
--- a/modules/monitor/back/methods/sales-monitor/specs/salesFilter.spec.js
+++ b/modules/monitor/back/methods/sales-monitor/specs/salesFilter.spec.js
@@ -151,7 +151,7 @@ describe('SalesMonitor salesFilter()', () => {
const result = await models.SalesMonitor.salesFilter(ctx, filter, options);
const firstRow = result[0];
- expect(result.length).toEqual(12);
+ expect(result.length).toEqual(15);
expect(firstRow.alertLevel).not.toEqual(0);
await tx.rollback();
diff --git a/modules/shelving/back/model-config.json b/modules/shelving/back/model-config.json
index 89a0832b0..6f3ffb5ea 100644
--- a/modules/shelving/back/model-config.json
+++ b/modules/shelving/back/model-config.json
@@ -11,6 +11,12 @@
"Sector": {
"dataSource": "vn"
},
+ "SectorCollection": {
+ "dataSource": "vn"
+ },
+ "SectorCollectionSaleGroup": {
+ "dataSource": "vn"
+ },
"Train": {
"dataSource": "vn"
}
diff --git a/modules/shelving/back/models/sectorCollection.json b/modules/shelving/back/models/sectorCollection.json
new file mode 100644
index 000000000..bf2cc7985
--- /dev/null
+++ b/modules/shelving/back/models/sectorCollection.json
@@ -0,0 +1,24 @@
+{
+ "name": "SectorCollection",
+ "base": "VnModel",
+ "options": {
+ "mysql": {
+ "table": "sectorCollection"
+ }
+ },
+ "properties": {
+ "id": {
+ "type": "number",
+ "id": true
+ },
+ "created": {
+ "type": "date"
+ },
+ "userFk": {
+ "type": "number"
+ },
+ "sectorFk": {
+ "type": "number"
+ }
+ }
+}
diff --git a/modules/shelving/back/models/sectorCollectionSaleGroup.json b/modules/shelving/back/models/sectorCollectionSaleGroup.json
new file mode 100644
index 000000000..421bdc885
--- /dev/null
+++ b/modules/shelving/back/models/sectorCollectionSaleGroup.json
@@ -0,0 +1,30 @@
+{
+ "name": "SectorCollectionSaleGroup",
+ "base": "VnModel",
+ "options": {
+ "mysql": {
+ "table": "sectorCollectionSaleGroup"
+ }
+ },
+ "properties": {
+ "id": {
+ "type": "number",
+ "id": true
+ },
+ "created": {
+ "type": "date"
+ }
+ },
+ "relations": {
+ "sectorCollection": {
+ "type": "belongsTo",
+ "model": "SectorCollection",
+ "foreignKey": "sectorCollectionFk"
+ },
+ "saleGroup": {
+ "type": "belongsTo",
+ "model": "SaleGroup",
+ "foreignKey": "saleGroupFk"
+ }
+ }
+}
diff --git a/modules/supplier/back/methods/supplier/getItemsPackaging.js b/modules/supplier/back/methods/supplier/getItemsPackaging.js
index c06195a55..8a27c89c4 100644
--- a/modules/supplier/back/methods/supplier/getItemsPackaging.js
+++ b/modules/supplier/back/methods/supplier/getItemsPackaging.js
@@ -33,7 +33,7 @@ module.exports = Self => {
JOIN vn.item i ON i.id = b.itemFk
WHERE e.id = ? AND e.supplierFk = ?
GROUP BY i.id
- ) SELECT i.id, i.name, et.quantity, SUM(b.quantity) quantityTotal, et.printedStickers
+ ) SELECT i.id, i.name, et.quantity, SUM(b.quantity) quantityTotal, et.printedStickers, ic.url
FROM vn.buy b
JOIN vn.item i ON i.id = b.itemFk
JOIN vn.entry e ON e.id = b.entryFk
@@ -41,6 +41,7 @@ module.exports = Self => {
JOIN vn.buyConfig bc ON bc.monthsAgo
JOIN vn.travel t ON t.id = e.travelFk
LEFT JOIN entryTmp et ON et.id = i.id
+ JOIN hedera.imageConfig ic
WHERE e.supplierFk = ?
AND i.family IN ('EMB', 'CONT')
AND b.created > (util.VN_CURDATE() - INTERVAL bc.monthsAgo MONTH)
diff --git a/modules/ticket/back/methods/ticket-tracking/specs/setDelivered.spec.js b/modules/ticket/back/methods/ticket-tracking/specs/setDelivered.spec.js
index 3d37221c4..3d39ea278 100644
--- a/modules/ticket/back/methods/ticket-tracking/specs/setDelivered.spec.js
+++ b/modules/ticket/back/methods/ticket-tracking/specs/setDelivered.spec.js
@@ -2,10 +2,12 @@ const models = require('vn-loopback/server/server').models;
const LoopBackContext = require('loopback-context');
describe('ticket setDelivered()', () => {
- const userId = 50;
+ const userId = 49;
const activeCtx = {
accessToken: {userId: userId},
+ __: value => value
};
+ const ctx = {req: activeCtx};
beforeAll(async() => {
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
@@ -19,8 +21,6 @@ describe('ticket setDelivered()', () => {
try {
const options = {transaction: tx};
- const ctx = {req: {accessToken: {userId: 49}}};
-
const originalTicketOne = await models.Ticket.findById(8, null, options);
const originalTicketTwo = await models.Ticket.findById(10, null, options);
diff --git a/modules/ticket/back/methods/ticket/addSale.js b/modules/ticket/back/methods/ticket/addSale.js
index 826de6e12..8dc7a633c 100644
--- a/modules/ticket/back/methods/ticket/addSale.js
+++ b/modules/ticket/back/methods/ticket/addSale.js
@@ -10,8 +10,8 @@ module.exports = Self => {
http: {source: 'path'}
},
{
- arg: 'itemId',
- type: 'number',
+ arg: 'barcode',
+ type: 'any',
required: true
},
{
@@ -29,7 +29,7 @@ module.exports = Self => {
}
});
- Self.addSale = async(ctx, id, itemId, quantity, options) => {
+ Self.addSale = async(ctx, id, barcode, quantity, options) => {
const $t = ctx.req.__; // $translate
const models = Self.app.models;
const myOptions = {userId: ctx.req.accessToken.userId};
@@ -46,7 +46,9 @@ module.exports = Self => {
try {
await models.Ticket.isEditableOrThrow(ctx, id, myOptions);
+ const itemId = await models.ItemBarcode.toItem(barcode, myOptions);
const item = await models.Item.findById(itemId, null, myOptions);
+
const ticket = await models.Ticket.findById(id, {
include: {
relation: 'client',
diff --git a/modules/ticket/back/methods/ticket/addSaleByCode.js b/modules/ticket/back/methods/ticket/addSaleByCode.js
deleted file mode 100644
index ca3d2cb07..000000000
--- a/modules/ticket/back/methods/ticket/addSaleByCode.js
+++ /dev/null
@@ -1,56 +0,0 @@
-const UserError = require('vn-loopback/util/user-error');
-module.exports = Self => {
- Self.remoteMethodCtx('addSaleByCode', {
- description: 'Add a collection',
- accessType: 'WRITE',
- accepts: [
- {
- arg: 'barcode',
- type: 'string',
- required: true
- }, {
- arg: 'quantity',
- type: 'number',
- required: true
- }, {
- arg: 'ticketFk',
- type: 'number',
- required: true
- }, {
- arg: 'warehouseFk',
- type: 'number',
- required: true
- },
-
- ],
- http: {
- path: `/addSaleByCode`,
- verb: 'POST'
- },
- });
-
- Self.addSaleByCode = async(ctx, barcode, quantity, ticketFk, warehouseFk, options) => {
- const myOptions = {userId: ctx.req.accessToken.userId};
- let tx;
-
- if (typeof options == 'object')
- Object.assign(myOptions, options);
-
- if (!myOptions.transaction) {
- tx = await Self.beginTransaction({});
- myOptions.transaction = tx;
- }
-
- try {
- const [[item]] = await Self.rawSql('CALL vn.item_getInfo(?,?)', [barcode, warehouseFk], myOptions);
- if (!item?.available) throw new UserError('We do not have availability for the selected item');
-
- await Self.rawSql('CALL vn.collection_addItem(?, ?, ?)', [item.id, quantity, ticketFk], myOptions);
-
- if (tx) await tx.commit();
- } catch (e) {
- if (tx) await tx.rollback();
- throw e;
- }
- };
-};
diff --git a/modules/ticket/back/methods/ticket/isEditableOrThrow.js b/modules/ticket/back/methods/ticket/isEditableOrThrow.js
index 16cff84f1..555063093 100644
--- a/modules/ticket/back/methods/ticket/isEditableOrThrow.js
+++ b/modules/ticket/back/methods/ticket/isEditableOrThrow.js
@@ -8,18 +8,13 @@ module.exports = Self => {
if (typeof options == 'object')
Object.assign(myOptions, options);
- const state = await models.TicketState.findOne({
- where: {ticketFk: id}
- }, myOptions);
-
+ const state = await models.TicketState.findOne({where: {ticketFk: id}}, myOptions);
const isRoleAdvanced = await models.ACL.checkAccessAcl(ctx, 'Ticket', 'isRoleAdvanced', '*');
+ const isProductionReviewer = await models.ACL.checkAccessAcl(ctx, 'Sale', 'isInPreparing', '*');
const canEditWeeklyTicket = await models.ACL.checkAccessAcl(ctx, 'Ticket', 'canEditWeekly', 'WRITE');
const alertLevel = state ? state.alertLevel : null;
const ticket = await models.Ticket.findById(id, {
- fields: ['clientFk'],
- include: {
- relation: 'client'
- }
+ fields: ['clientFk'], include: {relation: 'client'}
}, myOptions);
const isLocked = await models.Ticket.isLocked(id, myOptions);
@@ -29,10 +24,24 @@ module.exports = Self => {
const isNormalClient = ticket && ticket.client().typeFk == 'normal';
const isEditable = !(alertLevelGreaterThanZero && isNormalClient);
+ const ticketCollection = await models.TicketCollection.findOne({
+ include: {relation: 'collection'}, where: {ticketFk: id}
+ }, myOptions);
+ let isOwner = ticketCollection?.collection()?.workerFk === ctx.req.accessToken.userId;
+
+ if (!isOwner) {
+ const saleGroup = await models.SaleGroup.findOne({fields: ['id'], where: {ticketFk: id}}, myOptions);
+ const sectorCollectionSaleGroup = saleGroup && await models.SectorCollectionSaleGroup.findOne({
+ include: {relation: 'sectorCollection'}, where: {saleGroupFk: saleGroup.id}
+ }, myOptions);
+
+ isOwner = sectorCollectionSaleGroup?.sectorCollection()?.userFk === ctx.req.accessToken.userId;
+ }
+
if (!ticket)
throw new ForbiddenError(`The ticket doesn't exist.`);
- if (!isEditable && !isRoleAdvanced)
+ if (!isEditable && !isRoleAdvanced && !isProductionReviewer && !isOwner)
throw new ForbiddenError(`This ticket is not editable.`);
if (isLocked && !isWeekly)
diff --git a/modules/ticket/back/methods/ticket/specs/addSaleByCode.spec.js b/modules/ticket/back/methods/ticket/specs/addSaleByCode.spec.js
deleted file mode 100644
index b97139178..000000000
--- a/modules/ticket/back/methods/ticket/specs/addSaleByCode.spec.js
+++ /dev/null
@@ -1,39 +0,0 @@
-const {models} = require('vn-loopback/server/server');
-const LoopBackContext = require('loopback-context');
-
-describe('Ticket addSaleByCode()', () => {
- const quantity = 3;
- const ticketFk = 13;
- const warehouseFk = 1;
- beforeAll(async() => {
- activeCtx = {
- req: {
- accessToken: {userId: 9},
- headers: {origin: 'http://localhost'},
- __: value => value
- }
- };
- spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
- active: activeCtx
- });
- });
-
- it('should add a new sale', async() => {
- const tx = await models.Ticket.beginTransaction({});
-
- try {
- const options = {transaction: tx};
- const code = '1111111111';
-
- const salesBefore = await models.Sale.find(null, options);
- await models.Ticket.addSaleByCode(activeCtx, code, quantity, ticketFk, warehouseFk, options);
- const salesAfter = await models.Sale.find(null, options);
-
- expect(salesAfter.length).toEqual(salesBefore.length + 1);
- await tx.rollback();
- } catch (e) {
- await tx.rollback();
- throw e;
- }
- });
-});
diff --git a/modules/ticket/back/methods/ticket/specs/filter.spec.js b/modules/ticket/back/methods/ticket/specs/filter.spec.js
index e495a41f5..8008acfaf 100644
--- a/modules/ticket/back/methods/ticket/specs/filter.spec.js
+++ b/modules/ticket/back/methods/ticket/specs/filter.spec.js
@@ -68,7 +68,7 @@ describe('ticket filter()', () => {
const filter = {};
const result = await models.Ticket.filter(ctx, filter, options);
- expect(result.length).toEqual(7);
+ expect(result.length).toEqual(10);
await tx.rollback();
} catch (e) {
diff --git a/modules/ticket/back/methods/ticket/specs/priceDifference.spec.js b/modules/ticket/back/methods/ticket/specs/priceDifference.spec.js
index e5c06b6dd..7dc1c8ed2 100644
--- a/modules/ticket/back/methods/ticket/specs/priceDifference.spec.js
+++ b/modules/ticket/back/methods/ticket/specs/priceDifference.spec.js
@@ -42,7 +42,7 @@ describe('sale priceDifference()', () => {
try {
const options = {transaction: tx};
- const ctx = {req: {accessToken: {userId: 1106}}};
+ const ctx = {req: {accessToken: {userId: 1105}}};
ctx.args = {
id: 1,
landed: Date.vnNew(),
@@ -84,7 +84,7 @@ describe('sale priceDifference()', () => {
const {items} = await models.Ticket.priceDifference(ctx, options);
- expect(items[0].movable).toEqual(410);
+ expect(items[0].movable).toEqual(386);
expect(items[1].movable).toEqual(1810);
await tx.rollback();
diff --git a/modules/ticket/back/methods/ticket/specs/state.spec.js b/modules/ticket/back/methods/ticket/specs/state.spec.js
index 947e72b79..d908aa2ef 100644
--- a/modules/ticket/back/methods/ticket/specs/state.spec.js
+++ b/modules/ticket/back/methods/ticket/specs/state.spec.js
@@ -7,6 +7,7 @@ describe('ticket state()', () => {
const productionId = 49;
const activeCtx = {
accessToken: {userId: 9},
+ __: value => value
};
const ctx = {req: activeCtx};
const now = Date.vnNew();
@@ -88,7 +89,8 @@ describe('ticket state()', () => {
const ticket = await models.Ticket.create(sampleTicket, options);
activeCtx.accessToken.userId = productionId;
- const params = {ticketFk: ticket.id, stateFk: 3};
+ const stateOk = await models.State.findOne({where: {code: 'OK'}}, options);
+ const params = {ticketFk: ticket.id, stateFk: stateOk.id};
const ticketTracking = await models.Ticket.state(ctx, params, options);
@@ -112,16 +114,68 @@ describe('ticket state()', () => {
const options = {transaction: tx};
const ticket = await models.Ticket.create(sampleTicket, options);
- const ctx = {req: {accessToken: {userId: 18}}};
+ activeCtx.accessToken.userId = salesPersonId;
const assignedState = await models.State.findOne({where: {code: 'PICKER_DESIGNED'}}, options);
- const params = {ticketFk: ticket.id, stateFk: assignedState.id, userFk: 1};
- const res = await models.Ticket.state(ctx, params, options);
+ const paramsAssigned = {ticketFk: ticket.id, stateFk: assignedState.id, userFk: 1};
+ const resAssigned = await models.Ticket.state(ctx, paramsAssigned, options);
- expect(res.ticketFk).toBe(params.ticketFk);
- expect(res.stateFk).toBe(params.stateFk);
- expect(res.userFk).toBe(params.userFk);
- expect(res.userFk).toBe(1);
- expect(res.id).toBeDefined();
+ expect(resAssigned.ticketFk).toBe(paramsAssigned.ticketFk);
+ expect(resAssigned.stateFk).toBe(paramsAssigned.stateFk);
+ expect(resAssigned.userFk).toBe(paramsAssigned.userFk);
+ expect(resAssigned.userFk).toBe(1);
+ expect(resAssigned.id).toBeDefined();
+
+ activeCtx.accessToken.userId = productionId;
+ const packedState = await models.State.findOne({where: {code: 'PACKED'}}, options);
+ const paramsPacked = {ticketFk: ticket.id, stateFk: packedState.id, userFk: salesPersonId};
+ const resPacked = await models.Ticket.state(ctx, paramsPacked, options);
+
+ expect(resPacked.stateFk).toBe(paramsPacked.stateFk);
+
+ await tx.rollback();
+ } catch (e) {
+ await tx.rollback();
+ throw e;
+ }
+ });
+
+ it('Should equalize the quantities of quantity and originalQuantity' +
+ ' if they are different', async() => {
+ const tx = await models.TicketTracking.beginTransaction({});
+
+ try {
+ const options = {transaction: tx};
+
+ const ticket = await models.Ticket.create(sampleTicket, options);
+ activeCtx.accessToken.userId = salesPersonId;
+
+ const sampleSale = {
+ ticketFk: ticket.id,
+ itemFk: 1,
+ concept: 'Test',
+ quantity: 10,
+ originalQuantity: 6
+ };
+ await models.Sale.create(sampleSale, options);
+ const assignedState = await models.State.findOne({where: {code: 'PICKER_DESIGNED'}}, options);
+ const paramsAssigned = {ticketFk: ticket.id, stateFk: assignedState.id, userFk: 1};
+ const resAssigned = await models.Ticket.state(ctx, paramsAssigned, options);
+
+ expect(resAssigned.ticketFk).toBe(paramsAssigned.ticketFk);
+ expect(resAssigned.stateFk).toBe(paramsAssigned.stateFk);
+ expect(resAssigned.userFk).toBe(paramsAssigned.userFk);
+ expect(resAssigned.userFk).toBe(1);
+ expect(resAssigned.id).toBeDefined();
+
+ activeCtx.accessToken.userId = productionId;
+ const packedState = await models.State.findOne({where: {code: 'PACKED'}}, options);
+ const paramsPacked = {ticketFk: ticket.id, stateFk: packedState.id, userFk: salesPersonId};
+ const resPacked = await models.Ticket.state(ctx, paramsPacked, options);
+
+ const sale = await models.Sale.findOne({where: {ticketFk: ticket.id}}, options);
+
+ expect(resPacked.stateFk).toBe(paramsPacked.stateFk);
+ expect(sale.quantity).toBe(sale.originalQuantity);
await tx.rollback();
} catch (e) {
diff --git a/modules/ticket/back/methods/ticket/state.js b/modules/ticket/back/methods/ticket/state.js
index fea9475f8..9b0b862f2 100644
--- a/modules/ticket/back/methods/ticket/state.js
+++ b/modules/ticket/back/methods/ticket/state.js
@@ -64,7 +64,63 @@ module.exports = Self => {
if ((ticketState && !oldStateAllowed) || !newStateAllowed)
throw new UserError(`You don't have enough privileges`, 'ACCESS_DENIED');
- await Self.rawSql(`CALL vn.ticket_setState(?, ?)`, [params.ticketFk, params.code], myOptions);
+ const ticket = await models.Ticket.findById(params.ticketFk, {
+ include: [{
+ relation: 'client',
+ scope: {
+ fields: ['salesPersonFk']
+ }
+ }],
+ fields: ['id', 'clientFk']
+ }, myOptions);
+
+ const salesPersonFk = ticket.client().salesPersonFk;
+ if (salesPersonFk) {
+ const sales = await Self.rawSql(`
+ SELECT DISTINCT s.id,
+ s.itemFk,
+ s.concept,
+ s.originalQuantity AS oldQuantity,
+ s.quantity AS newQuantity
+ FROM vn.sale s
+ JOIN vn.saleTracking st ON st.saleFk = s.id
+ JOIN vn.ticket t ON t.id = s.ticketFk
+ JOIN vn.client c ON c.id = t.clientFk
+ JOIN vn.ticketState ts ON ts.ticketFk = t.id
+ JOIN vn.state s2 ON s2.id = ts.stateFk
+ WHERE s.ticketFk = ?
+ AND st.isChecked
+ AND s.originalQuantity IS NOT NULL
+ AND s.originalQuantity <> s.quantity
+ AND s2.\`order\` < (SELECT \`order\` FROM vn.state WHERE code = 'CHECKED')
+ ORDER BY st.created DESC
+ `, [params.ticketFk], myOptions);
+
+ let changes = '';
+ const url = await models.Url.getUrl();
+ const $t = ctx.req.__;
+ for (let sale of sales) {
+ changes += `\r\n-` + $t('Changes in sales', {
+ itemId: sale.itemFk,
+ concept: sale.concept,
+ oldQuantity: sale.oldQuantity,
+ newQuantity: sale.newQuantity,
+ itemUrl: `${url}item/${sale.itemFk}/summary`
+ });
+ const currentSale = await models.Sale.findById(sale.id, null, myOptions);
+ await currentSale.updateAttributes({
+ originalQuantity: currentSale.quantity
+ }, myOptions);
+ }
+
+ const message = $t('Changed sale quantity', {
+ ticketId: ticket.id,
+ changes: changes,
+ ticketUrl: `${url}ticket/${ticket.id}/sale`
+ });
+ await models.Chat.sendCheckingPresence(ctx, salesPersonFk, message, myOptions);
+ }
+ await Self.rawSql(`CALL vn.ticket_setState(?, ?)`, [ticket.id, params.code], myOptions);
const ticketTracking = await models.TicketTracking.findOne({
where: {ticketFk: params.ticketFk},
diff --git a/modules/ticket/back/models/saleGroup.json b/modules/ticket/back/models/saleGroup.json
index d5cf82cb5..aa78b4167 100644
--- a/modules/ticket/back/models/saleGroup.json
+++ b/modules/ticket/back/models/saleGroup.json
@@ -14,6 +14,9 @@
},
"parkingFk": {
"type": "number"
+ },
+ "ticketFk": {
+ "type": "number"
}
},
"relations": {
diff --git a/modules/ticket/back/models/specs/sale.spec.js b/modules/ticket/back/models/specs/sale.spec.js
index d078dc8e2..1aa40802b 100644
--- a/modules/ticket/back/models/specs/sale.spec.js
+++ b/modules/ticket/back/models/specs/sale.spec.js
@@ -1,361 +1,318 @@
/* eslint max-len: ["error", { "code": 150 }]*/
-
-const models = require('vn-loopback/server/server').models;
+const {models} = require('vn-loopback/server/server');
const LoopBackContext = require('loopback-context');
describe('sale model ', () => {
- const ctx = {
- req: {
- accessToken: {userId: 9},
- headers: {origin: 'localhost:5000'},
- __: () => {}
- }
- };
- function getActiveCtx(userId) {
- return {
- active: {
- accessToken: {userId},
- http: {
- req: {
- headers: {origin: 'http://localhost'}
- }
- }
- }
- };
+ const developerId = 9;
+ const buyerId = 35;
+ const employeeId = 1;
+ const productionId = 49;
+ const salesPersonId = 18;
+ const reviewerId = 130;
+
+ const barcode = '4444444444';
+ const ticketCollectionProd = 34;
+ const ticketCollectionSalesPerson = 35;
+ const previaTicketSalesPerson = 36;
+ const previaTicketProd = 37;
+ const notEditableError = 'This ticket is not editable.';
+
+ const ctx = getCtx(developerId);
+ let tx;
+ let opts;
+
+ function getCtx(userId, active = false) {
+ const accessToken = {userId};
+ const headers = {origin: 'localhost:5000'};
+ if (!active) return {req: {accessToken, headers, __: () => {}}};
+ return {active: {accessToken, http: {req: {headers}}}};
}
+ beforeEach(async() => {
+ tx = await models.Sale.beginTransaction({});
+ opts = {transaction: tx};
+ });
+
+ afterEach(async() => await tx.rollback());
+
describe('quantity field ', () => {
it('should add quantity if the quantity is greater than it should be and is role advanced', async() => {
const saleId = 17;
- const buyerId = 35;
- const ctx = {
- req: {
- accessToken: {userId: buyerId},
- headers: {origin: 'localhost:5000'},
- __: () => {}
- }
- };
- const tx = await models.Sale.beginTransaction({});
- spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getActiveCtx(buyerId));
- spyOn(models.Sale, 'rawSql').and.callFake((sqlStatement, params, options) => {
+ const ctx = getCtx(buyerId);
+
+ spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getCtx(buyerId, true));
+ spyOn(models.Sale, 'rawSql').and.callFake((sqlStatement, params, opts) => {
if (sqlStatement.includes('catalog_calcFromItem')) {
sqlStatement = `CREATE OR REPLACE TEMPORARY TABLE tmp.ticketCalculateItem ENGINE = MEMORY
SELECT 100 as available;`;
params = null;
}
- return models.Ticket.rawSql(sqlStatement, params, options);
+ return models.Ticket.rawSql(sqlStatement, params, opts);
});
- try {
- const options = {transaction: tx};
+ const isRoleAdvanced = await models.ACL.checkAccessAcl(ctx, 'Ticket', 'isRoleAdvanced', '*');
- const isRoleAdvanced = await models.ACL.checkAccessAcl(ctx, 'Ticket', 'isRoleAdvanced', '*');
+ expect(isRoleAdvanced).toEqual(true);
- expect(isRoleAdvanced).toEqual(true);
+ const originalLine = await models.Sale.findOne({where: {id: saleId}, fields: ['quantity']}, opts);
- const originalLine = await models.Sale.findOne({where: {id: saleId}, fields: ['quantity']}, options);
+ expect(originalLine.quantity).toEqual(30);
- expect(originalLine.quantity).toEqual(30);
+ const newQuantity = originalLine.quantity + 1;
+ await models.Sale.updateQuantity(ctx, saleId, newQuantity, opts);
- const newQuantity = originalLine.quantity + 1;
- await models.Sale.updateQuantity(ctx, saleId, newQuantity, options);
+ const modifiedLine = await models.Sale.findOne({where: {id: saleId}, fields: ['quantity']}, opts);
- const modifiedLine = await models.Sale.findOne({where: {id: saleId}, fields: ['quantity']}, options);
-
- expect(modifiedLine.quantity).toEqual(newQuantity);
-
- await tx.rollback();
- } catch (e) {
- await tx.rollback();
- throw e;
- }
+ expect(modifiedLine.quantity).toEqual(newQuantity);
});
it('should update the quantity of a given sale current line', async() => {
- spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getActiveCtx(9));
+ spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getCtx(developerId, true));
- const tx = await models.Sale.beginTransaction({});
const saleId = 25;
const newQuantity = 4;
- try {
- const options = {transaction: tx};
+ const originalLine = await models.Sale.findOne({where: {id: saleId}, fields: ['quantity']}, opts);
- const originalLine = await models.Sale.findOne({where: {id: saleId}, fields: ['quantity']}, options);
+ expect(originalLine.quantity).toEqual(20);
- expect(originalLine.quantity).toEqual(20);
+ await models.Sale.updateQuantity(ctx, saleId, newQuantity, opts);
- await models.Sale.updateQuantity(ctx, saleId, newQuantity, options);
+ const modifiedLine = await models.Sale.findOne({where: {id: saleId}, fields: ['quantity']}, opts);
- const modifiedLine = await models.Sale.findOne({where: {id: saleId}, fields: ['quantity']}, options);
-
- expect(modifiedLine.quantity).toEqual(newQuantity);
-
- await tx.rollback();
- } catch (e) {
- await tx.rollback();
- throw e;
- }
+ expect(modifiedLine.quantity).toEqual(newQuantity);
});
it('should throw an error if the quantity is negative and it is not a refund ticket', async() => {
- const ctx = {
- req: {
- accessToken: {userId: 1},
- headers: {origin: 'localhost:5000'},
- __: () => {}
- }
- };
- spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getActiveCtx(1));
+ spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getCtx(employeeId, true));
const saleId = 17;
const newQuantity = -10;
- const tx = await models.Sale.beginTransaction({});
-
- let error;
try {
- const options = {transaction: tx};
-
- await models.Sale.updateQuantity(ctx, saleId, newQuantity, options);
-
- await tx.rollback();
+ await models.Sale.updateQuantity(ctx, saleId, newQuantity, opts);
} catch (e) {
- await tx.rollback();
- error = e;
+ expect(e).toEqual(new Error('You can only add negative amounts in refund tickets'));
}
-
- expect(error).toEqual(new Error('You can only add negative amounts in refund tickets'));
});
it('should update a negative quantity when is a ticket refund', async() => {
- spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getActiveCtx(9));
+ spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getCtx(developerId, true));
- const tx = await models.Sale.beginTransaction({});
const saleId = 32;
const newQuantity = -10;
- try {
- const options = {transaction: tx};
+ await models.Sale.updateQuantity(ctx, saleId, newQuantity, opts);
- await models.Sale.updateQuantity(ctx, saleId, newQuantity, options);
+ const modifiedLine = await models.Sale.findOne({where: {id: saleId}, fields: ['quantity']}, opts);
- const modifiedLine = await models.Sale.findOne({where: {id: saleId}, fields: ['quantity']}, options);
-
- expect(modifiedLine.quantity).toEqual(newQuantity);
-
- await tx.rollback();
- } catch (e) {
- await tx.rollback();
- throw e;
- }
+ expect(modifiedLine.quantity).toEqual(newQuantity);
});
it('should throw an error if the quantity is less than the minimum quantity of the item', async() => {
- const ctx = {
- req: {
- accessToken: {userId: 1},
- headers: {origin: 'localhost:5000'},
- __: () => {}
- }
- };
- spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getActiveCtx(1));
+ spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getCtx(employeeId, true));
- const tx = await models.Sale.beginTransaction({});
const itemId = 2;
const saleId = 17;
const minQuantity = 30;
const newQuantity = minQuantity - 1;
- let error;
try {
- const options = {transaction: tx};
-
- const item = await models.Item.findById(itemId, null, options);
- await item.updateAttribute('minQuantity', minQuantity, options);
- spyOn(models.Sale, 'rawSql').and.callFake((sqlStatement, params, options) => {
+ const item = await models.Item.findById(itemId, null, opts);
+ await item.updateAttribute('minQuantity', minQuantity, opts);
+ spyOn(models.Sale, 'rawSql').and.callFake((sqlStatement, params, opts) => {
if (sqlStatement.includes('catalog_calcFromItem')) {
sqlStatement = `CREATE OR REPLACE TEMPORARY TABLE tmp.ticketCalculateItem ENGINE = MEMORY
SELECT 100 as available;`;
params = null;
}
- return models.Ticket.rawSql(sqlStatement, params, options);
+ return models.Ticket.rawSql(sqlStatement, params, opts);
});
- await models.Sale.updateQuantity(ctx, saleId, newQuantity, options);
-
- await tx.rollback();
+ await models.Sale.updateQuantity(ctx, saleId, newQuantity, opts);
} catch (e) {
- await tx.rollback();
- error = e;
+ expect(e).toEqual(new Error('The amount cannot be less than the minimum'));
}
-
- expect(error).toEqual(new Error('The amount cannot be less than the minimum'));
});
it('should change quantity if has minimum quantity and new quantity is equal than item available', async() => {
- const ctx = {
- req: {
- accessToken: {userId: 1},
- headers: {origin: 'localhost:5000'},
- __: () => {}
- }
- };
- spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getActiveCtx(1));
+ spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getCtx(employeeId, true));
- const tx = await models.Sale.beginTransaction({});
const itemId = 2;
const saleId = 17;
const minQuantity = 30;
const newQuantity = minQuantity - 1;
- try {
- const options = {transaction: tx};
+ const item = await models.Item.findById(itemId, null, opts);
+ await item.updateAttribute('minQuantity', minQuantity, opts);
- const item = await models.Item.findById(itemId, null, options);
- await item.updateAttribute('minQuantity', minQuantity, options);
-
- spyOn(models.Sale, 'rawSql').and.callFake((sqlStatement, params, options) => {
- if (sqlStatement.includes('catalog_calcFromItem')) {
- sqlStatement = `CREATE OR REPLACE TEMPORARY TABLE tmp.ticketCalculateItem ENGINE = MEMORY
+ spyOn(models.Sale, 'rawSql').and.callFake((sqlStatement, params, opts) => {
+ if (sqlStatement.includes('catalog_calcFromItem')) {
+ sqlStatement = `CREATE OR REPLACE TEMPORARY TABLE tmp.ticketCalculateItem ENGINE = MEMORY
SELECT ${newQuantity} as available;`;
- params = null;
- }
- return models.Ticket.rawSql(sqlStatement, params, options);
- });
+ params = null;
+ }
+ return models.Ticket.rawSql(sqlStatement, params, opts);
+ });
- await models.Sale.updateQuantity(ctx, saleId, newQuantity, options);
-
- await tx.rollback();
- } catch (e) {
- await tx.rollback();
- throw e;
- }
+ await models.Sale.updateQuantity(ctx, saleId, newQuantity, opts);
});
describe('newPrice', () => {
it('should increase quantity if you have enough available and the new price is the same as the previous one', async() => {
- const ctx = {
- req: {
- accessToken: {userId: 1},
- headers: {origin: 'localhost:5000'},
- __: () => {}
- }
- };
- spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getActiveCtx(1));
+ spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getCtx(employeeId, true));
- const tx = await models.Sale.beginTransaction({});
const itemId = 2;
const saleId = 17;
const minQuantity = 30;
const newQuantity = 31;
- try {
- const options = {transaction: tx};
-
- const item = await models.Item.findById(itemId, null, options);
- await item.updateAttribute('minQuantity', minQuantity, options);
- spyOn(models.Sale, 'rawSql').and.callFake((sqlStatement, params, options) => {
- if (sqlStatement.includes('catalog_calcFromItem')) {
- sqlStatement = `
+ const item = await models.Item.findById(itemId, null, opts);
+ await item.updateAttribute('minQuantity', minQuantity, opts);
+ spyOn(models.Sale, 'rawSql').and.callFake((sqlStatement, params, opts) => {
+ if (sqlStatement.includes('catalog_calcFromItem')) {
+ sqlStatement = `
CREATE OR REPLACE TEMPORARY TABLE tmp.ticketCalculateItem ENGINE = MEMORY SELECT ${newQuantity} as available;
CREATE OR REPLACE TEMPORARY TABLE tmp.ticketComponentPrice ENGINE = MEMORY SELECT 1 as grouping, 7.07 as price;`;
- params = null;
- }
- return models.Ticket.rawSql(sqlStatement, params, options);
- });
+ params = null;
+ }
+ return models.Ticket.rawSql(sqlStatement, params, opts);
+ });
- await models.Sale.updateQuantity(ctx, saleId, newQuantity, options);
-
- await tx.rollback();
- } catch (e) {
- await tx.rollback();
- throw e;
- }
+ await models.Sale.updateQuantity(ctx, saleId, newQuantity, opts);
});
it('should increase quantity when the new price is lower than the previous one', async() => {
- const ctx = {
- req: {
- accessToken: {userId: 1},
- headers: {origin: 'localhost:5000'},
- __: () => {}
- }
- };
- spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getActiveCtx(1));
+ spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getCtx(employeeId, true));
- const tx = await models.Sale.beginTransaction({});
const itemId = 2;
const saleId = 17;
const minQuantity = 30;
const newQuantity = 31;
- try {
- const options = {transaction: tx};
-
- const item = await models.Item.findById(itemId, null, options);
- await item.updateAttribute('minQuantity', minQuantity, options);
- spyOn(models.Sale, 'rawSql').and.callFake((sqlStatement, params, options) => {
- if (sqlStatement.includes('catalog_calcFromItem')) {
- sqlStatement = `
+ const item = await models.Item.findById(itemId, null, opts);
+ await item.updateAttribute('minQuantity', minQuantity, opts);
+ spyOn(models.Sale, 'rawSql').and.callFake((sqlStatement, params, opts) => {
+ if (sqlStatement.includes('catalog_calcFromItem')) {
+ sqlStatement = `
CREATE OR REPLACE TEMPORARY TABLE tmp.ticketCalculateItem ENGINE = MEMORY SELECT ${newQuantity} as available;
CREATE OR REPLACE TEMPORARY TABLE tmp.ticketComponentPrice ENGINE = MEMORY SELECT 1 as grouping, 1 as price;`;
- params = null;
- }
- return models.Ticket.rawSql(sqlStatement, params, options);
- });
+ params = null;
+ }
+ return models.Ticket.rawSql(sqlStatement, params, opts);
+ });
- await models.Sale.updateQuantity(ctx, saleId, newQuantity, options);
-
- await tx.rollback();
- } catch (e) {
- await tx.rollback();
- throw e;
- }
+ await models.Sale.updateQuantity(ctx, saleId, newQuantity, opts);
});
it('should throw error when increase quantity and the new price is higher than the previous one', async() => {
- const ctx = {
- req: {
- accessToken: {userId: 1},
- headers: {origin: 'localhost:5000'},
- __: () => {}
- }
- };
- spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getActiveCtx(1));
+ spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getCtx(employeeId, true));
- const tx = await models.Sale.beginTransaction({});
const itemId = 2;
const saleId = 17;
const minQuantity = 30;
const newQuantity = 31;
- let error;
try {
- const options = {transaction: tx};
-
- const item = await models.Item.findById(itemId, null, options);
- await item.updateAttribute('minQuantity', minQuantity, options);
- spyOn(models.Sale, 'rawSql').and.callFake((sqlStatement, params, options) => {
+ const item = await models.Item.findById(itemId, null, opts);
+ await item.updateAttribute('minQuantity', minQuantity, opts);
+ spyOn(models.Sale, 'rawSql').and.callFake((sqlStatement, params, opts) => {
if (sqlStatement.includes('catalog_calcFromItem')) {
sqlStatement = `
CREATE OR REPLACE TEMPORARY TABLE tmp.ticketCalculateItem ENGINE = MEMORY SELECT ${newQuantity} as available;
CREATE OR REPLACE TEMPORARY TABLE tmp.ticketComponentPrice ENGINE = MEMORY SELECT 1 as grouping, 100000 as price;`;
params = null;
}
- return models.Ticket.rawSql(sqlStatement, params, options);
+ return models.Ticket.rawSql(sqlStatement, params, opts);
});
- await models.Sale.updateQuantity(ctx, saleId, newQuantity, options);
-
- await tx.rollback();
+ await models.Sale.updateQuantity(ctx, saleId, newQuantity, opts);
} catch (e) {
- await tx.rollback();
- error = e;
+ expect(e).toEqual(new Error('The price of the item changed'));
}
-
- expect(error).toEqual(new Error('The price of the item changed'));
});
});
});
+
+ describe('add a sale from a collection or previa ticket', () => {
+ it('if is allocated to them and alert level higher than 0 as Production role', async() => {
+ const ctx = getCtx(productionId);
+ spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getCtx(productionId, true));
+
+ const beforeSalesCollection = await models.Sale.count({ticketFk: ticketCollectionProd}, opts);
+ await models.Ticket.addSale(ctx, ticketCollectionProd, barcode, 20, opts);
+ const afterSalesCollection = await models.Sale.count({ticketFk: ticketCollectionProd}, opts);
+
+ expect(afterSalesCollection).toEqual(beforeSalesCollection + 1);
+
+ const beforeSalesPrevia = await models.Sale.count({ticketFk: previaTicketProd}, opts);
+ await models.Ticket.addSale(ctx, previaTicketProd, barcode, 20, opts);
+ const afterSalesPrevia = await models.Sale.count({ticketFk: previaTicketProd}, opts);
+
+ expect(afterSalesPrevia).toEqual(beforeSalesPrevia + 1);
+ });
+
+ it('should throw an error if is not allocated to them and alert level higher than 0 as Production role', async() => {
+ const ctx = getCtx(productionId);
+ spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getCtx(productionId, true));
+
+ try {
+ await models.Ticket.addSale(ctx, ticketCollectionSalesPerson, barcode, 20, opts);
+ } catch ({message}) {
+ expect(message).toEqual(notEditableError);
+ }
+
+ try {
+ await models.Ticket.addSale(ctx, previaTicketSalesPerson, barcode, 20, opts);
+ } catch ({message}) {
+ expect(message).toEqual(notEditableError);
+ }
+ });
+
+ it('if is allocated to them and alert level higher than 0 as salesPerson role', async() => {
+ const ctx = getCtx(salesPersonId);
+ spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getCtx(salesPersonId, true));
+
+ const beforeSalesCollection = await models.Sale.count({ticketFk: ticketCollectionSalesPerson}, opts);
+ await models.Ticket.addSale(ctx, ticketCollectionSalesPerson, barcode, 20, opts);
+ const afterSalesCollection = await models.Sale.count({ticketFk: ticketCollectionSalesPerson}, opts);
+
+ expect(afterSalesCollection).toEqual(beforeSalesCollection + 1);
+
+ const beforeSalesPrevia = await models.Sale.count({ticketFk: previaTicketSalesPerson}, opts);
+ await models.Ticket.addSale(ctx, previaTicketSalesPerson, barcode, 20, opts);
+ const afterSalesPrevia = await models.Sale.count({ticketFk: previaTicketSalesPerson}, opts);
+
+ expect(afterSalesPrevia).toEqual(beforeSalesPrevia + 1);
+ });
+
+ it('should throw an error if is not allocated to them and alert level higher than 0 as salesPerson role', async() => {
+ const ctx = getCtx(salesPersonId);
+
+ spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getCtx(salesPersonId, true));
+
+ try {
+ await models.Ticket.addSale(ctx, ticketCollectionProd, barcode, 20, opts);
+ } catch ({message}) {
+ expect(message).toEqual(notEditableError);
+ }
+ });
+
+ it('if is a reviewer', async() => {
+ const ctx = getCtx(reviewerId);
+ spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getCtx(reviewerId, true));
+
+ const beforeSalesCollection = await models.Sale.count({ticketFk: ticketCollectionSalesPerson}, opts);
+ await models.Ticket.addSale(ctx, ticketCollectionSalesPerson, barcode, 20, opts);
+ const afterSalesCollection = await models.Sale.count({ticketFk: ticketCollectionSalesPerson}, opts);
+
+ expect(afterSalesCollection).toEqual(beforeSalesCollection + 1);
+
+ const beforeSalesPrevia = await models.Sale.count({ticketFk: previaTicketSalesPerson}, opts);
+ await models.Ticket.addSale(ctx, previaTicketSalesPerson, barcode, 20, opts);
+ const afterSalesPrevia = await models.Sale.count({ticketFk: previaTicketSalesPerson}, opts);
+
+ expect(afterSalesPrevia).toEqual(beforeSalesPrevia + 1);
+ });
+ });
});
diff --git a/modules/ticket/back/models/ticket-methods.js b/modules/ticket/back/models/ticket-methods.js
index 0ae2ce3b4..5582dde5c 100644
--- a/modules/ticket/back/models/ticket-methods.js
+++ b/modules/ticket/back/models/ticket-methods.js
@@ -46,6 +46,5 @@ module.exports = function(Self) {
require('../methods/ticket/invoiceTicketsAndPdf')(Self);
require('../methods/ticket/docuwareDownload')(Self);
require('../methods/ticket/myLastModified')(Self);
- require('../methods/ticket/addSaleByCode')(Self);
require('../methods/ticket/clone')(Self);
};
diff --git a/modules/ticket/front/sale/index.js b/modules/ticket/front/sale/index.js
index 1cd5560a4..7ff8d89e3 100644
--- a/modules/ticket/front/sale/index.js
+++ b/modules/ticket/front/sale/index.js
@@ -476,7 +476,7 @@ class Controller extends Section {
*/
addSale(sale) {
const data = {
- itemId: sale.itemFk,
+ barcode: sale.itemFk,
quantity: sale.quantity
};
const query = `tickets/${this.ticket.id}/addSale`;
diff --git a/modules/ticket/front/sale/index.spec.js b/modules/ticket/front/sale/index.spec.js
index fb1c925d4..8200d6b89 100644
--- a/modules/ticket/front/sale/index.spec.js
+++ b/modules/ticket/front/sale/index.spec.js
@@ -659,7 +659,7 @@ describe('Ticket', () => {
jest.spyOn(controller, 'resetChanges').mockReturnThis();
const newSale = {itemFk: 4, quantity: 10};
- const expectedParams = {itemId: 4, quantity: 10};
+ const expectedParams = {barcode: 4, quantity: 10};
const expectedResult = {
id: 30,
quantity: 10,
diff --git a/modules/zone/back/methods/zone/specs/deleteZone.spec.js b/modules/zone/back/methods/zone/specs/deleteZone.spec.js
index 968685fec..08dafd181 100644
--- a/modules/zone/back/methods/zone/specs/deleteZone.spec.js
+++ b/modules/zone/back/methods/zone/specs/deleteZone.spec.js
@@ -5,6 +5,7 @@ describe('zone deletezone()', () => {
const userId = 9;
const activeCtx = {
accessToken: {userId: userId},
+ __: value => value
};
const ctx = {req: activeCtx};
const zoneId = 9;
@@ -15,19 +16,15 @@ describe('zone deletezone()', () => {
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
active: activeCtx
});
- try {
- const originalTickets = await models.Ticket.find({
- where: {
- zoneFk: zoneId
- }
- });
- ticketIDs = originalTickets.map(ticket => ticket.id);
- originalTicketStates = await models.TicketState.find({where: {
- ticketFk: {inq: ticketIDs},
- code: 'FIXING'}});
- } catch (error) {
- console.error(error);
- }
+ const originalTickets = await models.Ticket.find({
+ where: {
+ zoneFk: zoneId
+ }
+ });
+ ticketIDs = originalTickets.map(ticket => ticket.id);
+ originalTicketStates = await models.TicketState.find({where: {
+ ticketFk: {inq: ticketIDs},
+ code: 'FIXING'}});
});
it('should delete a zone and update their tickets', async() => {
diff --git a/package.json b/package.json
index 468d13156..be361ce7b 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "salix-back",
- "version": "24.22.10",
+ "version": "24.24.3",
"author": "Verdnatura Levante SL",
"description": "Salix backend",
"license": "GPL-3.0",