From 51417adffeecdbfdaf2c205075fb6e5a1811dd1c Mon Sep 17 00:00:00 2001 From: carlosjr Date: Mon, 20 Sep 2021 09:51:09 +0200 Subject: [PATCH 01/47] refactor(wtf): removed unused package --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index fb956bfff..ff70e2c4e 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,6 @@ "strong-error-handler": "^2.3.2", "uuid": "^3.3.3", "vn-loopback": "file:./loopback", - "vn-mysql": "^1.0.3", "xml2js": "^0.4.23" }, "devDependencies": { From ca00e3611c63e6f0c359e0e9b9458de9fb117f73 Mon Sep 17 00:00:00 2001 From: carlosjr Date: Tue, 21 Sep 2021 18:43:45 +0200 Subject: [PATCH 02/47] package-lock after removing vn-mysql --- package-lock.json | 1610 ++------------------------------------------- 1 file changed, 44 insertions(+), 1566 deletions(-) diff --git a/package-lock.json b/package-lock.json index d2ff3b6d4..e1a4831b0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -39,7 +39,6 @@ "strong-error-handler": "^2.3.2", "uuid": "^3.3.3", "vn-loopback": "file:./loopback", - "vn-mysql": "^1.0.3", "xml2js": "^0.4.23" }, "devDependencies": { @@ -100,311 +99,10 @@ } }, "loopback": { + "name": "vn-loopback", "version": "1.0.0", "integrity": "sha1-S06UTBRgMQ2KQ8X6J7DX5bbSnEI=", - "deprecated": "LoopBack 1 is no longer maintained, please upgrade to a newer version. Learn more at https://loopback.io", - "dependencies": { - "bcryptjs": "~0.7.10", - "debug": "~0.7.2", - "ejs": "~0.8.4", - "express": "~3.4.0", - "inflection": "~1.2.5", - "loopback-datasource-juggler": "~1.0.0", - "nodemailer": "~0.4.4", - "passport": "~0.1.17", - "passport-local": "~0.1.6", - "strong-remoting": "~1.0.0" - }, - "devDependencies": { - "blanket": "~1.1.5", - "mocha": "~1.12.1", - "strong-task-emitter": "0.0.x", - "supertest": "~0.7.1" - } - }, - "loopback/node_modules/async": { - "version": "0.2.10", - "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", - "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E=" - }, - "loopback/node_modules/bcryptjs": { - "version": "0.7.12", - "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-0.7.12.tgz", - "integrity": "sha1-zNhgV8CvCZhI/iFLffDStnJszOs=" - }, - "loopback/node_modules/buffer-crc32": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.1.tgz", - "integrity": "sha1-vj5TgvwCttYySVasGvmKqYsIU0w=", - "engines": { - "node": "*" - } - }, - "loopback/node_modules/commander": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/commander/-/commander-1.3.2.tgz", - "integrity": "sha1-io8w7GcKb91kr1LxkUuQfXnq1bU=", - "dependencies": { - "keypress": "0.1.x" - }, - "engines": { - "node": ">= 0.6.x" - } - }, - "loopback/node_modules/cookie": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.1.0.tgz", - "integrity": "sha1-kOtGndzpBchm3mh+/EMTHYgB+dA=", - "engines": { - "node": "*" - } - }, - "loopback/node_modules/cookie-signature": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.1.tgz", - "integrity": "sha1-ROByFIrwHm6OJK+/EmkNaK5pjss=" - }, - "loopback/node_modules/debug": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz", - "integrity": "sha1-BuHqgILCyxTjmAbiLi9vdX+Srzk=", - "engines": { - "node": "*" - } - }, - "loopback/node_modules/diff": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-1.0.2.tgz", - "integrity": "sha1-Suc/Gu6Nb89ITxoc53zmUdm38Mk=", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "loopback/node_modules/ejs": { - "version": "0.8.8", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-0.8.8.tgz", - "integrity": "sha1-/9xW3MNdApJt1QrRNDm7xUBh1Zg=", - "deprecated": "Critical security bugs fixed in 2.5.5" - }, - "loopback/node_modules/eventemitter2": { - "version": "0.4.14", - "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz", - "integrity": "sha1-j2G3XN4BKy6esoTUVFWDtWQ7Yas=" - }, - "loopback/node_modules/express": { - "version": "3.4.8", - "resolved": "https://registry.npmjs.org/express/-/express-3.4.8.tgz", - "integrity": "sha1-qnqJht4HBTM39Lxe2aZFPZzI4uE=", - "dependencies": { - "buffer-crc32": "0.2.1", - "commander": "1.3.2", - "connect": "2.12.0", - "cookie": "0.1.0", - "cookie-signature": "1.0.1", - "debug": ">= 0.7.3 < 1", - "fresh": "0.2.0", - "merge-descriptors": "0.0.1", - "methods": "0.1.0", - "mkdirp": "0.3.5", - "range-parser": "0.0.4", - "send": "0.1.4" - }, - "bin": { - "express": "bin/express" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "loopback/node_modules/fresh": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.2.0.tgz", - "integrity": "sha1-v9lALPPfEsSkwxDHn5mj3eE9NKc=" - }, - "loopback/node_modules/glob": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/glob/-/glob-3.2.1.tgz", - "integrity": "sha1-V69w7HO6IyO/4/KaBndl22TF11g=", - "dev": true, - "dependencies": { - "graceful-fs": "~1.2.0", - "inherits": "1", - "minimatch": "~0.2.11" - }, - "engines": { - "node": "*" - } - }, - "loopback/node_modules/graceful-fs": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-1.2.3.tgz", - "integrity": "sha1-FaSAaldUfLLS2/J/QuiajDRRs2Q=", - "deprecated": "please upgrade to graceful-fs 4 for compatibility with current and future versions of Node.js", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "loopback/node_modules/growl": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.7.0.tgz", - "integrity": "sha1-3i1mE20ALhErpw8/EMMc98NQsto=", - "dev": true - }, - "loopback/node_modules/inflection": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.2.7.tgz", - "integrity": "sha1-WdtFBTEKdGZ3GC7UbhVeADv7NZE=", - "engines": [ - "node >= 0.4.0" - ] - }, - "loopback/node_modules/inherits": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-1.0.2.tgz", - "integrity": "sha1-ykMJ2t7mtUzAuNJH6NfHoJdb3Js=", - "dev": true - }, - "loopback/node_modules/loopback-datasource-juggler": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/loopback-datasource-juggler/-/loopback-datasource-juggler-1.0.0.tgz", - "integrity": "sha1-3A+OUMBK8ENRkyr/cHkoLsrlM+U=", - "deprecated": "LoopBack 1 is no longer maintained, please upgrade to a newer version. Learn more at https://loopback.io", - "engines": [ - "node >= 0.6" - ], - "dependencies": { - "async": "~0.2.9", - "inflection": "~1.2.6", - "traverse": "~0.6.5" - } - }, - "loopback/node_modules/lru-cache": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", - "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=", - "dev": true - }, - "loopback/node_modules/merge-descriptors": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-0.0.1.tgz", - "integrity": "sha1-L/CYDJJM+B0LXR+2ARd8uLtWwNA=" - }, - "loopback/node_modules/methods": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/methods/-/methods-0.1.0.tgz", - "integrity": "sha1-M11Cnu/SG3us8unJIqjSvRSjDk8=" - }, - "loopback/node_modules/mime": { - "version": "1.2.11", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz", - "integrity": "sha1-WCA+7Ybjpe8XrtK32evUfwpg3RA=" - }, - "loopback/node_modules/minimatch": { - "version": "0.2.14", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz", - "integrity": "sha1-x054BXT2PG+aCQ6Q775u9TpqdWo=", - "deprecated": "Please update to minimatch 3.0.2 or higher to avoid a RegExp DoS issue", - "dev": true, - "dependencies": { - "lru-cache": "2", - "sigmund": "~1.0.0" - }, - "engines": { - "node": "*" - } - }, - "loopback/node_modules/mkdirp": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz", - "integrity": "sha1-3j5fiWHIjHh+4TaN+EmsRBPsqNc=", - "deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)" - }, - "loopback/node_modules/mocha": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-1.12.1.tgz", - "integrity": "sha1-UhLj9ZFO74wIiK40Tmp90uWsKUo=", - "deprecated": "Mocha v1.x is no longer supported.", - "dev": true, - "dependencies": { - "commander": "0.6.1", - "debug": "*", - "diff": "1.0.2", - "glob": "3.2.1", - "growl": "1.7.x", - "jade": "0.26.3", - "mkdirp": "0.3.5" - }, - "bin": { - "_mocha": "bin/_mocha", - "mocha": "bin/mocha" - }, - "engines": { - "node": ">= 0.4.x" - } - }, - "loopback/node_modules/mocha/node_modules/commander": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-0.6.1.tgz", - "integrity": "sha1-+mihT2qUXVTbvlDYzbMyDp47GgY=", - "dev": true, - "engines": { - "node": ">= 0.4.x" - } - }, - "loopback/node_modules/nodemailer": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-0.4.4.tgz", - "integrity": "sha1-z8sMFE903PSrM3hQINggdv+5BXI=", - "deprecated": "All versions below 4.0.1 of Nodemailer are deprecated. See https://nodemailer.com/status/", - "dependencies": { - "mailcomposer": "~0.1", - "simplesmtp": "~0.2 || ~0.3" - }, - "engines": { - "node": ">=0.6.0" - } - }, - "loopback/node_modules/qs": { - "version": "0.6.6", - "resolved": "https://registry.npmjs.org/qs/-/qs-0.6.6.tgz", - "integrity": "sha1-bgFQmP9RlouKPIGQAdXyyJvEsQc=", - "engines": { - "node": "*" - } - }, - "loopback/node_modules/range-parser": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-0.0.4.tgz", - "integrity": "sha1-wEJ//vUcEKy6B4KkbJYC50T/Ygs=", - "engines": { - "node": "*" - } - }, - "loopback/node_modules/send": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/send/-/send-0.1.4.tgz", - "integrity": "sha1-vnDY0b4B3mGCGvE3gLUDRaT3Gr0=", - "dependencies": { - "debug": "*", - "fresh": "0.2.0", - "mime": "~1.2.9", - "range-parser": "0.0.4" - } - }, - "loopback/node_modules/strong-remoting": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strong-remoting/-/strong-remoting-1.0.0.tgz", - "integrity": "sha1-XIQPL7F97LVVXKoZ98uUVJUzy9s=", - "deprecated": "LoopBack 1 is no longer maintained, please upgrade to a newer version. Learn more at https://loopback.io", - "dependencies": { - "cors": "~1.0.1", - "debug": "~0.7.2", - "eventemitter2": "~0.4.11", - "express": "~3.4.0", - "qs": "~0.6.5" - } + "license": "GPL-3.0" }, "node_modules/@babel/code-frame": { "version": "7.12.13", @@ -2892,11 +2590,6 @@ "node": ">=0.4.0" } }, - "node_modules/addressparser": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/addressparser/-/addressparser-0.3.2.tgz", - "integrity": "sha1-WYc/Nej89sc2HBAjkmHXbhU0i7I=" - }, "node_modules/agent-base": { "version": "4.3.0", "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", @@ -4042,41 +3735,6 @@ "safe-buffer": "^5.1.1" } }, - "node_modules/blanket": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/blanket/-/blanket-1.1.10.tgz", - "integrity": "sha1-m+r8WbZmvUetlOxkCCvxl++Ms0I=", - "dev": true, - "dependencies": { - "acorn": "^1.0.3", - "falafel": "~1.2.0", - "foreach": "^2.0.5", - "isarray": "0.0.1", - "object-keys": "^1.0.6", - "xtend": "~4.0.0" - }, - "engines": { - "node": ">=0.10.7" - } - }, - "node_modules/blanket/node_modules/acorn": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-1.2.2.tgz", - "integrity": "sha1-yM4n3grMdtiW0rH6099YjZ6C8BQ=", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/blanket/node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - }, "node_modules/block-stream": { "version": "0.0.9", "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=", @@ -5171,32 +4829,6 @@ "signal-exit": "^3.0.2" } }, - "node_modules/connect": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/connect/-/connect-2.12.0.tgz", - "integrity": "sha1-Mdj6DcrN8ZCNgivSkjvootKn7Zo=", - "deprecated": "connect 2.x series is deprecated", - "dependencies": { - "batch": "0.5.0", - "buffer-crc32": "0.2.1", - "bytes": "0.2.1", - "cookie": "0.1.0", - "cookie-signature": "1.0.1", - "debug": ">= 0.7.3 < 1", - "fresh": "0.2.0", - "methods": "0.1.0", - "multiparty": "2.2.0", - "negotiator": "0.3.0", - "pause": "0.0.1", - "qs": "0.6.6", - "raw-body": "1.1.2", - "send": "0.1.4", - "uid2": "0.0.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/connect-history-api-fallback": { "version": "1.6.0", "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==", @@ -5205,106 +4837,6 @@ "node": ">=0.8" } }, - "node_modules/connect/node_modules/batch": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/batch/-/batch-0.5.0.tgz", - "integrity": "sha1-/S4Fp6XWlrTbkxQBPihdj/NVfsM=" - }, - "node_modules/connect/node_modules/buffer-crc32": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.1.tgz", - "integrity": "sha1-vj5TgvwCttYySVasGvmKqYsIU0w=", - "engines": { - "node": "*" - } - }, - "node_modules/connect/node_modules/bytes": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-0.2.1.tgz", - "integrity": "sha1-VVsIq8sGP4l1kFMCUj5M1P/f3zE=" - }, - "node_modules/connect/node_modules/cookie": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.1.0.tgz", - "integrity": "sha1-kOtGndzpBchm3mh+/EMTHYgB+dA=", - "engines": { - "node": "*" - } - }, - "node_modules/connect/node_modules/cookie-signature": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.1.tgz", - "integrity": "sha1-ROByFIrwHm6OJK+/EmkNaK5pjss=" - }, - "node_modules/connect/node_modules/debug": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-0.8.1.tgz", - "integrity": "sha1-IP9NJvXkIstoobrLu2EDmtjBwTA=", - "engines": { - "node": "*" - } - }, - "node_modules/connect/node_modules/fresh": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.2.0.tgz", - "integrity": "sha1-v9lALPPfEsSkwxDHn5mj3eE9NKc=" - }, - "node_modules/connect/node_modules/methods": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/methods/-/methods-0.1.0.tgz", - "integrity": "sha1-M11Cnu/SG3us8unJIqjSvRSjDk8=" - }, - "node_modules/connect/node_modules/mime": { - "version": "1.2.11", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz", - "integrity": "sha1-WCA+7Ybjpe8XrtK32evUfwpg3RA=" - }, - "node_modules/connect/node_modules/negotiator": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.3.0.tgz", - "integrity": "sha1-cG1pLv7d9XTVfqn7GriaT6fuj2A=", - "engines": { - "node": "*" - } - }, - "node_modules/connect/node_modules/qs": { - "version": "0.6.6", - "resolved": "https://registry.npmjs.org/qs/-/qs-0.6.6.tgz", - "integrity": "sha1-bgFQmP9RlouKPIGQAdXyyJvEsQc=", - "engines": { - "node": "*" - } - }, - "node_modules/connect/node_modules/range-parser": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-0.0.4.tgz", - "integrity": "sha1-wEJ//vUcEKy6B4KkbJYC50T/Ygs=", - "engines": { - "node": "*" - } - }, - "node_modules/connect/node_modules/raw-body": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-1.1.2.tgz", - "integrity": "sha1-x0swBN6l3v0WlhcRBqx0DsMdYr4=", - "dependencies": { - "bytes": "~0.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/connect/node_modules/send": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/send/-/send-0.1.4.tgz", - "integrity": "sha1-vnDY0b4B3mGCGvE3gLUDRaT3Gr0=", - "dependencies": { - "debug": "*", - "fresh": "0.2.0", - "mime": "~1.2.9", - "range-parser": "0.0.4" - } - }, "node_modules/console-browserify": { "version": "1.2.0", "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==", @@ -5373,15 +4905,6 @@ "version": "1.0.6", "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" }, - "node_modules/cookiejar": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-1.3.0.tgz", - "integrity": "sha1-3QCzVnkCHpnL1OhVua0EGRNHR2U=", - "dev": true, - "engines": { - "node": "*" - } - }, "node_modules/copy-concurrently": { "version": "1.0.5", "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", @@ -5457,14 +4980,6 @@ "version": "1.0.2", "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, - "node_modules/cors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cors/-/cors-1.0.1.tgz", - "integrity": "sha1-2LGLrJRgrv1b+7BvXYaE9yBvbZ0=", - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/create-ecdh": { "version": "4.0.4", "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", @@ -6446,12 +5961,6 @@ "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", "dev": true }, - "node_modules/emitter-component": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/emitter-component/-/emitter-component-1.0.0.tgz", - "integrity": "sha1-8E3Rj8PcPpp0y8DzELCIZm5MAW8=", - "dev": true - }, "node_modules/emitter-listener": { "version": "1.1.2", "integrity": "sha512-Bt1sBAGFHY9DKY+4/2cV6izcKJUf5T7/gkdmkxzX/qv9CcGH8xSwVRW5mtX03SWJtRTWSOpzCuWN9rBFYZepZQ==", @@ -6490,29 +5999,10 @@ "node": ">= 0.8" } }, - "node_modules/encoding": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", - "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", - "dependencies": { - "iconv-lite": "^0.6.2" - } - }, "node_modules/encoding-japanese": { "version": "1.0.30", "integrity": "sha512-bd/DFLAoJetvv7ar/KIpE3CNO8wEuyrt9Xuw6nSMiZ+Vrz/Q21BPsMHvARL2Wz6IKHKXgb+DWZqtRg1vql9cBg==" }, - "node_modules/encoding/node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/end-of-stream": { "version": "1.4.4", "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", @@ -7554,39 +7044,6 @@ "node": "> 0.1.90" } }, - "node_modules/falafel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/falafel/-/falafel-1.2.0.tgz", - "integrity": "sha1-wY0k71CRF0pJfzGM0ksCaiXN2rQ=", - "dev": true, - "dependencies": { - "acorn": "^1.0.3", - "foreach": "^2.0.5", - "isarray": "0.0.1", - "object-keys": "^1.0.6" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/falafel/node_modules/acorn": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-1.2.2.tgz", - "integrity": "sha1-yM4n3grMdtiW0rH6099YjZ6C8BQ=", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/falafel/node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - }, "node_modules/fancy-log": { "version": "1.3.3", "integrity": "sha512-k9oEhlyc0FrVh25qYuSELjr8oxsCoc4/LEZfg2iJJrfEk/tZL9bCoJE47gqAvI2m/AUjluCS4+3I0eTx8n3AEw==", @@ -8032,12 +7489,6 @@ "node": ">=0.10.0" } }, - "node_modules/foreach": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", - "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", - "dev": true - }, "node_modules/forever-agent": { "version": "0.6.1", "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", @@ -13517,11 +12968,6 @@ "safe-buffer": "^5.0.1" } }, - "node_modules/keypress": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/keypress/-/keypress-0.1.0.tgz", - "integrity": "sha1-SjGI1CkbZrT2XtuZ+AaqmuKTWSo=" - }, "node_modules/keyv": { "version": "3.1.0", "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", @@ -14408,21 +13854,6 @@ "yallist": "^3.0.2" } }, - "node_modules/mailcomposer": { - "version": "0.1.34", - "resolved": "https://registry.npmjs.org/mailcomposer/-/mailcomposer-0.1.34.tgz", - "integrity": "sha1-a9X6QrVAR4kNKuMhiImuxvJOxQA=", - "deprecated": "This project is unmaintained", - "dependencies": { - "mime": "1.2.9", - "mimelib": "~0.2" - } - }, - "node_modules/mailcomposer/node_modules/mime": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.2.9.tgz", - "integrity": "sha1-AJzUCGe9Nd5SGzuWbwTi+NTRPQk=" - }, "node_modules/mailparser": { "version": "2.8.1", "integrity": "sha512-H/CYAO9dsw6SFNbEGGpZsejVSWDcFlyHjb1OkHUWg0wggUekva1tNc28trB155nSqM8rhtbwTKt//orX0AmJxQ==", @@ -14992,16 +14423,6 @@ "node": ">= 0.6" } }, - "node_modules/mimelib": { - "version": "0.2.19", - "resolved": "https://registry.npmjs.org/mimelib/-/mimelib-0.2.19.tgz", - "integrity": "sha1-N+yQpqx9AJVIUdCywxYY8KSdoO4=", - "deprecated": "This project is unmaintained", - "dependencies": { - "addressparser": "~0.3.2", - "encoding": "~0.1.7" - } - }, "node_modules/mimic-fn": { "version": "2.1.0", "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", @@ -15302,39 +14723,6 @@ "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=", "dev": true }, - "node_modules/multiparty": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/multiparty/-/multiparty-2.2.0.tgz", - "integrity": "sha1-pWfCrwAK0i3I8qZT2Rl4rh9TFvQ=", - "dependencies": { - "readable-stream": "~1.1.9", - "stream-counter": "~0.2.0" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/multiparty/node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" - }, - "node_modules/multiparty/node_modules/readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "node_modules/multiparty/node_modules/string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" - }, "node_modules/multipipe": { "version": "0.1.2", "integrity": "sha1-Ko8t33Du1WTf8tV/HhoTfZ8FB4s=", @@ -16805,30 +16193,6 @@ "node": ">=0.10.0" } }, - "node_modules/passport": { - "version": "0.1.18", - "resolved": "https://registry.npmjs.org/passport/-/passport-0.1.18.tgz", - "integrity": "sha1-yCZEedy2QUytu2Z1LRKzfgtlJaE=", - "dependencies": { - "pause": "0.0.1", - "pkginfo": "0.2.x" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/passport-local": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/passport-local/-/passport-local-0.1.6.tgz", - "integrity": "sha1-+wz4KASNuTG2fRmYXHqgbdN3qds=", - "dependencies": { - "passport": "~0.1.1", - "pkginfo": "0.2.x" - }, - "engines": { - "node": ">= 0.4.0" - } - }, "node_modules/path-browserify": { "version": "0.0.1", "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==", @@ -16906,11 +16270,6 @@ "node": ">=0.10.0" } }, - "node_modules/pause": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", - "integrity": "sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10=" - }, "node_modules/pbkdf2": { "version": "3.1.1", "integrity": "sha512-4Ejy1OPxi9f2tt1rRV7Go7zmfDQ+ZectEQz3VGUQhgq62HtIRPDyG/JtnwIxs6x3uNMwo2V7q1fMvKjb+Tnpqg==", @@ -17069,14 +16428,6 @@ "readable-stream": "2 || 3" } }, - "node_modules/pkginfo": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/pkginfo/-/pkginfo-0.2.3.tgz", - "integrity": "sha1-cjnEKl72wwuPMoQ52bn/cQQkkPg=", - "engines": { - "node": ">= 0.4.0" - } - }, "node_modules/plugin-error": { "version": "1.0.1", "integrity": "sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==", @@ -17641,14 +16992,6 @@ "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", "dev": true }, - "node_modules/rai": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/rai/-/rai-0.1.12.tgz", - "integrity": "sha1-jM/QFND5YIYw3XPBm45LBXdUpqY=", - "engines": [ - "node >=0.4.0" - ] - }, "node_modules/randombytes": { "version": "2.1.0", "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", @@ -19561,18 +18904,6 @@ "version": "0.3.2", "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" }, - "node_modules/simplesmtp": { - "version": "0.3.35", - "resolved": "https://registry.npmjs.org/simplesmtp/-/simplesmtp-0.3.35.tgz", - "integrity": "sha1-AXseuLJjF6w20qKoqTJjGIBzagM=", - "dependencies": { - "rai": "~0.1.11", - "xoauth2": "~0.1.8" - }, - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/sisteransi": { "version": "1.0.5", "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", @@ -20195,38 +19526,6 @@ "duplexer": "~0.0.3" } }, - "node_modules/stream-counter": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/stream-counter/-/stream-counter-0.2.0.tgz", - "integrity": "sha1-3tJmVWMZyLDiIoErnPOyb6fZR94=", - "dependencies": { - "readable-stream": "~1.1.8" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/stream-counter/node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" - }, - "node_modules/stream-counter/node_modules/readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "node_modules/stream-counter/node_modules/string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" - }, "node_modules/stream-each": { "version": "1.2.3", "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==", @@ -20785,24 +20084,6 @@ "version": "2.0.3", "integrity": "sha512-HgS+X6zAztGa9zIK3Y3LXuJes33Lz9x+YyTxgrkIdabu2vqcGOWwdfCpf1hWLRrd553wd4QCDf6BBO6FfdsRiQ==" }, - "node_modules/strong-task-emitter": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/strong-task-emitter/-/strong-task-emitter-0.0.8.tgz", - "integrity": "sha512-SWbn6ucuV4jVJMB61lbzqlJiIFG/jwGiUJ09JjxhtAVHqdGIHWxcvyNMXfRqX+APnxikozpjO9rg7PHnpqis9g==", - "dev": true, - "dependencies": { - "debug": "^3.1.0" - } - }, - "node_modules/strong-task-emitter/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, "node_modules/stubs": { "version": "3.0.0", "integrity": "sha1-6NK6H6nJBXAwPAMLaQD31fiavls=" @@ -20832,82 +20113,6 @@ "node": ">= 4" } }, - "node_modules/superagent": { - "version": "0.15.1", - "resolved": "https://registry.npmjs.org/superagent/-/superagent-0.15.1.tgz", - "integrity": "sha1-8N+ZVMK5DynkrlStMI5KK0MsxWo=", - "dev": true, - "dependencies": { - "cookiejar": "1.3.0", - "debug": "~0.7.2", - "emitter-component": "1.0.0", - "formidable": "1.0.9", - "methods": "0.0.1", - "mime": "1.2.5", - "qs": "0.6.5" - }, - "engines": { - "node": "*" - } - }, - "node_modules/superagent/node_modules/debug": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz", - "integrity": "sha1-BuHqgILCyxTjmAbiLi9vdX+Srzk=", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/superagent/node_modules/formidable": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.0.9.tgz", - "integrity": "sha1-QZ47zOrT6IdNU59bPnKkxQOzGpg=", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/superagent/node_modules/methods": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/methods/-/methods-0.0.1.tgz", - "integrity": "sha1-J3yQ+L7zlwlkWoNxxRw7bGSOBow=", - "dev": true - }, - "node_modules/superagent/node_modules/mime": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.2.5.tgz", - "integrity": "sha1-nu0HMCKov14WyFZsaGe4gyv7+hM=", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/superagent/node_modules/qs": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/qs/-/qs-0.6.5.tgz", - "integrity": "sha1-KUsmjksNQlD23eGbO4s0k13/FO8=", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/supertest": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/supertest/-/supertest-0.7.1.tgz", - "integrity": "sha1-NJplqL+1IHJQZY9xdhJ5rTpnHYg=", - "dev": true, - "dependencies": { - "methods": "0.0.1", - "superagent": "0.15.1" - } - }, - "node_modules/supertest/node_modules/methods": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/methods/-/methods-0.0.1.tgz", - "integrity": "sha1-J3yQ+L7zlwlkWoNxxRw7bGSOBow=", - "dev": true - }, "node_modules/supports-color": { "version": "5.5.0", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", @@ -22583,56 +21788,6 @@ "resolved": "loopback", "link": true }, - "node_modules/vn-mysql": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/vn-mysql/-/vn-mysql-1.0.3.tgz", - "integrity": "sha1-U3v5swXd+6xZl9oA6ax4zWpY0o0=", - "dependencies": { - "bignumber.js": "2.3.0", - "readable-stream": "1.1.14", - "sqlstring": "2.0.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/vn-mysql/node_modules/bignumber.js": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-2.3.0.tgz", - "integrity": "sha1-WXoC15Htw9ZPF4UOIXieekCV32Y=", - "engines": { - "node": "*" - } - }, - "node_modules/vn-mysql/node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" - }, - "node_modules/vn-mysql/node_modules/readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "node_modules/vn-mysql/node_modules/sqlstring": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.0.1.tgz", - "integrity": "sha1-vNPDkxrxpat9VKVY6zVjyj03i5g=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/vn-mysql/node_modules/string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" - }, "node_modules/w3c-hr-time": { "version": "1.0.2", "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", @@ -24133,11 +23288,6 @@ "node": ">=10.0.0" } }, - "node_modules/xoauth2": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/xoauth2/-/xoauth2-0.1.8.tgz", - "integrity": "sha1-uRb/EOz7VDIPFvJKPpdRIGU6sNI=" - }, "node_modules/xpath": { "version": "0.0.27", "integrity": "sha512-fg03WRxtkCV6ohClePNAECYsmpKKTv5L8y/X3Dn1hQrec3POx2jHZ/0P2qQ6HvsrU1BmeqXcof3NGGueG6LxwQ==", @@ -26386,11 +25536,6 @@ "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", "dev": true }, - "addressparser": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/addressparser/-/addressparser-0.3.2.tgz", - "integrity": "sha1-WYc/Nej89sc2HBAjkmHXbhU0i7I=" - }, "agent-base": { "version": "4.3.0", "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", @@ -27192,6 +26337,7 @@ }, "base64-js": { "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" }, "batch": { @@ -27245,34 +26391,6 @@ "safe-buffer": "^5.1.1" } }, - "blanket": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/blanket/-/blanket-1.1.10.tgz", - "integrity": "sha1-m+r8WbZmvUetlOxkCCvxl++Ms0I=", - "dev": true, - "requires": { - "acorn": "^1.0.3", - "falafel": "~1.2.0", - "foreach": "^2.0.5", - "isarray": "0.0.1", - "object-keys": "^1.0.6", - "xtend": "~4.0.0" - }, - "dependencies": { - "acorn": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-1.2.2.tgz", - "integrity": "sha1-yM4n3grMdtiW0rH6099YjZ6C8BQ=", - "dev": true - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - } - } - }, "block-stream": { "version": "0.0.9", "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=", @@ -28180,109 +27298,6 @@ } } }, - "connect": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/connect/-/connect-2.12.0.tgz", - "integrity": "sha1-Mdj6DcrN8ZCNgivSkjvootKn7Zo=", - "requires": { - "batch": "0.5.0", - "buffer-crc32": "0.2.1", - "bytes": "0.2.1", - "cookie": "0.1.0", - "cookie-signature": "1.0.1", - "debug": ">= 0.7.3 < 1", - "fresh": "0.2.0", - "methods": "0.1.0", - "multiparty": "2.2.0", - "negotiator": "0.3.0", - "pause": "0.0.1", - "qs": "0.6.6", - "raw-body": "1.1.2", - "send": "0.1.4", - "uid2": "0.0.3" - }, - "dependencies": { - "batch": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/batch/-/batch-0.5.0.tgz", - "integrity": "sha1-/S4Fp6XWlrTbkxQBPihdj/NVfsM=" - }, - "buffer-crc32": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.1.tgz", - "integrity": "sha1-vj5TgvwCttYySVasGvmKqYsIU0w=" - }, - "bytes": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-0.2.1.tgz", - "integrity": "sha1-VVsIq8sGP4l1kFMCUj5M1P/f3zE=" - }, - "cookie": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.1.0.tgz", - "integrity": "sha1-kOtGndzpBchm3mh+/EMTHYgB+dA=" - }, - "cookie-signature": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.1.tgz", - "integrity": "sha1-ROByFIrwHm6OJK+/EmkNaK5pjss=" - }, - "debug": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-0.8.1.tgz", - "integrity": "sha1-IP9NJvXkIstoobrLu2EDmtjBwTA=" - }, - "fresh": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.2.0.tgz", - "integrity": "sha1-v9lALPPfEsSkwxDHn5mj3eE9NKc=" - }, - "methods": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/methods/-/methods-0.1.0.tgz", - "integrity": "sha1-M11Cnu/SG3us8unJIqjSvRSjDk8=" - }, - "mime": { - "version": "1.2.11", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz", - "integrity": "sha1-WCA+7Ybjpe8XrtK32evUfwpg3RA=" - }, - "negotiator": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.3.0.tgz", - "integrity": "sha1-cG1pLv7d9XTVfqn7GriaT6fuj2A=" - }, - "qs": { - "version": "0.6.6", - "resolved": "https://registry.npmjs.org/qs/-/qs-0.6.6.tgz", - "integrity": "sha1-bgFQmP9RlouKPIGQAdXyyJvEsQc=" - }, - "range-parser": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-0.0.4.tgz", - "integrity": "sha1-wEJ//vUcEKy6B4KkbJYC50T/Ygs=" - }, - "raw-body": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-1.1.2.tgz", - "integrity": "sha1-x0swBN6l3v0WlhcRBqx0DsMdYr4=", - "requires": { - "bytes": "~0.2.1" - } - }, - "send": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/send/-/send-0.1.4.tgz", - "integrity": "sha1-vnDY0b4B3mGCGvE3gLUDRaT3Gr0=", - "requires": { - "debug": "*", - "fresh": "0.2.0", - "mime": "~1.2.9", - "range-parser": "0.0.4" - } - } - } - }, "connect-history-api-fallback": { "version": "1.6.0", "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==", @@ -28341,12 +27356,6 @@ "version": "1.0.6", "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" }, - "cookiejar": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-1.3.0.tgz", - "integrity": "sha1-3QCzVnkCHpnL1OhVua0EGRNHR2U=", - "dev": true - }, "copy-concurrently": { "version": "1.0.5", "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", @@ -28397,17 +27406,13 @@ }, "core-js-pure": { "version": "3.9.1", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.9.1.tgz", "integrity": "sha512-laz3Zx0avrw9a4QEIdmIblnVuJz8W51leY9iLThatCsFawWxC3sE4guASC78JbCin+DkwMpCdp1AVAuzL/GN7A==" }, "core-util-is": { "version": "1.0.2", "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, - "cors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cors/-/cors-1.0.1.tgz", - "integrity": "sha1-2LGLrJRgrv1b+7BvXYaE9yBvbZ0=" - }, "create-ecdh": { "version": "4.0.4", "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", @@ -28996,10 +28001,12 @@ "dependencies": { "domelementtype": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.1.0.tgz", "integrity": "sha512-LsTgx/L5VpD+Q8lmsXSHW2WpA+eBlZ9HPf3erD1IoPF00/3JKHZ3BknUVA2QGDNu69ZNmyFmCWBSO45XjYKC5w==" }, "entities": { "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==" } } @@ -29198,12 +28205,6 @@ } } }, - "emitter-component": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/emitter-component/-/emitter-component-1.0.0.tgz", - "integrity": "sha1-8E3Rj8PcPpp0y8DzELCIZm5MAW8=", - "dev": true - }, "emitter-listener": { "version": "1.1.2", "integrity": "sha512-Bt1sBAGFHY9DKY+4/2cV6izcKJUf5T7/gkdmkxzX/qv9CcGH8xSwVRW5mtX03SWJtRTWSOpzCuWN9rBFYZepZQ==", @@ -29230,24 +28231,6 @@ "version": "1.0.2", "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" }, - "encoding": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", - "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", - "requires": { - "iconv-lite": "^0.6.2" - }, - "dependencies": { - "iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "requires": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - } - } - } - }, "encoding-japanese": { "version": "1.0.30", "integrity": "sha512-bd/DFLAoJetvv7ar/KIpE3CNO8wEuyrt9Xuw6nSMiZ+Vrz/Q21BPsMHvARL2Wz6IKHKXgb+DWZqtRg1vql9cBg==" @@ -30054,32 +29037,6 @@ "version": "0.1.8", "integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A=" }, - "falafel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/falafel/-/falafel-1.2.0.tgz", - "integrity": "sha1-wY0k71CRF0pJfzGM0ksCaiXN2rQ=", - "dev": true, - "requires": { - "acorn": "^1.0.3", - "foreach": "^2.0.5", - "isarray": "0.0.1", - "object-keys": "^1.0.6" - }, - "dependencies": { - "acorn": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-1.2.2.tgz", - "integrity": "sha1-yM4n3grMdtiW0rH6099YjZ6C8BQ=", - "dev": true - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - } - } - }, "fancy-log": { "version": "1.3.3", "integrity": "sha512-k9oEhlyc0FrVh25qYuSELjr8oxsCoc4/LEZfg2iJJrfEk/tZL9bCoJE47gqAvI2m/AUjluCS4+3I0eTx8n3AEw==", @@ -30427,12 +29384,6 @@ "for-in": "^1.0.1" } }, - "foreach": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", - "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", - "dev": true - }, "forever-agent": { "version": "0.6.1", "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" @@ -30448,6 +29399,7 @@ }, "formidable": { "version": "1.2.2", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.2.tgz", "integrity": "sha512-V8gLm+41I/8kguQ4/o1D3RIHRmhYFG4pnNyonvua+40rqcEmT4+V71yaZ3B457xbbgCsCfjSPi65u/W6vK1U5Q==" }, "forwarded": { @@ -30520,6 +29472,17 @@ "version": "1.0.0", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, + "fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "dev": true, + "optional": true, + "requires": { + "bindings": "^1.5.0", + "nan": "^2.12.1" + } + }, "fstream": { "version": "1.0.12", "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", @@ -31293,6 +30256,13 @@ "to-regex-range": "^5.0.1" } }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, "get-stream": { "version": "4.1.0", "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", @@ -33470,6 +32440,13 @@ "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true } } }, @@ -34574,11 +33551,6 @@ "safe-buffer": "^5.0.1" } }, - "keypress": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/keypress/-/keypress-0.1.0.tgz", - "integrity": "sha1-SjGI1CkbZrT2XtuZ+AaqmuKTWSo=" - }, "keyv": { "version": "3.1.0", "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", @@ -35321,22 +34293,6 @@ "yallist": "^3.0.2" } }, - "mailcomposer": { - "version": "0.1.34", - "resolved": "https://registry.npmjs.org/mailcomposer/-/mailcomposer-0.1.34.tgz", - "integrity": "sha1-a9X6QrVAR4kNKuMhiImuxvJOxQA=", - "requires": { - "mime": "1.2.9", - "mimelib": "~0.2" - }, - "dependencies": { - "mime": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.2.9.tgz", - "integrity": "sha1-AJzUCGe9Nd5SGzuWbwTi+NTRPQk=" - } - } - }, "mailparser": { "version": "2.8.1", "integrity": "sha512-H/CYAO9dsw6SFNbEGGpZsejVSWDcFlyHjb1OkHUWg0wggUekva1tNc28trB155nSqM8rhtbwTKt//orX0AmJxQ==", @@ -35793,15 +34749,6 @@ "mime-db": "1.46.0" } }, - "mimelib": { - "version": "0.2.19", - "resolved": "https://registry.npmjs.org/mimelib/-/mimelib-0.2.19.tgz", - "integrity": "sha1-N+yQpqx9AJVIUdCywxYY8KSdoO4=", - "requires": { - "addressparser": "~0.3.2", - "encoding": "~0.1.7" - } - }, "mimic-fn": { "version": "2.1.0", "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" @@ -36051,38 +34998,6 @@ "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=", "dev": true }, - "multiparty": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/multiparty/-/multiparty-2.2.0.tgz", - "integrity": "sha1-pWfCrwAK0i3I8qZT2Rl4rh9TFvQ=", - "requires": { - "readable-stream": "~1.1.9", - "stream-counter": "~0.2.0" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" - }, - "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" - } - } - }, "multipipe": { "version": "0.1.2", "integrity": "sha1-Ko8t33Du1WTf8tV/HhoTfZ8FB4s=", @@ -37245,24 +36160,6 @@ "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", "dev": true }, - "passport": { - "version": "0.1.18", - "resolved": "https://registry.npmjs.org/passport/-/passport-0.1.18.tgz", - "integrity": "sha1-yCZEedy2QUytu2Z1LRKzfgtlJaE=", - "requires": { - "pause": "0.0.1", - "pkginfo": "0.2.x" - } - }, - "passport-local": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/passport-local/-/passport-local-0.1.6.tgz", - "integrity": "sha1-+wz4KASNuTG2fRmYXHqgbdN3qds=", - "requires": { - "passport": "~0.1.1", - "pkginfo": "0.2.x" - } - }, "path-browserify": { "version": "0.0.1", "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==", @@ -37322,11 +36219,6 @@ "pinkie-promise": "^2.0.0" } }, - "pause": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", - "integrity": "sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10=" - }, "pbkdf2": { "version": "3.1.1", "integrity": "sha512-4Ejy1OPxi9f2tt1rRV7Go7zmfDQ+ZectEQz3VGUQhgq62HtIRPDyG/JtnwIxs6x3uNMwo2V7q1fMvKjb+Tnpqg==", @@ -37450,11 +36342,6 @@ } } }, - "pkginfo": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/pkginfo/-/pkginfo-0.2.3.tgz", - "integrity": "sha1-cjnEKl72wwuPMoQ52bn/cQQkkPg=" - }, "plugin-error": { "version": "1.0.1", "integrity": "sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==", @@ -37898,11 +36785,6 @@ "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", "dev": true }, - "rai": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/rai/-/rai-0.1.12.tgz", - "integrity": "sha1-jM/QFND5YIYw3XPBm45LBXdUpqY=" - }, "randombytes": { "version": "2.1.0", "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", @@ -39367,6 +38249,7 @@ }, "simple-concat": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==" }, "simple-get": { @@ -39391,15 +38274,6 @@ } } }, - "simplesmtp": { - "version": "0.3.35", - "resolved": "https://registry.npmjs.org/simplesmtp/-/simplesmtp-0.3.35.tgz", - "integrity": "sha1-AXseuLJjF6w20qKoqTJjGIBzagM=", - "requires": { - "rai": "~0.1.11", - "xoauth2": "~0.1.8" - } - }, "sisteransi": { "version": "1.0.5", "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", @@ -39913,37 +38787,6 @@ "duplexer": "~0.0.3" } }, - "stream-counter": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/stream-counter/-/stream-counter-0.2.0.tgz", - "integrity": "sha1-3tJmVWMZyLDiIoErnPOyb6fZR94=", - "requires": { - "readable-stream": "~1.1.8" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" - }, - "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" - } - } - }, "stream-each": { "version": "1.2.3", "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==", @@ -40380,26 +39223,6 @@ } } }, - "strong-task-emitter": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/strong-task-emitter/-/strong-task-emitter-0.0.8.tgz", - "integrity": "sha512-SWbn6ucuV4jVJMB61lbzqlJiIFG/jwGiUJ09JjxhtAVHqdGIHWxcvyNMXfRqX+APnxikozpjO9rg7PHnpqis9g==", - "dev": true, - "requires": { - "debug": "^3.1.0" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - } - } - }, "stubs": { "version": "3.0.0", "integrity": "sha1-6NK6H6nJBXAwPAMLaQD31fiavls=" @@ -40425,71 +39248,6 @@ } } }, - "superagent": { - "version": "0.15.1", - "resolved": "https://registry.npmjs.org/superagent/-/superagent-0.15.1.tgz", - "integrity": "sha1-8N+ZVMK5DynkrlStMI5KK0MsxWo=", - "dev": true, - "requires": { - "cookiejar": "1.3.0", - "debug": "~0.7.2", - "emitter-component": "1.0.0", - "formidable": "1.0.9", - "methods": "0.0.1", - "mime": "1.2.5", - "qs": "0.6.5" - }, - "dependencies": { - "debug": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz", - "integrity": "sha1-BuHqgILCyxTjmAbiLi9vdX+Srzk=", - "dev": true - }, - "formidable": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.0.9.tgz", - "integrity": "sha1-QZ47zOrT6IdNU59bPnKkxQOzGpg=", - "dev": true - }, - "methods": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/methods/-/methods-0.0.1.tgz", - "integrity": "sha1-J3yQ+L7zlwlkWoNxxRw7bGSOBow=", - "dev": true - }, - "mime": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.2.5.tgz", - "integrity": "sha1-nu0HMCKov14WyFZsaGe4gyv7+hM=", - "dev": true - }, - "qs": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/qs/-/qs-0.6.5.tgz", - "integrity": "sha1-KUsmjksNQlD23eGbO4s0k13/FO8=", - "dev": true - } - } - }, - "supertest": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/supertest/-/supertest-0.7.1.tgz", - "integrity": "sha1-NJplqL+1IHJQZY9xdhJ5rTpnHYg=", - "dev": true, - "requires": { - "methods": "0.0.1", - "superagent": "0.15.1" - }, - "dependencies": { - "methods": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/methods/-/methods-0.0.1.tgz", - "integrity": "sha1-J3yQ+L7zlwlkWoNxxRw7bGSOBow=", - "dev": true - } - } - }, "supports-color": { "version": "5.5.0", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", @@ -40568,6 +39326,7 @@ }, "ieee754": { "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" }, "punycode": { @@ -40590,6 +39349,7 @@ }, "swagger-ui": { "version": "2.2.10", + "resolved": "https://registry.npmjs.org/swagger-ui/-/swagger-ui-2.2.10.tgz", "integrity": "sha1-sl56IWZOXZC/OR2zDbCN5B6FLXs=" }, "symbol-tree": { @@ -40969,6 +39729,7 @@ }, "to-iso-string": { "version": "0.0.2", + "resolved": "https://registry.npmjs.org/to-iso-string/-/to-iso-string-0.0.2.tgz", "integrity": "sha1-TcGeZk38y+Jb2NtQiwDG2hWCVdE=" }, "to-object-path": { @@ -41822,291 +40583,7 @@ "dev": true }, "vn-loopback": { - "version": "file:loopback", - "requires": { - "bcryptjs": "~0.7.10", - "blanket": "~1.1.5", - "debug": "~0.7.2", - "ejs": "~0.8.4", - "express": "~3.4.0", - "inflection": "~1.2.5", - "loopback-datasource-juggler": "~1.0.0", - "mocha": "~1.12.1", - "nodemailer": "~0.4.4", - "passport": "~0.1.17", - "passport-local": "~0.1.6", - "strong-remoting": "~1.0.0", - "strong-task-emitter": "0.0.x", - "supertest": "~0.7.1" - }, - "dependencies": { - "async": { - "version": "0.2.10", - "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", - "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E=" - }, - "bcryptjs": { - "version": "0.7.12", - "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-0.7.12.tgz", - "integrity": "sha1-zNhgV8CvCZhI/iFLffDStnJszOs=" - }, - "buffer-crc32": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.1.tgz", - "integrity": "sha1-vj5TgvwCttYySVasGvmKqYsIU0w=" - }, - "commander": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/commander/-/commander-1.3.2.tgz", - "integrity": "sha1-io8w7GcKb91kr1LxkUuQfXnq1bU=", - "requires": { - "keypress": "0.1.x" - } - }, - "cookie": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.1.0.tgz", - "integrity": "sha1-kOtGndzpBchm3mh+/EMTHYgB+dA=" - }, - "cookie-signature": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.1.tgz", - "integrity": "sha1-ROByFIrwHm6OJK+/EmkNaK5pjss=" - }, - "debug": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz", - "integrity": "sha1-BuHqgILCyxTjmAbiLi9vdX+Srzk=" - }, - "diff": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-1.0.2.tgz", - "integrity": "sha1-Suc/Gu6Nb89ITxoc53zmUdm38Mk=", - "dev": true - }, - "ejs": { - "version": "0.8.8", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-0.8.8.tgz", - "integrity": "sha1-/9xW3MNdApJt1QrRNDm7xUBh1Zg=" - }, - "eventemitter2": { - "version": "0.4.14", - "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz", - "integrity": "sha1-j2G3XN4BKy6esoTUVFWDtWQ7Yas=" - }, - "express": { - "version": "3.4.8", - "resolved": "https://registry.npmjs.org/express/-/express-3.4.8.tgz", - "integrity": "sha1-qnqJht4HBTM39Lxe2aZFPZzI4uE=", - "requires": { - "buffer-crc32": "0.2.1", - "commander": "1.3.2", - "connect": "2.12.0", - "cookie": "0.1.0", - "cookie-signature": "1.0.1", - "debug": ">= 0.7.3 < 1", - "fresh": "0.2.0", - "merge-descriptors": "0.0.1", - "methods": "0.1.0", - "mkdirp": "0.3.5", - "range-parser": "0.0.4", - "send": "0.1.4" - } - }, - "fresh": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.2.0.tgz", - "integrity": "sha1-v9lALPPfEsSkwxDHn5mj3eE9NKc=" - }, - "glob": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/glob/-/glob-3.2.1.tgz", - "integrity": "sha1-V69w7HO6IyO/4/KaBndl22TF11g=", - "dev": true, - "requires": { - "graceful-fs": "~1.2.0", - "inherits": "1", - "minimatch": "~0.2.11" - } - }, - "graceful-fs": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-1.2.3.tgz", - "integrity": "sha1-FaSAaldUfLLS2/J/QuiajDRRs2Q=", - "dev": true - }, - "growl": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.7.0.tgz", - "integrity": "sha1-3i1mE20ALhErpw8/EMMc98NQsto=", - "dev": true - }, - "inflection": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.2.7.tgz", - "integrity": "sha1-WdtFBTEKdGZ3GC7UbhVeADv7NZE=" - }, - "inherits": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-1.0.2.tgz", - "integrity": "sha1-ykMJ2t7mtUzAuNJH6NfHoJdb3Js=", - "dev": true - }, - "loopback-datasource-juggler": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/loopback-datasource-juggler/-/loopback-datasource-juggler-1.0.0.tgz", - "integrity": "sha1-3A+OUMBK8ENRkyr/cHkoLsrlM+U=", - "requires": { - "async": "~0.2.9", - "inflection": "~1.2.6", - "traverse": "~0.6.5" - } - }, - "lru-cache": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", - "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=", - "dev": true - }, - "merge-descriptors": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-0.0.1.tgz", - "integrity": "sha1-L/CYDJJM+B0LXR+2ARd8uLtWwNA=" - }, - "methods": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/methods/-/methods-0.1.0.tgz", - "integrity": "sha1-M11Cnu/SG3us8unJIqjSvRSjDk8=" - }, - "mime": { - "version": "1.2.11", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz", - "integrity": "sha1-WCA+7Ybjpe8XrtK32evUfwpg3RA=" - }, - "minimatch": { - "version": "0.2.14", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz", - "integrity": "sha1-x054BXT2PG+aCQ6Q775u9TpqdWo=", - "dev": true, - "requires": { - "lru-cache": "2", - "sigmund": "~1.0.0" - } - }, - "mkdirp": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz", - "integrity": "sha1-3j5fiWHIjHh+4TaN+EmsRBPsqNc=" - }, - "mocha": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-1.12.1.tgz", - "integrity": "sha1-UhLj9ZFO74wIiK40Tmp90uWsKUo=", - "dev": true, - "requires": { - "commander": "0.6.1", - "debug": "*", - "diff": "1.0.2", - "glob": "3.2.1", - "growl": "1.7.x", - "jade": "0.26.3", - "mkdirp": "0.3.5" - }, - "dependencies": { - "commander": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-0.6.1.tgz", - "integrity": "sha1-+mihT2qUXVTbvlDYzbMyDp47GgY=", - "dev": true - } - } - }, - "nodemailer": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-0.4.4.tgz", - "integrity": "sha1-z8sMFE903PSrM3hQINggdv+5BXI=", - "requires": { - "mailcomposer": "~0.1", - "simplesmtp": "~0.2 || ~0.3" - } - }, - "qs": { - "version": "0.6.6", - "resolved": "https://registry.npmjs.org/qs/-/qs-0.6.6.tgz", - "integrity": "sha1-bgFQmP9RlouKPIGQAdXyyJvEsQc=" - }, - "range-parser": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-0.0.4.tgz", - "integrity": "sha1-wEJ//vUcEKy6B4KkbJYC50T/Ygs=" - }, - "send": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/send/-/send-0.1.4.tgz", - "integrity": "sha1-vnDY0b4B3mGCGvE3gLUDRaT3Gr0=", - "requires": { - "debug": "*", - "fresh": "0.2.0", - "mime": "~1.2.9", - "range-parser": "0.0.4" - } - }, - "strong-remoting": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strong-remoting/-/strong-remoting-1.0.0.tgz", - "integrity": "sha1-XIQPL7F97LVVXKoZ98uUVJUzy9s=", - "requires": { - "cors": "~1.0.1", - "debug": "~0.7.2", - "eventemitter2": "~0.4.11", - "express": "~3.4.0", - "qs": "~0.6.5" - } - } - } - }, - "vn-mysql": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/vn-mysql/-/vn-mysql-1.0.3.tgz", - "integrity": "sha1-U3v5swXd+6xZl9oA6ax4zWpY0o0=", - "requires": { - "bignumber.js": "2.3.0", - "readable-stream": "1.1.14", - "sqlstring": "2.0.1" - }, - "dependencies": { - "bignumber.js": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-2.3.0.tgz", - "integrity": "sha1-WXoC15Htw9ZPF4UOIXieekCV32Y=" - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" - }, - "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "sqlstring": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.0.1.tgz", - "integrity": "sha1-vNPDkxrxpat9VKVY6zVjyj03i5g=" - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" - } - } + "version": "file:loopback" }, "w3c-hr-time": { "version": "1.0.2", @@ -42193,6 +40670,13 @@ "to-regex-range": "^5.0.1" } }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, "is-binary-path": { "version": "2.1.0", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", @@ -43192,7 +41676,6 @@ }, "ws": { "version": "7.5.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.0.tgz", "integrity": "sha512-6ezXvzOZupqKj4jUqbQ9tXuJNo+BR2gU8fFRk3XCP3e0G6WT414u5ELe6Y0vtp7kmSJ3F7YWObSNr1ESsgi4vw==", "requires": {} }, @@ -43254,11 +41737,6 @@ "integrity": "sha512-Foaj5FXVzgn7xFzsKeNIde9g6aFBxTPi37iwsno8QvApmtg7KYrr+OPyRHcJF7dud2a5nGRBXK3n0dL62Gf7PA==", "dev": true }, - "xoauth2": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/xoauth2/-/xoauth2-0.1.8.tgz", - "integrity": "sha1-uRb/EOz7VDIPFvJKPpdRIGU6sNI=" - }, "xpath": { "version": "0.0.27", "integrity": "sha512-fg03WRxtkCV6ohClePNAECYsmpKKTv5L8y/X3Dn1hQrec3POx2jHZ/0P2qQ6HvsrU1BmeqXcof3NGGueG6LxwQ==" From cc90a08f0333af6d554906b4779431be1d1244f9 Mon Sep 17 00:00:00 2001 From: carlosjr Date: Tue, 21 Sep 2021 18:48:59 +0200 Subject: [PATCH 03/47] refactor(ticket): ticket endpoins now can receive transactions --- .../sales-monitor/specs/salesFilter.spec.js | 42 +-- .../ticket/back/methods/state/isEditable.js | 18 +- .../methods/state/specs/isEditable.spec.js | 134 +++++++--- .../methods/ticket-tracking/changeState.js | 82 ++++-- .../ticket-tracking/specs/changeState.spec.js | 157 ++++++----- modules/ticket/back/methods/ticket/new.js | 6 +- .../methods/ticket/recalculateComponents.js | 32 ++- modules/ticket/back/methods/ticket/restore.js | 2 +- modules/ticket/back/methods/ticket/sendSms.js | 62 +++-- .../ticket/back/methods/ticket/setDeleted.js | 210 ++++++++------- .../specs/recalculateComponents.spec.js | 43 ++- .../back/methods/ticket/specs/sendSms.spec.js | 39 +-- .../methods/ticket/specs/setDeleted.spec.js | 150 ++++++----- .../back/methods/ticket/specs/summary.spec.js | 64 ++++- .../ticket/specs/transferSales.spec.js | 213 +++++++-------- .../ticket/specs/updateDiscount.spec.js | 247 ++++++++++-------- .../ticket/specs/updateEditableTicket.spec.js | 48 ++-- .../methods/ticket/specs/uploadFile.spec.js | 29 +- modules/ticket/back/methods/ticket/summary.js | 38 +-- .../back/methods/ticket/transferSales.js | 65 +++-- .../back/methods/ticket/updateDiscount.js | 43 +-- .../methods/ticket/updateEditableTicket.js | 32 ++- .../ticket/back/methods/ticket/uploadFile.js | 45 ++-- modules/zone/back/methods/agency/getLanded.js | 5 +- 24 files changed, 1074 insertions(+), 732 deletions(-) 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 53cd9941e..ceea82ca8 100644 --- a/modules/monitor/back/methods/sales-monitor/specs/salesFilter.spec.js +++ b/modules/monitor/back/methods/sales-monitor/specs/salesFilter.spec.js @@ -1,15 +1,15 @@ -const app = require('vn-loopback/server/server'); +const models = require('vn-loopback/server/server').models; describe('SalesMonitor salesFilter()', () => { - it('should return the tickets matching the filter', async() => { + it('should now return the tickets matching the filter', async() => { const ctx = {req: {accessToken: {userId: 9}}, args: {}}; const filter = {order: 'id DESC'}; - const result = await app.models.SalesMonitor.salesFilter(ctx, filter); + const result = await models.SalesMonitor.salesFilter(ctx, filter); expect(result.length).toEqual(24); }); - it('should return the tickets matching the problems on true', async() => { + it('should now return the tickets matching the problems on true', async() => { const yesterday = new Date(); yesterday.setHours(0, 0, 0, 0); const today = new Date(); @@ -21,12 +21,12 @@ describe('SalesMonitor salesFilter()', () => { to: today }}; const filter = {}; - const result = await app.models.SalesMonitor.salesFilter(ctx, filter); + const result = await models.SalesMonitor.salesFilter(ctx, filter); expect(result.length).toEqual(9); }); - it('should return the tickets matching the problems on false', async() => { + it('should now return the tickets matching the problems on false', async() => { const yesterday = new Date(); yesterday.setDate(yesterday.getDate() - 1); yesterday.setHours(0, 0, 0, 0); @@ -39,33 +39,33 @@ describe('SalesMonitor salesFilter()', () => { to: today }}; const filter = {}; - const result = await app.models.SalesMonitor.salesFilter(ctx, filter); + const result = await models.SalesMonitor.salesFilter(ctx, filter); expect(result.length).toEqual(0); }); - it('should return the tickets matching the problems on null', async() => { + it('should now return the tickets matching the problems on null', async() => { const ctx = {req: {accessToken: {userId: 9}}, args: {problems: null}}; const filter = {}; - const result = await app.models.SalesMonitor.salesFilter(ctx, filter); + const result = await models.SalesMonitor.salesFilter(ctx, filter); expect(result.length).toEqual(24); }); - it('should return the tickets matching the orderId 11', async() => { + it('should now return the tickets matching the orderId 11', async() => { const ctx = {req: {accessToken: {userId: 9}}, args: {orderFk: 11}}; const filter = {}; - const result = await app.models.SalesMonitor.salesFilter(ctx, filter); + const result = await models.SalesMonitor.salesFilter(ctx, filter); const firstRow = result[0]; expect(result.length).toEqual(1); expect(firstRow.id).toEqual(11); }); - it('should return the tickets with grouped state "Pending" and not "Ok" nor "BOARDING"', async() => { + it('should now return the tickets with grouped state "Pending" and not "Ok" nor "BOARDING"', async() => { const ctx = {req: {accessToken: {userId: 9}}, args: {pending: true}}; const filter = {}; - const result = await app.models.SalesMonitor.salesFilter(ctx, filter); + const result = await models.SalesMonitor.salesFilter(ctx, filter); const length = result.length; const anyResult = result[Math.floor(Math.random() * Math.floor(length))]; @@ -74,10 +74,10 @@ describe('SalesMonitor salesFilter()', () => { expect(anyResult.state).toMatch(/(Libre|Arreglar)/); }); - it('should return the tickets that are not pending', async() => { + it('should now return the tickets that are not pending', async() => { const ctx = {req: {accessToken: {userId: 9}}, args: {pending: false}}; const filter = {}; - const result = await app.models.SalesMonitor.salesFilter(ctx, filter); + const result = await models.SalesMonitor.salesFilter(ctx, filter); const firstRow = result[0]; const secondRow = result[1]; const thirdRow = result[2]; @@ -88,18 +88,18 @@ describe('SalesMonitor salesFilter()', () => { expect(thirdRow.state).toEqual('Entregado'); }); - it('should return the tickets from the worker team', async() => { + it('should now return the tickets from the worker team', async() => { const ctx = {req: {accessToken: {userId: 18}}, args: {myTeam: true}}; const filter = {}; - const result = await app.models.SalesMonitor.salesFilter(ctx, filter); + const result = await models.SalesMonitor.salesFilter(ctx, filter); expect(result.length).toEqual(20); }); - it('should return the tickets that are not from the worker team', async() => { + it('should now return the tickets that are not from the worker team', async() => { const ctx = {req: {accessToken: {userId: 18}}, args: {myTeam: false}}; const filter = {}; - const result = await app.models.SalesMonitor.salesFilter(ctx, filter); + const result = await models.SalesMonitor.salesFilter(ctx, filter); expect(result.length).toEqual(4); }); @@ -113,7 +113,7 @@ describe('SalesMonitor salesFilter()', () => { const ctx = {req: {accessToken: {userId: 18}}, args: {}}; const filter = {order: 'totalProblems DESC'}; - const result = await app.models.SalesMonitor.salesFilter(ctx, filter); + const result = await models.SalesMonitor.salesFilter(ctx, filter); const firstTicket = result.shift(); const secondTicket = result.shift(); @@ -131,7 +131,7 @@ describe('SalesMonitor salesFilter()', () => { const ctx = {req: {accessToken: {userId: 18}}, args: {}}; const filter = {order: 'totalProblems ASC'}; - const result = await app.models.SalesMonitor.salesFilter(ctx, filter); + const result = await models.SalesMonitor.salesFilter(ctx, filter); const firstTicket = result.shift(); const secondTicket = result.shift(); diff --git a/modules/ticket/back/methods/state/isEditable.js b/modules/ticket/back/methods/state/isEditable.js index 34d86aad1..a0d11c2b7 100644 --- a/modules/ticket/back/methods/state/isEditable.js +++ b/modules/ticket/back/methods/state/isEditable.js @@ -18,19 +18,23 @@ module.exports = Self => { } }); - Self.isEditable = async(ctx, stateId) => { + Self.isEditable = async(ctx, stateId, options) => { const accessToken = ctx.req.accessToken; const models = Self.app.models; const userId = accessToken.userId; + const myOptions = {}; - let isProduction = await models.Account.hasRole(userId, 'production'); - let isSalesPerson = await models.Account.hasRole(userId, 'salesPerson'); - let isAdministrative = await models.Account.hasRole(userId, 'administrative'); - let state = await models.State.findById(stateId); + if (typeof options == 'object') + Object.assign(myOptions, options); - let salesPersonAllowed = (isSalesPerson && (state.code == 'PICKER_DESIGNED' || state.code == 'PRINTED')); + const isProduction = await models.Account.hasRole(userId, 'production', myOptions); + const isSalesPerson = await models.Account.hasRole(userId, 'salesPerson', myOptions); + const isAdministrative = await models.Account.hasRole(userId, 'administrative', myOptions); + const state = await models.State.findById(stateId, null, myOptions); - let isAllowed = isProduction || isAdministrative || salesPersonAllowed || state.alertLevel == 0; + const salesPersonAllowed = (isSalesPerson && (state.code == 'PICKER_DESIGNED' || state.code == 'PRINTED')); + + const isAllowed = isProduction || isAdministrative || salesPersonAllowed || state.alertLevel == 0; return isAllowed; }; }; diff --git a/modules/ticket/back/methods/state/specs/isEditable.spec.js b/modules/ticket/back/methods/state/specs/isEditable.spec.js index 518a543bf..20641cfa3 100644 --- a/modules/ticket/back/methods/state/specs/isEditable.spec.js +++ b/modules/ticket/back/methods/state/specs/isEditable.spec.js @@ -1,61 +1,127 @@ -const app = require('vn-loopback/server/server'); +const models = require('vn-loopback/server/server').models; describe('state isEditable()', () => { it('should return false if the state is not editable by a specific role', async() => { - const salesPersonRole = 18; - const onDeliveryState = 13; - let ctx = {req: {accessToken: {userId: salesPersonRole}}}; - let result = await app.models.State.isEditable(ctx, onDeliveryState); + const tx = await models.State.beginTransaction({}); - expect(result).toBe(false); + try { + const options = {transaction: tx}; + + const salesPersonRole = 18; + const onDeliveryState = 13; + const ctx = {req: {accessToken: {userId: salesPersonRole}}}; + const result = await models.State.isEditable(ctx, onDeliveryState, options); + + expect(result).toBe(false); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } }); it('should return true if the state is editable by a specific role', async() => { - const salesPersonRole = 18; - const asignedState = 20; - let ctx = {req: {accessToken: {userId: salesPersonRole}}}; - let result = await app.models.State.isEditable(ctx, asignedState); + const tx = await models.State.beginTransaction({}); - expect(result).toBe(true); + try { + const options = {transaction: tx}; + + const salesPersonRole = 18; + const asignedState = 20; + const ctx = {req: {accessToken: {userId: salesPersonRole}}}; + const result = await models.State.isEditable(ctx, asignedState, options); + + expect(result).toBe(true); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } }); it('should return true again if the state is editable by a specific role', async() => { - const employeeRole = 1; - const fixingState = 1; - let ctx = {req: {accessToken: {userId: employeeRole}}}; - let result = await app.models.State.isEditable(ctx, fixingState); + const tx = await models.State.beginTransaction({}); - expect(result).toBe(true); + try { + const options = {transaction: tx}; + + const employeeRole = 1; + const fixingState = 1; + const ctx = {req: {accessToken: {userId: employeeRole}}}; + const result = await models.State.isEditable(ctx, fixingState, options); + + expect(result).toBe(true); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } }); it('should return false if the state is not editable for the given role', async() => { - const employeeRole = 1; - const asignedState = 13; - let ctx = {req: {accessToken: {userId: employeeRole}}}; - let result = await app.models.State.isEditable(ctx, asignedState); + const tx = await models.State.beginTransaction({}); - expect(result).toBe(false); + try { + const options = {transaction: tx}; + + const employeeRole = 1; + const asignedState = 13; + const ctx = {req: {accessToken: {userId: employeeRole}}}; + const result = await models.State.isEditable(ctx, asignedState, options); + + expect(result).toBe(false); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } }); it('should return true if the state is editable for the given role', async() => { - const productionRole = 49; - const onDeliveryState = 13; - let ctx = {req: {accessToken: {userId: productionRole}}}; - let result = await app.models.State.isEditable(ctx, onDeliveryState); + const tx = await models.State.beginTransaction({}); - expect(result).toBe(true); + try { + const options = {transaction: tx}; + + const productionRole = 49; + const onDeliveryState = 13; + const ctx = {req: {accessToken: {userId: productionRole}}}; + const result = await models.State.isEditable(ctx, onDeliveryState, options); + + expect(result).toBe(true); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } }); it('should return true if the ticket is editable, the role is salesPerson and the ticket state is printed', async() => { - const salesPersonRole = 18; - const printedState = 4; - const okState = 3; - const ctx = {req: {accessToken: {userId: salesPersonRole}}}; + const tx = await models.State.beginTransaction({}); - let canEditCurrent = await app.models.State.isEditable(ctx, printedState); - let canAsignNew = await app.models.State.isEditable(ctx, okState); - let result = canEditCurrent && canAsignNew; + try { + const options = {transaction: tx}; - expect(result).toBe(true); + const salesPersonRole = 18; + const printedState = 4; + const okState = 3; + const ctx = {req: {accessToken: {userId: salesPersonRole}}}; + + const canEditCurrent = await models.State.isEditable(ctx, printedState, options); + const canAsignNew = await models.State.isEditable(ctx, okState, options); + const result = canEditCurrent && canAsignNew; + + expect(result).toBe(true); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } }); }); diff --git a/modules/ticket/back/methods/ticket-tracking/changeState.js b/modules/ticket/back/methods/ticket-tracking/changeState.js index f7baeecfd..4ae9ab40c 100644 --- a/modules/ticket/back/methods/ticket-tracking/changeState.js +++ b/modules/ticket/back/methods/ticket-tracking/changeState.js @@ -23,38 +23,64 @@ module.exports = Self => { } }); - Self.changeState = async(ctx, params) => { - let userId = ctx.req.accessToken.userId; - let models = Self.app.models; + Self.changeState = async(ctx, params, options) => { + const models = Self.app.models; + const myOptions = {}; + let tx; - if (!params.stateFk && !params.code) - throw new UserError('State cannot be blank'); + if (typeof options == 'object') + Object.assign(myOptions, options); - if (params.code) { - let state = await models.State.findOne({where: {code: params.code}, fields: ['id']}); - params.stateFk = state.id; + if (!myOptions.transaction) { + tx = await Self.beginTransaction({}); + myOptions.transaction = tx; } - if (!params.workerFk) { - let worker = await models.Worker.findOne({where: {userFk: userId}}); - params.workerFk = worker.id; + try { + const userId = ctx.req.accessToken.userId; + + if (!params.stateFk && !params.code) + throw new UserError('State cannot be blank'); + + if (params.code) { + const state = await models.State.findOne({ + where: {code: params.code}, + fields: ['id'] + }, myOptions); + + params.stateFk = state.id; + } + + if (!params.workerFk) { + const worker = await models.Worker.findOne({ + where: {userFk: userId} + }, myOptions); + + params.workerFk = worker.id; + } + + const ticketState = await models.TicketState.findById(params.ticketFk, { + fields: ['stateFk'] + }, myOptions); + + let oldStateAllowed; + if (ticketState) + oldStateAllowed = await models.State.isEditable(ctx, ticketState.stateFk, myOptions); + const newStateAllowed = await models.State.isEditable(ctx, params.stateFk, myOptions); + + const isAllowed = (!ticketState || oldStateAllowed == true) && newStateAllowed == true; + + if (!isAllowed) + throw new UserError(`You don't have enough privileges`, 'ACCESS_DENIED'); + + const ticketTracking = await models.TicketTracking.create(params, myOptions); + + if (tx) await tx.commit(); + + return ticketTracking; + } catch (e) { + if (tx) await tx.rollback(); + throw e; } - - let ticketState = await models.TicketState.findById( - params.ticketFk, - {fields: ['stateFk']} - ); - - let oldStateAllowed; - if (ticketState) - oldStateAllowed = await models.State.isEditable(ctx, ticketState.stateFk); - let newStateAllowed = await models.State.isEditable(ctx, params.stateFk); - - let isAllowed = (!ticketState || oldStateAllowed == true) && newStateAllowed == true; - - if (!isAllowed) - throw new UserError(`You don't have enough privileges`, 'ACCESS_DENIED'); - - return models.TicketTracking.create(params); }; }; diff --git a/modules/ticket/back/methods/ticket-tracking/specs/changeState.spec.js b/modules/ticket/back/methods/ticket-tracking/specs/changeState.spec.js index 9b10f18f0..6bee334e4 100644 --- a/modules/ticket/back/methods/ticket-tracking/specs/changeState.spec.js +++ b/modules/ticket/back/methods/ticket-tracking/specs/changeState.spec.js @@ -1,15 +1,34 @@ -const app = require('vn-loopback/server/server'); +const models = require('vn-loopback/server/server').models; const LoopBackContext = require('loopback-context'); describe('ticket changeState()', () => { const salesPersonId = 18; const employeeId = 1; const productionId = 49; - let activeCtx = { + const activeCtx = { accessToken: {userId: 9}, }; - let ctx = {req: activeCtx}; - let ticket; + const ctx = {req: activeCtx}; + const now = new Date(); + const sampleTicket = { + shipped: now, + landed: now, + nickname: 'Many Places', + packages: 0, + updated: now, + priority: 1, + zoneFk: 3, + zonePrice: 5, + zoneBonus: 1, + totalWithVat: 120, + totalWithoutVat: 100, + clientFk: 1106, + warehouseFk: 1, + addressFk: 126, + routeFk: 6, + companyFk: 442, + agencyModeFk: 7 + }; beforeAll(async done => { spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ @@ -19,92 +38,98 @@ describe('ticket changeState()', () => { done(); }); - beforeEach(async done => { - try { - let originalTicket = await app.models.Ticket.findOne({where: {id: 16}}); - originalTicket.id = null; - ticket = await app.models.Ticket.create(originalTicket); - } catch (error) { - console.error(error); - } - - done(); - }); - - afterEach(async done => { - try { - await app.models.Ticket.destroyById(ticket.id); - } catch (error) { - console.error(error); - } - - done(); - }); - - afterAll(async done => { - try { - await app.models.Ticket.destroyById(ticket.id); - } catch (error) { - console.error(error); - } - - done(); - }); - it('should throw if the ticket is not editable and the user isnt production', async() => { - activeCtx.accessToken.userId = salesPersonId; - let params = {ticketFk: 2, stateFk: 3}; + const tx = await models.TicketTracking.beginTransaction({}); + + let error; - let errCode; try { - await app.models.TicketTracking.changeState(ctx, params); + const options = {transaction: tx}; + + activeCtx.accessToken.userId = salesPersonId; + const params = {ticketFk: 2, stateFk: 3}; + + await models.TicketTracking.changeState(ctx, params, options); + + await tx.rollback(); } catch (e) { - errCode = e.code; + await tx.rollback(); + error = e; } - expect(errCode).toBe('ACCESS_DENIED'); + expect(error.code).toBe('ACCESS_DENIED'); }); it('should throw an error if a worker with employee role attemps to a forbidden state', async() => { - activeCtx.accessToken.userId = employeeId; - let params = {ticketFk: 11, stateFk: 13}; + const tx = await models.TicketTracking.beginTransaction({}); + + let error; - let errCode; try { - await app.models.TicketTracking.changeState(ctx, params); + const options = {transaction: tx}; + + activeCtx.accessToken.userId = employeeId; + const params = {ticketFk: 11, stateFk: 13}; + + await models.TicketTracking.changeState(ctx, params, options); + + await tx.rollback(); } catch (e) { - errCode = e.code; + await tx.rollback(); + error = e; } - expect(errCode).toBe('ACCESS_DENIED'); + expect(error.code).toBe('ACCESS_DENIED'); }); it('should be able to create a ticket tracking line for a not editable ticket if the user has the production role', async() => { - activeCtx.accessToken.userId = productionId; - let params = {ticketFk: ticket.id, stateFk: 3}; + const tx = await models.TicketTracking.beginTransaction({}); - let ticketTracking = await app.models.TicketTracking.changeState(ctx, params); + try { + const options = {transaction: tx}; - expect(ticketTracking.__data.ticketFk).toBe(params.ticketFk); - expect(ticketTracking.__data.stateFk).toBe(params.stateFk); - expect(ticketTracking.__data.workerFk).toBe(49); - expect(ticketTracking.__data.id).toBeDefined(); + const ticket = await models.Ticket.create(sampleTicket, options); - // restores - await app.models.TicketTracking.destroyById(ticketTracking.__data.id); + activeCtx.accessToken.userId = productionId; + const params = {ticketFk: ticket.id, stateFk: 3}; + + const ticketTracking = await models.TicketTracking.changeState(ctx, params, options); + + expect(ticketTracking.__data.ticketFk).toBe(params.ticketFk); + expect(ticketTracking.__data.stateFk).toBe(params.stateFk); + expect(ticketTracking.__data.workerFk).toBe(49); + expect(ticketTracking.__data.id).toBeDefined(); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } }); it('should update the ticket tracking line when the user is salesperson, uses the state assigned and a valid worker id', async() => { - let ctx = {req: {accessToken: {userId: 18}}}; - let assignedState = await app.models.State.findOne({where: {code: 'PICKER_DESIGNED'}}); - let params = {ticketFk: ticket.id, stateFk: assignedState.id, workerFk: 1}; - let res = await app.models.TicketTracking.changeState(ctx, params); + const tx = await models.TicketTracking.beginTransaction({}); - expect(res.__data.ticketFk).toBe(params.ticketFk); - expect(res.__data.stateFk).toBe(params.stateFk); - expect(res.__data.workerFk).toBe(params.workerFk); - expect(res.__data.workerFk).toBe(1); - expect(res.__data.id).toBeDefined(); + try { + const options = {transaction: tx}; + + const ticket = await models.Ticket.create(sampleTicket, options); + const ctx = {req: {accessToken: {userId: 18}}}; + const assignedState = await models.State.findOne({where: {code: 'PICKER_DESIGNED'}}, options); + const params = {ticketFk: ticket.id, stateFk: assignedState.id, workerFk: 1}; + const res = await models.TicketTracking.changeState(ctx, params, options); + + expect(res.__data.ticketFk).toBe(params.ticketFk); + expect(res.__data.stateFk).toBe(params.stateFk); + expect(res.__data.workerFk).toBe(params.workerFk); + expect(res.__data.workerFk).toBe(1); + expect(res.__data.id).toBeDefined(); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } }); }); diff --git a/modules/ticket/back/methods/ticket/new.js b/modules/ticket/back/methods/ticket/new.js index a72ea6c45..e6048421e 100644 --- a/modules/ticket/back/methods/ticket/new.js +++ b/modules/ticket/back/methods/ticket/new.js @@ -12,12 +12,12 @@ module.exports = Self => { }, { arg: 'shipped', - type: 'Date', + type: 'date', description: `The shipment date filter` }, { arg: 'landed', - type: 'Date', + type: 'date', description: `The landing date filter` }, { @@ -142,7 +142,7 @@ module.exports = Self => { if (tx) await tx.commit(); - return await ticket; + return ticket; } catch (e) { if (tx) await tx.rollback(); throw e; diff --git a/modules/ticket/back/methods/ticket/recalculateComponents.js b/modules/ticket/back/methods/ticket/recalculateComponents.js index 0648983c5..5b9e8e5dc 100644 --- a/modules/ticket/back/methods/ticket/recalculateComponents.js +++ b/modules/ticket/back/methods/ticket/recalculateComponents.js @@ -11,7 +11,7 @@ module.exports = Self => { http: {source: 'path'} }], returns: { - type: 'Number', + type: 'number', root: true }, http: { @@ -20,12 +20,32 @@ module.exports = Self => { } }); - Self.recalculateComponents = async(ctx, id) => { - const isEditable = await Self.isEditable(ctx, id); + Self.recalculateComponents = async(ctx, id, options) => { + const myOptions = {}; + let tx; - if (!isEditable) - throw new UserError(`The current ticket can't be modified`); + if (typeof options == 'object') + Object.assign(myOptions, options); - return Self.rawSql('CALL vn.ticket_recalcComponents(?, NULL)', [id]); + if (!myOptions.transaction) { + tx = await Self.beginTransaction({}); + myOptions.transaction = tx; + } + + try { + const isEditable = await Self.isEditable(ctx, id, myOptions); + + if (!isEditable) + throw new UserError(`The current ticket can't be modified`); + + const recalculation = await Self.rawSql('CALL vn.ticket_recalcComponents(?, NULL)', [id], myOptions); + + if (tx) await tx.commit(); + + return recalculation; + } catch (e) { + if (tx) await tx.rollback(); + throw e; + } }; }; diff --git a/modules/ticket/back/methods/ticket/restore.js b/modules/ticket/back/methods/ticket/restore.js index a3a79dc7c..c9bb126fd 100644 --- a/modules/ticket/back/methods/ticket/restore.js +++ b/modules/ticket/back/methods/ticket/restore.js @@ -6,7 +6,7 @@ module.exports = Self => { accessType: 'WRITE', accepts: [{ arg: 'id', - type: 'Number', + type: 'number', required: true, description: 'The ticket id', http: {source: 'path'} diff --git a/modules/ticket/back/methods/ticket/sendSms.js b/modules/ticket/back/methods/ticket/sendSms.js index efcaf4eda..efe8ff206 100644 --- a/modules/ticket/back/methods/ticket/sendSms.js +++ b/modules/ticket/back/methods/ticket/sendSms.js @@ -5,23 +5,23 @@ module.exports = Self => { accessType: 'WRITE', accepts: [{ arg: 'id', - type: 'Number', + type: 'number', required: true, description: 'The ticket id', http: {source: 'path'} }, { arg: 'destination', - type: 'String', + type: 'string', required: true, }, { arg: 'message', - type: 'String', + type: 'string', required: true, }], returns: { - type: 'Object', + type: 'object', root: true }, http: { @@ -30,28 +30,46 @@ module.exports = Self => { } }); - Self.sendSms = async(ctx, id, destination, message) => { + Self.sendSms = async(ctx, id, destination, message, options) => { + const myOptions = {}; + let tx; + + if (typeof options == 'object') + Object.assign(myOptions, options); + + if (!myOptions.transaction) { + tx = await Self.beginTransaction({}); + myOptions.transaction = tx; + } + const userId = ctx.req.accessToken.userId; - let sms = await Self.app.models.Sms.send(ctx, id, destination, message); - let logRecord = { - originFk: id, - userFk: userId, - action: 'insert', - changedModel: 'sms', - newInstance: { - destinationFk: id, - destination: destination, - message: message, - statusCode: sms.statusCode, - status: sms.status - } - }; + try { + const sms = await Self.app.models.Sms.send(ctx, id, destination, message); + const logRecord = { + originFk: id, + userFk: userId, + action: 'insert', + changedModel: 'sms', + newInstance: { + destinationFk: id, + destination: destination, + message: message, + statusCode: sms.statusCode, + status: sms.status + } + }; - const ticketLog = await Self.app.models.TicketLog.create(logRecord); + const ticketLog = await Self.app.models.TicketLog.create(logRecord, myOptions); - sms.logId = ticketLog.id; + sms.logId = ticketLog.id; - return sms; + if (tx) await tx.commit(); + + return sms; + } catch (e) { + if (tx) await tx.rollback(); + throw e; + } }; }; diff --git a/modules/ticket/back/methods/ticket/setDeleted.js b/modules/ticket/back/methods/ticket/setDeleted.js index 9e8d202fa..38bd6e7b5 100644 --- a/modules/ticket/back/methods/ticket/setDeleted.js +++ b/modules/ticket/back/methods/ticket/setDeleted.js @@ -6,7 +6,7 @@ module.exports = Self => { accessType: 'WRITE', accepts: [{ arg: 'id', - type: 'Number', + type: 'number', required: true, description: 'The ticket id', http: {source: 'path'} @@ -21,113 +21,133 @@ module.exports = Self => { } }); - Self.setDeleted = async(ctx, id) => { + Self.setDeleted = async(ctx, id, options) => { const models = Self.app.models; - const userId = ctx.req.accessToken.userId; - const isEditable = await Self.isEditable(ctx, id); const $t = ctx.req.__; // $translate + const myOptions = {}; + let tx; - if (!isEditable) - throw new UserError(`The sales of this ticket can't be modified`); + if (typeof options == 'object') + Object.assign(myOptions, options); - // Check if has sales with shelving - const isSalesAssistant = await models.Account.hasRole(userId, 'salesAssistant'); - const sales = await models.Sale.find({ - include: {relation: 'itemShelvingSale'}, - where: {ticketFk: id} - }); - const hasItemShelvingSales = sales.some(sale => { - return sale.itemShelvingSale(); - }); - - if (hasItemShelvingSales && !isSalesAssistant) - throw new UserError(`You cannot delete a ticket that part of it is being prepared`); - - // Check for existing claim - const claimOfATicket = await models.Claim.findOne({where: {ticketFk: id}}); - if (claimOfATicket) - throw new UserError('You must delete the claim id %d first', 'DELETE_CLAIM_FIRST', claimOfATicket.id); - - // Check for existing purchase requests - const hasPurchaseRequests = await models.TicketRequest.count({ - ticketFk: id, - isOk: true - }); - - if (hasPurchaseRequests) - throw new UserError('You must delete all the buy requests first'); - - // removes item shelvings - if (hasItemShelvingSales && isSalesAssistant) { - const promises = []; - for (let sale of sales) { - if (sale.itemShelvingSale()) { - const itemShelvingSale = sale.itemShelvingSale(); - const destroyedShelving = models.ItemShelvingSale.destroyById(itemShelvingSale.id); - promises.push(destroyedShelving); - } - } - await Promise.all(promises); + if (!myOptions.transaction) { + tx = await Self.beginTransaction({}); + myOptions.transaction = tx; } - // Remove ticket greuges - const ticketGreuges = await models.Greuge.find({where: {ticketFk: id}}); - const ownGreuges = ticketGreuges.every(greuge => { - return greuge.ticketFk == id; - }); - if (ownGreuges) { - for (const greuge of ticketGreuges) { - const instance = await models.Greuge.findById(greuge.id); + try { + const userId = ctx.req.accessToken.userId; + const isEditable = await Self.isEditable(ctx, id, myOptions); - await instance.destroy(); - } - } + if (!isEditable) + throw new UserError(`The sales of this ticket can't be modified`); - const ticket = await models.Ticket.findById(id, { - include: [{ - relation: 'client', - scope: { - fields: ['id', 'salesPersonFk'], - include: { - relation: 'salesPersonUser', - scope: { - fields: ['id', 'name'] - } + // Check if has sales with shelving + const isSalesAssistant = await models.Account.hasRole(userId, 'salesAssistant', myOptions); + const sales = await models.Sale.find({ + include: {relation: 'itemShelvingSale'}, + where: {ticketFk: id} + }, myOptions); + const hasItemShelvingSales = sales.some(sale => { + return sale.itemShelvingSale(); + }); + + if (hasItemShelvingSales && !isSalesAssistant) + throw new UserError(`You cannot delete a ticket that part of it is being prepared`); + + // Check for existing claim + const claimOfATicket = await models.Claim.findOne({where: {ticketFk: id}}, myOptions); + if (claimOfATicket) + throw new UserError('You must delete the claim id %d first', 'DELETE_CLAIM_FIRST', claimOfATicket.id); + + // Check for existing purchase requests + const hasPurchaseRequests = await models.TicketRequest.count({ + ticketFk: id, + isOk: true + }, myOptions); + + if (hasPurchaseRequests) + throw new UserError('You must delete all the buy requests first'); + + // removes item shelvings + if (hasItemShelvingSales && isSalesAssistant) { + const promises = []; + for (let sale of sales) { + if (sale.itemShelvingSale()) { + const itemShelvingSale = sale.itemShelvingSale(); + const destroyedShelving = models.ItemShelvingSale.destroyById(itemShelvingSale.id, myOptions); + promises.push(destroyedShelving); } } - }, { - relation: 'ship' - }, { - relation: 'stowaway' - }] - }); + await Promise.all(promises); + } - // Change state to "fixing" if contains an stowaway and remove the link between them - let otherTicketId; - if (ticket.stowaway()) - otherTicketId = ticket.stowaway().shipFk; - else if (ticket.ship()) - otherTicketId = ticket.ship().id; - - if (otherTicketId) { - await models.Ticket.deleteStowaway(ctx, otherTicketId); - await models.TicketTracking.changeState(ctx, { - ticketFk: otherTicketId, - code: 'FIXING' + // Remove ticket greuges + const ticketGreuges = await models.Greuge.find({where: {ticketFk: id}}, myOptions); + const ownGreuges = ticketGreuges.every(greuge => { + return greuge.ticketFk == id; }); - } + if (ownGreuges) { + for (const greuge of ticketGreuges) { + const instance = await models.Greuge.findById(greuge.id, null, myOptions); - // Send notification to salesPerson - const salesPersonUser = ticket.client().salesPersonUser(); - if (salesPersonUser) { - const origin = ctx.req.headers.origin; - const message = $t(`I have deleted the ticket id`, { - id: id, - url: `${origin}/#!/ticket/${id}/summary` - }); - await models.Chat.send(ctx, `@${salesPersonUser.name}`, message); - } + await instance.destroy(myOptions); + } + } - return ticket.updateAttribute('isDeleted', true); + const ticket = await models.Ticket.findById(id, { + include: [{ + relation: 'client', + scope: { + fields: ['id', 'salesPersonFk'], + include: { + relation: 'salesPersonUser', + scope: { + fields: ['id', 'name'] + } + } + } + }, { + relation: 'ship' + }, { + relation: 'stowaway' + }] + }, myOptions); + + // Change state to "fixing" if contains an stowaway and remove the link between them + let otherTicketId; + if (ticket.stowaway()) + otherTicketId = ticket.stowaway().shipFk; + else if (ticket.ship()) + otherTicketId = ticket.ship().id; + + if (otherTicketId) { + await models.Ticket.deleteStowaway(ctx, otherTicketId, myOptions); + await models.TicketTracking.changeState(ctx, { + ticketFk: otherTicketId, + code: 'FIXING' + }, myOptions); + } + + // Send notification to salesPerson + const salesPersonUser = ticket.client().salesPersonUser(); + if (salesPersonUser) { + const origin = ctx.req.headers.origin; + const message = $t(`I have deleted the ticket id`, { + id: id, + url: `${origin}/#!/ticket/${id}/summary` + }); + await models.Chat.send(ctx, `@${salesPersonUser.name}`, message); + } + + const updatedTicket = await ticket.updateAttribute('isDeleted', true, myOptions); + + if (tx) await tx.commit(); + + return updatedTicket; + } catch (e) { + if (tx) await tx.rollback(); + throw e; + } }; }; diff --git a/modules/ticket/back/methods/ticket/specs/recalculateComponents.spec.js b/modules/ticket/back/methods/ticket/specs/recalculateComponents.spec.js index 72be4c3b4..ed10d114f 100644 --- a/modules/ticket/back/methods/ticket/specs/recalculateComponents.spec.js +++ b/modules/ticket/back/methods/ticket/specs/recalculateComponents.spec.js @@ -1,24 +1,43 @@ -const app = require('vn-loopback/server/server'); +const models = require('vn-loopback/server/server').models; describe('ticket recalculateComponents()', () => { const ticketId = 11; it('should update the ticket components', async() => { - const ctx = {req: {accessToken: {userId: 9}}}; - const response = await app.models.Ticket.recalculateComponents(ctx, ticketId); + const tx = await models.Ticket.beginTransaction({}); - expect(response.affectedRows).toBeDefined(); + try { + const options = {transaction: tx}; + + const ctx = {req: {accessToken: {userId: 9}}}; + const response = await models.Ticket.recalculateComponents(ctx, ticketId, options); + + expect(response.affectedRows).toBeDefined(); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } }); it('should throw an error if the ticket is not editable', async() => { - const ctx = {req: {accessToken: {userId: 9}}}; - const immutableTicketId = 1; - await app.models.Ticket.recalculateComponents(ctx, immutableTicketId) - .catch(response => { - expect(response).toEqual(new Error(`The current ticket can't be modified`)); - error = response; - }); + const tx = await models.Ticket.beginTransaction({}); - expect(error).toBeDefined(); + let error; + try { + const options = {transaction: tx}; + + const ctx = {req: {accessToken: {userId: 9}}}; + const immutableTicketId = 1; + await models.Ticket.recalculateComponents(ctx, immutableTicketId, options); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + error = e; + } + + expect(error).toEqual(new Error(`The current ticket can't be modified`)); }); }); diff --git a/modules/ticket/back/methods/ticket/specs/sendSms.spec.js b/modules/ticket/back/methods/ticket/specs/sendSms.spec.js index 61dc60abc..8ec4ca487 100644 --- a/modules/ticket/back/methods/ticket/specs/sendSms.spec.js +++ b/modules/ticket/back/methods/ticket/specs/sendSms.spec.js @@ -1,29 +1,30 @@ -const app = require('vn-loopback/server/server'); +const models = require('vn-loopback/server/server').models; const soap = require('soap'); describe('ticket sendSms()', () => { - let logId; - - afterAll(async done => { - await app.models.TicketLog.destroyById(logId); - - done(); - }); - it('should send a message and log it', async() => { - spyOn(soap, 'createClientAsync').and.returnValue('a so fake client'); - let ctx = {req: {accessToken: {userId: 9}}}; - let id = 11; - let destination = 222222222; - let message = 'this is the message created in a test'; + const tx = await models.Ticket.beginTransaction({}); - let sms = await app.models.Ticket.sendSms(ctx, id, destination, message); + try { + const options = {transaction: tx}; - logId = sms.logId; + spyOn(soap, 'createClientAsync').and.returnValue('a so fake client'); + const ctx = {req: {accessToken: {userId: 9}}}; + const id = 11; + const destination = 222222222; + const message = 'this is the message created in a test'; - let createdLog = await app.models.TicketLog.findById(logId); - let json = JSON.parse(JSON.stringify(createdLog.newInstance)); + const sms = await models.Ticket.sendSms(ctx, id, destination, message, options); - expect(json.message).toEqual(message); + const createdLog = await models.TicketLog.findById(sms.logId, null, options); + const json = JSON.parse(JSON.stringify(createdLog.newInstance)); + + expect(json.message).toEqual(message); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } }); }); diff --git a/modules/ticket/back/methods/ticket/specs/setDeleted.spec.js b/modules/ticket/back/methods/ticket/specs/setDeleted.spec.js index 7d200a72d..73ccc116d 100644 --- a/modules/ticket/back/methods/ticket/specs/setDeleted.spec.js +++ b/modules/ticket/back/methods/ticket/specs/setDeleted.spec.js @@ -1,6 +1,5 @@ -const app = require('vn-loopback/server/server'); +const models = require('vn-loopback/server/server').models; const LoopBackContext = require('loopback-context'); -const models = app.models; describe('ticket setDeleted()', () => { const userId = 1106; @@ -10,95 +9,110 @@ describe('ticket setDeleted()', () => { }; it('should throw an error if the given ticket has a claim', async() => { - const ctx = {req: activeCtx}; - const ticketId = 16; - let error; + const tx = await models.Ticket.beginTransaction({}); + let error; try { - await app.models.Ticket.setDeleted(ctx, ticketId); + const options = {transaction: tx}; + + const ctx = {req: activeCtx}; + const ticketId = 16; + + await models.Ticket.setDeleted(ctx, ticketId, options); + + await tx.rollback(); } catch (e) { + await tx.rollback(); error = e; } - expect(error.translateArgs[0]).toEqual(2); expect(error.message).toEqual('You must delete the claim id %d first'); }); it('should delete the ticket, remove the stowaway link and change the stowaway ticket state to "FIXING" and get rid of the itemshelving', async() => { - spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ - active: activeCtx - }); - const ctx = { - req: { - accessToken: {userId: employeeUser}, - headers: { - origin: 'http://localhost:5000' - }, - __: () => {} - } - }; + const tx = await models.Ticket.beginTransaction({}); - let sampleTicket = await models.Ticket.findById(12); - let sampleStowaway = await models.Ticket.findById(13); + try { + const options = {transaction: tx}; - sampleTicket.id = undefined; - let shipTicket = await models.Ticket.create(sampleTicket); + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ + active: activeCtx + }); + const ctx = { + req: { + accessToken: {userId: employeeUser}, + headers: { + origin: 'http://localhost:5000' + }, + __: () => {} + } + }; - sampleStowaway.id = undefined; - let stowawayTicket = await models.Ticket.create(sampleStowaway); + const sampleTicket = await models.Ticket.findById(12); + const sampleStowaway = await models.Ticket.findById(13); - await models.Stowaway.rawSql(` - INSERT INTO vn.stowaway(id, shipFk) - VALUES (?, ?)`, [stowawayTicket.id, shipTicket.id]); + sampleTicket.id = undefined; + const shipTicket = await models.Ticket.create(sampleTicket, options); - const boardingState = await models.State.findOne({ - where: { - code: 'BOARDING' - } - }); - await models.TicketTracking.create({ - ticketFk: stowawayTicket.id, - stateFk: boardingState.id, - workerFk: ctx.req.accessToken.userId - }); + sampleStowaway.id = undefined; + const stowawayTicket = await models.Ticket.create(sampleStowaway, options); - const okState = await models.State.findOne({ - where: { - code: 'OK' - } - }); - await models.TicketTracking.create({ - ticketFk: shipTicket.id, - stateFk: okState.id, - workerFk: ctx.req.accessToken.userId - }); + await models.Stowaway.rawSql(` + INSERT INTO vn.stowaway(id, shipFk) + VALUES (?, ?)`, [stowawayTicket.id, shipTicket.id], options); - let stowawayTicketState = await models.TicketState.findOne({ - where: { - ticketFk: stowawayTicket.id - } - }); + const boardingState = await models.State.findOne({ + where: { + code: 'BOARDING' + } + }, options); - let stowaway = await models.Stowaway.findById(shipTicket.id); + await models.TicketTracking.create({ + ticketFk: stowawayTicket.id, + stateFk: boardingState.id, + workerFk: ctx.req.accessToken.userId + }, options); - expect(stowaway).toBeDefined(); - expect(stowawayTicketState.code).toEqual('BOARDING'); + const okState = await models.State.findOne({ + where: { + code: 'OK' + } + }, options); - await models.Ticket.setDeleted(ctx, shipTicket.id); + await models.TicketTracking.create({ + ticketFk: shipTicket.id, + stateFk: okState.id, + workerFk: ctx.req.accessToken.userId + }, options); - stowawayTicketState = await models.TicketState.findOne({ - where: { - ticketFk: stowawayTicket.id - } - }); + let stowawayTicketState = await models.TicketState.findOne({ + where: { + ticketFk: stowawayTicket.id + } + }, options); - stowaway = await models.Stowaway.findById(shipTicket.id); + let stowaway = await models.Stowaway.findById(shipTicket.id, null, options); - expect(stowaway).toBeNull(); - expect(stowawayTicketState.code).toEqual('FIXING'); + expect(stowaway).toBeDefined(); + expect(stowawayTicketState.code).toEqual('BOARDING'); - // restores - await models.Ticket.destroyById(shipTicket.id); - await models.Ticket.destroyById(stowawayTicket.id); + await models.Ticket.setDeleted(ctx, shipTicket.id, options); + + stowawayTicketState = await models.TicketState.findOne({ + where: { + ticketFk: stowawayTicket.id + } + }, options); + + stowaway = await models.Stowaway.findById(shipTicket.id, null, options); + + expect(stowaway).toBeNull(); + expect(stowawayTicketState.code).toEqual('FIXING'); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } }); }); diff --git a/modules/ticket/back/methods/ticket/specs/summary.spec.js b/modules/ticket/back/methods/ticket/specs/summary.spec.js index 7d29e8258..5d2991b0a 100644 --- a/modules/ticket/back/methods/ticket/specs/summary.spec.js +++ b/modules/ticket/back/methods/ticket/specs/summary.spec.js @@ -1,28 +1,72 @@ -const app = require('vn-loopback/server/server'); +const models = require('vn-loopback/server/server').models; describe('ticket summary()', () => { it('should return a summary object containing data from 1 ticket', async() => { - let result = await app.models.Ticket.summary(1); + const tx = await models.Ticket.beginTransaction({}); - expect(result.id).toEqual(1); - expect(result.nickname).toEqual('Bat cave'); + try { + const options = {transaction: tx}; + + const result = await models.Ticket.summary(1, options); + + expect(result.id).toEqual(1); + expect(result.nickname).toEqual('Bat cave'); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } }); it('should return a summary object containing sales from 1 ticket', async() => { - let result = await app.models.Ticket.summary(1); + const tx = await models.Ticket.beginTransaction({}); - expect(result.sales.length).toEqual(4); + try { + const options = {transaction: tx}; + + const result = await models.Ticket.summary(1, options); + + expect(result.sales.length).toEqual(4); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } }); it('should return a summary object containing totalWithoutVat for 1 ticket', async() => { - let result = await app.models.Ticket.summary(1); + const tx = await models.Ticket.beginTransaction({}); - expect(result.totalWithoutVat).toEqual(jasmine.any(Number)); + try { + const options = {transaction: tx}; + + const result = await models.Ticket.summary(1, options); + + expect(result.totalWithoutVat).toEqual(jasmine.any(Number)); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } }); it('should return a summary object containing total for 1 ticket', async() => { - let result = await app.models.Ticket.summary(1); + const tx = await models.Ticket.beginTransaction({}); - expect(result.totalWithVat).toEqual(jasmine.any(Number)); + try { + const options = {transaction: tx}; + + const result = await models.Ticket.summary(1, options); + + expect(result.totalWithVat).toEqual(jasmine.any(Number)); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } }); }); diff --git a/modules/ticket/back/methods/ticket/specs/transferSales.spec.js b/modules/ticket/back/methods/ticket/specs/transferSales.spec.js index 5a37abef4..58e598ea9 100644 --- a/modules/ticket/back/methods/ticket/specs/transferSales.spec.js +++ b/modules/ticket/back/methods/ticket/specs/transferSales.spec.js @@ -1,4 +1,4 @@ -const app = require('vn-loopback/server/server'); +const models = require('vn-loopback/server/server').models; const LoopBackContext = require('loopback-context'); describe('sale transferSales()', () => { @@ -8,160 +8,167 @@ describe('sale transferSales()', () => { }; const ctx = {req: activeCtx}; - let createdTicketsIds = []; - beforeAll(() => { spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ active: activeCtx }); }); - afterEach(async done => { - if (createdTicketsIds.length) { - try { - createdTicketsIds.forEach(async createdTicketId => { - await app.models.Ticket.destroyById(createdTicketId); - }); - } catch (error) { - console.error(error); - } + it('should throw an error as the ticket is not editable', async() => { + const tx = await models.Ticket.beginTransaction({}); + + let error; + try { + const options = {transaction: tx}; + + const currentTicketId = 1; + const receiverTicketId = undefined; + const sales = []; + + await models.Ticket.transferSales(ctx, currentTicketId, receiverTicketId, sales, options); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + error = e; } - done(); - }); - - it('should throw an error as the ticket is not editable', async() => { - let error; - - const currentTicketId = 1; - const receiverTicketId = undefined; - const sales = []; - - await app.models.Ticket.transferSales(ctx, currentTicketId, receiverTicketId, sales) - .catch(response => { - expect(response.message).toEqual(`The sales of this ticket can't be modified`); - error = response; - }); - - expect(error).toBeDefined(); + expect(error.message).toEqual(`The sales of this ticket can't be modified`); }); it('should throw an error if the receiving ticket is not editable', async() => { + const tx = await models.Ticket.beginTransaction({}); + let error; + try { + const options = {transaction: tx}; - const currentTicketId = 16; - const receiverTicketId = 1; - const sales = []; + const currentTicketId = 16; + const receiverTicketId = 1; + const sales = []; - await app.models.Ticket.transferSales(ctx, currentTicketId, receiverTicketId, sales) - .catch(response => { - expect(response.message).toEqual(`The sales of the receiver ticket can't be modified`); - error = response; - }); + await models.Ticket.transferSales(ctx, currentTicketId, receiverTicketId, sales, options); - expect(error).toBeDefined(); + await tx.rollback(); + } catch (e) { + await tx.rollback(); + error = e; + } + + expect(error.message).toEqual(`The sales of the receiver ticket can't be modified`); }); it('should transfer the sales from one ticket to a new one then send them back and delete the created ticket', async() => { - const formerTicketId = 11; - let createdTicketId = undefined; + const tx = await models.Ticket.beginTransaction({}); - let formerTicketSales = await app.models.Ticket.getSales(formerTicketId); + try { + const options = {transaction: tx}; - expect(formerTicketSales.length).toEqual(2); + const formerTicketId = 11; + let createdTicketId = undefined; - let createdTicket = await app.models.Ticket.transferSales( - ctx, formerTicketId, createdTicketId, formerTicketSales); + let formerTicketSales = await models.Ticket.getSales(formerTicketId, options); - createdTicketId = createdTicket.id; - createdTicketsIds.push(createdTicketId); + expect(formerTicketSales.length).toEqual(2); - formerTicketSales = await app.models.Ticket.getSales(formerTicketId); - createdTicketSales = await app.models.Ticket.getSales(createdTicketId); + let createdTicket = await models.Ticket.transferSales( + ctx, formerTicketId, createdTicketId, formerTicketSales, options); - expect(formerTicketSales.length).toEqual(0); - expect(createdTicketSales.length).toEqual(2); + createdTicketId = createdTicket.id; - await app.models.Ticket.transferSales( - ctx, createdTicketId, formerTicketId, createdTicketSales); + formerTicketSales = await models.Ticket.getSales(formerTicketId, options); + createdTicketSales = await models.Ticket.getSales(createdTicketId, options); - formerTicketSales = await app.models.Ticket.getSales(formerTicketId); - createdTicketSales = await app.models.Ticket.getSales(createdTicketId); + expect(formerTicketSales.length).toEqual(0); + expect(createdTicketSales.length).toEqual(2); - createdTicket = await app.models.Ticket.findById(createdTicketId); + await models.Ticket.transferSales( + ctx, createdTicketId, formerTicketId, createdTicketSales, options); - expect(createdTicket.isDeleted).toBeTruthy(); - expect(formerTicketSales.length).toEqual(2); - expect(createdTicketSales.length).toEqual(0); + formerTicketSales = await models.Ticket.getSales(formerTicketId, options); + createdTicketSales = await models.Ticket.getSales(createdTicketId, options); + + createdTicket = await models.Ticket.findById(createdTicketId, null, options); + + expect(createdTicket.isDeleted).toBeTruthy(); + expect(formerTicketSales.length).toEqual(2); + expect(createdTicketSales.length).toEqual(0); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } }); describe('sale transferPartialSales()', () => { it('should throw an error in the quantity to transfer exceeds the amount from the original sale', async() => { + const tx = await models.Ticket.beginTransaction({}); + let error; - let currentTicket = await app.models.Ticket.findById(11); - let currentTicketSales = await app.models.Ticket.getSales(currentTicket.id); + try { + const options = {transaction: tx}; - const currentTicketId = currentTicket.id; - const receiverTicketId = undefined; + const currentTicket = await models.Ticket.findById(11, null, options); + const currentTicketSales = await models.Ticket.getSales(currentTicket.id, options); - currentTicketSales[0].quantity = 99; + const currentTicketId = currentTicket.id; + const receiverTicketId = undefined; - await app.models.Ticket.transferSales( - ctx, currentTicketId, receiverTicketId, currentTicketSales) - .catch(response => { - expect(response.message).toEqual(`Invalid quantity`); - error = response; - }); + currentTicketSales[0].quantity = 99; - expect(error).toBeDefined(); + await models.Ticket.transferSales( + ctx, currentTicketId, receiverTicketId, currentTicketSales, options); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + error = e; + } + + expect(error.message).toEqual(`Invalid quantity`); }); it('should transfer two sales to a new ticket but one shall be partial', async() => { - const formerTicketId = 11; - let createdTicketId = undefined; + const tx = await models.Ticket.beginTransaction({}); - let formerTicketSales = await app.models.Ticket.getSales(formerTicketId); + try { + const options = {transaction: tx}; - const partialSaleId = formerTicketSales[0].id; - const completeSaleId = formerTicketSales[1].id; - let partialSaleTotalQuantity = formerTicketSales[0].quantity; + const formerTicketId = 11; + let createdTicketId = undefined; - expect(partialSaleTotalQuantity).toEqual(15); + let formerTicketSales = await models.Ticket.getSales(formerTicketId, options); - formerTicketSales[0].quantity = 1; + const completeSaleId = formerTicketSales[1].id; + let partialSaleTotalQuantity = formerTicketSales[0].quantity; - let createdTicket = await app.models.Ticket.transferSales( - ctx, formerTicketId, createdTicketId, formerTicketSales); + expect(partialSaleTotalQuantity).toEqual(15); - createdTicketId = createdTicket.id; - createdTicketsIds.push(createdTicket.id); + formerTicketSales[0].quantity = 1; - formerTicketSales = await app.models.Ticket.getSales(formerTicketId); - createdTicketSales = await app.models.Ticket.getSales(createdTicketId); + let createdTicket = await models.Ticket.transferSales( + ctx, formerTicketId, createdTicketId, formerTicketSales, options); - const [createdPartialSale] = createdTicketSales.filter(sale => { - return sale.id != completeSaleId; - }); + createdTicketId = createdTicket.id; - expect(formerTicketSales.length).toEqual(1); - expect(formerTicketSales[0].quantity).toEqual(partialSaleTotalQuantity - 1); - expect(createdTicketSales.length).toEqual(2); - expect(createdPartialSale.quantity).toEqual(1); + formerTicketSales = await models.Ticket.getSales(formerTicketId, options); + createdTicketSales = await models.Ticket.getSales(createdTicketId, options); - let saleToRestore = await app.models.Sale.findById(partialSaleId); - await saleToRestore.updateAttribute('quantity', partialSaleTotalQuantity); + const [createdPartialSale] = createdTicketSales.filter(sale => { + return sale.id != completeSaleId; + }); - let saleToReturnToTicket = await app.models.Sale.findById(completeSaleId); - await saleToReturnToTicket.updateAttribute('ticketFk', formerTicketId); + expect(formerTicketSales.length).toEqual(1); + expect(formerTicketSales[0].quantity).toEqual(partialSaleTotalQuantity - 1); + expect(createdTicketSales.length).toEqual(2); + expect(createdPartialSale.quantity).toEqual(1); - formerTicketSales = await app.models.Ticket.getSales(formerTicketId); - - const [returningPartialSale] = formerTicketSales.filter(sale => { - return sale.id == partialSaleId; - }); - - expect(returningPartialSale.quantity).toEqual(partialSaleTotalQuantity); - expect(formerTicketSales.length).toEqual(2); + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } }); }); }); diff --git a/modules/ticket/back/methods/ticket/specs/updateDiscount.spec.js b/modules/ticket/back/methods/ticket/specs/updateDiscount.spec.js index 406a3f3ee..ae79185e4 100644 --- a/modules/ticket/back/methods/ticket/specs/updateDiscount.spec.js +++ b/modules/ticket/back/methods/ticket/specs/updateDiscount.spec.js @@ -1,156 +1,171 @@ -const app = require('vn-loopback/server/server'); +const models = require('vn-loopback/server/server').models; describe('sale updateDiscount()', () => { const originalSaleId = 8; - let componentId; - let originalSale; - let salesPersonMana; - - beforeAll(async done => { - try { - originalSale = await app.models.Sale.findById(originalSaleId); - let manaDiscount = await app.models.Component.findOne({where: {code: 'buyerDiscount'}}); - componentId = manaDiscount.id; - - let ticket = await app.models.Ticket.findById(originalSale.ticketFk); - let client = await app.models.Client.findById(ticket.clientFk); - salesPersonMana = await app.models.WorkerMana.findById(client.salesPersonFk); - } catch (error) { - console.error(error); - } - - done(); - }); - - afterAll(async done => { - try { - await originalSale.save(); - await app.models.SaleComponent.updateAll({componentFk: componentId, saleFk: originalSaleId}, {value: 0}); - await salesPersonMana.save(); - } catch (error) { - console.error(error); - } - - done(); - }); it('should throw an error if no sales were selected', async() => { - const ctx = { - req: { - accessToken: {userId: 9}, - headers: {origin: 'localhost:5000'}, - __: () => {} - } - }; - let error; - const ticketId = 11; - const sales = []; - const newDiscount = 10; + const tx = await models.Ticket.beginTransaction({}); + let error; try { - await app.models.Ticket.updateDiscount(ctx, ticketId, sales, newDiscount); - } catch (err) { - error = err; + const options = {transaction: tx}; + + const ctx = { + req: { + accessToken: {userId: 9}, + headers: {origin: 'localhost:5000'}, + __: () => {} + } + }; + const ticketId = 11; + const sales = []; + const newDiscount = 10; + + await models.Ticket.updateDiscount(ctx, ticketId, sales, newDiscount, options); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + error = e; } expect(error.message).toEqual('Please select at least one sale'); }); it('should throw an error if no sales belong to different tickets', async() => { - const ctx = { - req: { - accessToken: {userId: 9}, - headers: {origin: 'localhost:5000'}, - __: () => {} - } - }; - let error; - const ticketId = 11; - const sales = [1, 14]; - const newDiscount = 10; + const tx = await models.Ticket.beginTransaction({}); + let error; try { - await app.models.Ticket.updateDiscount(ctx, ticketId, sales, newDiscount); - } catch (err) { - error = err; + const options = {transaction: tx}; + + const ctx = { + req: { + accessToken: {userId: 9}, + headers: {origin: 'localhost:5000'}, + __: () => {} + } + }; + const ticketId = 11; + const sales = [1, 14]; + const newDiscount = 10; + + await models.Ticket.updateDiscount(ctx, ticketId, sales, newDiscount, options); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + error = e; } expect(error.message).toEqual('All sales must belong to the same ticket'); }); it('should throw an error if the ticket is invoiced already', async() => { - const ctx = { - req: { - accessToken: {userId: 9}, - headers: {origin: 'localhost:5000'}, - __: () => {} - } - }; - let error; - const ticketId = 1; - const sales = [1]; - const newDiscount = 100; + const tx = await models.Ticket.beginTransaction({}); + let error; try { - await app.models.Ticket.updateDiscount(ctx, ticketId, sales, newDiscount); - } catch (err) { - error = err; + const options = {transaction: tx}; + + const ctx = { + req: { + accessToken: {userId: 9}, + headers: {origin: 'localhost:5000'}, + __: () => {} + } + }; + const ticketId = 1; + const sales = [1]; + const newDiscount = 100; + + await models.Ticket.updateDiscount(ctx, ticketId, sales, newDiscount, options); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + error = e; } expect(error.message).toEqual(`The sales of this ticket can't be modified`); }); it('should update the discount if the salesPerson has mana', async() => { - const ctx = { - req: { - accessToken: {userId: 18}, - headers: {origin: 'localhost:5000'}, - __: () => {} - } - }; - const ticketId = 11; - const sales = [originalSaleId]; - const newDiscount = 100; - let manaDiscount = await app.models.Component.findOne({where: {code: 'mana'}}); - componentId = manaDiscount.id; + const tx = await models.Ticket.beginTransaction({}); - await app.models.Ticket.updateDiscount(ctx, ticketId, sales, newDiscount); + try { + const options = {transaction: tx}; - let updatedSale = await app.models.Sale.findById(originalSaleId); - let createdSaleComponent = await app.models.SaleComponent.findOne({ - where: { - componentFk: componentId, - saleFk: originalSaleId - } - }); + const ctx = { + req: { + accessToken: {userId: 18}, + headers: {origin: 'localhost:5000'}, + __: () => {} + } + }; + const ticketId = 11; + const sales = [originalSaleId]; + const newDiscount = 100; + const manaDiscount = await models.Component.findOne({where: {code: 'mana'}}, options); + const componentId = manaDiscount.id; - expect(createdSaleComponent.componentFk).toEqual(componentId); - expect(updatedSale.discount).toEqual(100); + await models.Ticket.updateDiscount(ctx, ticketId, sales, newDiscount, options); + + const updatedSale = await models.Sale.findById(originalSaleId, null, options); + const createdSaleComponent = await models.SaleComponent.findOne({ + where: { + componentFk: componentId, + saleFk: originalSaleId + } + }, options); + + expect(createdSaleComponent.componentFk).toEqual(componentId); + expect(updatedSale.discount).toEqual(100); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } }); it('should update the discount and add company discount component if the worker does not have mana', async() => { - const ctx = { - req: { - accessToken: {userId: 9}, - headers: {origin: 'localhost:5000'}, - __: () => {} - } - }; - const ticketId = 11; - const sales = [originalSaleId]; - const newDiscount = 100; + const tx = await models.Ticket.beginTransaction({}); - await app.models.Ticket.updateDiscount(ctx, ticketId, sales, newDiscount); + try { + const options = {transaction: tx}; - let updatedSale = await app.models.Sale.findById(originalSaleId); - let createdSaleComponent = await app.models.SaleComponent.findOne({ - where: { - componentFk: componentId, - saleFk: originalSaleId - } - }); + const ctx = { + req: { + accessToken: {userId: 9}, + headers: {origin: 'localhost:5000'}, + __: () => {} + } + }; + const ticketId = 11; + const sales = [originalSaleId]; + const newDiscount = 100; - expect(createdSaleComponent.componentFk).toEqual(componentId); - expect(updatedSale.discount).toEqual(100); + await models.Ticket.updateDiscount(ctx, ticketId, sales, newDiscount, options); + + const updatedSale = await models.Sale.findById(originalSaleId, null, options); + const manaDiscount = await models.Component.findOne({where: {code: 'buyerDiscount'}}, options); + const componentId = manaDiscount.id; + + const createdSaleComponent = await models.SaleComponent.findOne({ + where: { + componentFk: componentId, + saleFk: originalSaleId + } + }, options); + + expect(createdSaleComponent.componentFk).toEqual(componentId); + expect(updatedSale.discount).toEqual(100); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } }); }); diff --git a/modules/ticket/back/methods/ticket/specs/updateEditableTicket.spec.js b/modules/ticket/back/methods/ticket/specs/updateEditableTicket.spec.js index ffe61e35d..8f36e21cd 100644 --- a/modules/ticket/back/methods/ticket/specs/updateEditableTicket.spec.js +++ b/modules/ticket/back/methods/ticket/specs/updateEditableTicket.spec.js @@ -1,4 +1,4 @@ -const app = require('vn-loopback/server/server'); +const models = require('vn-loopback/server/server').models; const LoopBackContext = require('loopback-context'); const userId = 9; @@ -11,34 +11,44 @@ describe('ticket updateEditableTicket()', () => { const validTicketId = 12; const invalidTicketId = 1; const data = {addressFk: 1}; - const originalData = {addressFk: 123}; - - afterAll(async done => { - await app.models.Ticket.updateEditableTicket(ctx, validTicketId, originalData); - - done(); - }); it('should now throw an error if the ticket is not editable', async() => { + const tx = await models.Ticket.beginTransaction({}); + let error; + try { + const options = {transaction: tx}; - await app.models.Ticket.updateEditableTicket(ctx, invalidTicketId, data).catch(e => { + await models.Ticket.updateEditableTicket(ctx, invalidTicketId, data, options); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); error = e; - }).finally(() => { - expect(error.message).toEqual('This ticket can not be modified'); - }); + } - expect(error).toBeDefined(); + expect(error.message).toEqual('This ticket can not be modified'); }); it('should edit the ticket address', async() => { - spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ - active: activeCtx - }); - await app.models.Ticket.updateEditableTicket(ctx, validTicketId, data); + const tx = await models.Ticket.beginTransaction({}); - let updatedTicket = await app.models.Ticket.findById(validTicketId); + try { + const options = {transaction: tx}; - expect(updatedTicket.addressFk).toEqual(1); + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ + active: activeCtx + }); + await models.Ticket.updateEditableTicket(ctx, validTicketId, data, options); + + const updatedTicket = await models.Ticket.findById(validTicketId, null, options); + + expect(updatedTicket.addressFk).toEqual(1); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } }); }); diff --git a/modules/ticket/back/methods/ticket/specs/uploadFile.spec.js b/modules/ticket/back/methods/ticket/specs/uploadFile.spec.js index 4ad689411..133c13265 100644 --- a/modules/ticket/back/methods/ticket/specs/uploadFile.spec.js +++ b/modules/ticket/back/methods/ticket/specs/uploadFile.spec.js @@ -1,19 +1,26 @@ -const app = require('vn-loopback/server/server'); +const models = require('vn-loopback/server/server').models; describe('Ticket uploadFile()', () => { it(`should return an error for a user without enough privileges`, async() => { - let ticketId = 15; - let currentUserId = 1101; - let ticketTypeId = 14; - let ctx = {req: {accessToken: {userId: currentUserId}}, args: {dmsTypeId: ticketTypeId}}; + const tx = await models.Ticket.beginTransaction({}); let error; - await app.models.Ticket.uploadFile(ctx, ticketId).catch(e => { - error = e; - }).finally(() => { - expect(error.message).toEqual(`You don't have enough privileges`); - }); + try { + const options = {transaction: tx}; - expect(error).toBeDefined(); + const ticketId = 15; + const currentUserId = 1101; + const ticketTypeId = 14; + const ctx = {req: {accessToken: {userId: currentUserId}}, args: {dmsTypeId: ticketTypeId}}; + + await models.Ticket.uploadFile(ctx, ticketId, options); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + error = e; + } + + expect(error.message).toEqual(`You don't have enough privileges`); }); }); diff --git a/modules/ticket/back/methods/ticket/summary.js b/modules/ticket/back/methods/ticket/summary.js index 037aee8b1..848913fe1 100644 --- a/modules/ticket/back/methods/ticket/summary.js +++ b/modules/ticket/back/methods/ticket/summary.js @@ -19,10 +19,17 @@ module.exports = Self => { } }); - Self.summary = async ticketFk => { - let models = Self.app.models; - let summaryObj = await getTicketData(Self, ticketFk); - summaryObj.sales = await models.Ticket.getSales(ticketFk); + Self.summary = async(ticketFk, options) => { + const models = Self.app.models; + const myOptions = {}; + + if (typeof options == 'object') + Object.assign(myOptions, options); + + const summaryObj = await getTicketData(Self, ticketFk, myOptions); + + summaryObj.sales = await models.Ticket.getSales(ticketFk, myOptions); + summaryObj.packagings = await models.TicketPackaging.find({ where: {ticketFk: ticketFk}, include: [{relation: 'packaging', @@ -33,24 +40,25 @@ module.exports = Self => { } } }] - }); - summaryObj.requests = await getRequests(Self, ticketFk); + }, myOptions); + + summaryObj.requests = await getRequests(Self, ticketFk, myOptions); + summaryObj.services = await models.TicketService.find({ where: {ticketFk: ticketFk}, include: [{relation: 'taxClass'}] - }); + }, myOptions); return summaryObj; }; - async function getTicketData(Self, ticketFk) { - let filter = { + async function getTicketData(Self, ticketFk, options) { + const filter = { include: [ {relation: 'warehouse', scope: {fields: ['name']}}, {relation: 'agencyMode', scope: {fields: ['name']}}, {relation: 'zone', scope: {fields: ['name']}}, - { - relation: 'client', + {relation: 'client', scope: { fields: ['salesPersonFk', 'name', 'phone', 'mobile'], include: { @@ -99,11 +107,11 @@ module.exports = Self => { where: {id: ticketFk} }; - return await Self.findOne(filter); + return Self.findOne(filter, options); } - async function getRequests(Self, ticketFk) { - let filter = { + async function getRequests(Self, ticketFk, options) { + const filter = { where: { ticketFk: ticketFk }, @@ -127,6 +135,6 @@ module.exports = Self => { } ] }; - return await Self.app.models.TicketRequest.find(filter); + return Self.app.models.TicketRequest.find(filter, options); } }; diff --git a/modules/ticket/back/methods/ticket/transferSales.js b/modules/ticket/back/methods/ticket/transferSales.js index 541f19615..e196b7c19 100644 --- a/modules/ticket/back/methods/ticket/transferSales.js +++ b/modules/ticket/back/methods/ticket/transferSales.js @@ -5,25 +5,25 @@ module.exports = Self => { description: 'Transfer sales to a new or a given ticket', accepts: [{ arg: 'id', - type: 'Number', + type: 'number', required: true, description: 'Origin ticket id', http: {source: 'path'} }, { arg: 'ticketId', - type: 'Number', + type: 'number', description: 'Destination ticket id', required: false }, { arg: 'sales', - type: ['Object'], + type: ['object'], description: 'The sales to transfer', required: true }], returns: { - type: 'Object', + type: 'object', root: true }, http: { @@ -32,28 +32,35 @@ module.exports = Self => { } }); - Self.transferSales = async(ctx, id, ticketId, sales) => { - let userId = ctx.req.accessToken.userId; + Self.transferSales = async(ctx, id, ticketId, sales, options) => { + const userId = ctx.req.accessToken.userId; const models = Self.app.models; + const myOptions = {}; + let tx; - const isEditable = await models.Ticket.isEditable(ctx, id); - if (!isEditable) - throw new UserError(`The sales of this ticket can't be modified`); + if (typeof options == 'object') + Object.assign(myOptions, options); - if (ticketId) { - const isReceiverEditable = await models.Ticket.isEditable(ctx, ticketId); - if (!isReceiverEditable) - throw new UserError(`The sales of the receiver ticket can't be modified`); + if (!myOptions.transaction) { + tx = await Self.beginTransaction({}); + myOptions.transaction = tx; } - let tx = await Self.beginTransaction({}); - try { - const options = {transaction: tx}; - const originalTicket = await models.Ticket.findById(id, null, options); + const isEditable = await models.Ticket.isEditable(ctx, id, myOptions); + if (!isEditable) + throw new UserError(`The sales of this ticket can't be modified`); + + if (ticketId) { + const isReceiverEditable = await models.Ticket.isEditable(ctx, ticketId, myOptions); + if (!isReceiverEditable) + throw new UserError(`The sales of the receiver ticket can't be modified`); + } + + const originalTicket = await models.Ticket.findById(id, null, myOptions); const originalSales = await models.Sale.find({ where: {ticketFk: id} - }, options); + }, myOptions); if (!ticketId) { const ticket = await models.Ticket.findById(id); @@ -61,7 +68,7 @@ module.exports = Self => { if (!canCreateTicket) throw new UserError(`You can't create a ticket for a inactive client`); - ticketId = await cloneTicket(originalTicket, options); + ticketId = await cloneTicket(originalTicket, myOptions); } const map = new Map(); @@ -80,10 +87,10 @@ module.exports = Self => { if (sale.quantity == originalSale.quantity) { await models.Sale.updateAll({ id: sale.id - }, {ticketFk: ticketId}, options); + }, {ticketFk: ticketId}, myOptions); } else if (sale.quantity != originalSale.quantity) { await transferPartialSale( - ticketId, originalSale, sale, options); + ticketId, originalSale, sale, myOptions); } // Log to original ticket @@ -105,7 +112,7 @@ module.exports = Self => { concept: sale.concept, ticket: ticketId } - }, options); + }, myOptions); // Log to destination ticket await models.TicketLog.create({ @@ -126,22 +133,22 @@ module.exports = Self => { concept: sale.concept, ticket: ticketId } - }, options); + }, myOptions); } - const isTicketEmpty = await models.Ticket.isEmpty(id, options); + const isTicketEmpty = await models.Ticket.isEmpty(id, myOptions); if (isTicketEmpty) { await originalTicket.updateAttributes({ isDeleted: true - }, options); + }, myOptions); } - await tx.commit(); + if (tx) await tx.commit(); return {id: ticketId}; - } catch (error) { - await tx.rollback(); - throw error; + } catch (e) { + if (tx) await tx.rollback(); + throw e; } }; diff --git a/modules/ticket/back/methods/ticket/updateDiscount.js b/modules/ticket/back/methods/ticket/updateDiscount.js index c9424395d..8d5c4a32d 100644 --- a/modules/ticket/back/methods/ticket/updateDiscount.js +++ b/modules/ticket/back/methods/ticket/updateDiscount.js @@ -35,14 +35,21 @@ module.exports = Self => { } }); - Self.updateDiscount = async(ctx, id, salesIds, newDiscount) => { + Self.updateDiscount = async(ctx, id, salesIds, newDiscount, options) => { const $t = ctx.req.__; // $translate const models = Self.app.models; - const tx = await Self.beginTransaction({}); + const myOptions = {}; + let tx; + + if (typeof options == 'object') + Object.assign(myOptions, options); + + if (!myOptions.transaction) { + tx = await Self.beginTransaction({}); + myOptions.transaction = tx; + } try { - const options = {transaction: tx}; - const filter = { where: { id: {inq: salesIds} @@ -61,7 +68,7 @@ module.exports = Self => { } }; - const sales = await models.Sale.find(filter, options); + const sales = await models.Sale.find(filter, myOptions); if (sales.length === 0) throw new UserError('Please select at least one sale'); @@ -71,15 +78,15 @@ module.exports = Self => { throw new UserError('All sales must belong to the same ticket'); const userId = ctx.req.accessToken.userId; - const isLocked = await models.Ticket.isLocked(id); - const roles = await models.Account.getRoles(userId); + const isLocked = await models.Ticket.isLocked(id, myOptions); + const roles = await models.Account.getRoles(userId, myOptions); const hasAllowedRoles = roles.filter(role => role == 'salesPerson' || role == 'claimManager' ); const state = await Self.app.models.TicketState.findOne({ where: {ticketFk: id} - }); + }, myOptions); const alertLevel = state ? state.alertLevel : null; if (isLocked || (!hasAllowedRoles && alertLevel > 0)) @@ -89,11 +96,11 @@ module.exports = Self => { where: { workerFk: userId }, - fields: 'amount'}, options); + fields: 'amount'}, myOptions); const componentCode = usesMana ? 'mana' : 'buyerDiscount'; const discountComponent = await models.Component.findOne({ - where: {code: componentCode}}, options); + where: {code: componentCode}}, myOptions); const componentId = discountComponent.id; const promises = []; @@ -105,9 +112,9 @@ module.exports = Self => { const newComponent = models.SaleComponent.upsert({ saleFk: sale.id, value: value, - componentFk: componentId}, options); + componentFk: componentId}, myOptions); - const updatedSale = sale.updateAttribute('discount', newDiscount, options); + const updatedSale = sale.updateAttribute('discount', newDiscount, myOptions); promises.push(newComponent, updatedSale); changesMade += `\r\n-${sale.itemFk}: ${sale.concept} (${sale.quantity}) ${oldDiscount}% ➔ *${newDiscount}%*`; @@ -116,7 +123,7 @@ module.exports = Self => { await Promise.all(promises); const query = `call vn.manaSpellersRequery(?)`; - await Self.rawSql(query, [userId], options); + await Self.rawSql(query, [userId], myOptions); const ticket = await models.Ticket.findById(id, { include: { @@ -130,7 +137,7 @@ module.exports = Self => { } } } - }, options); + }, myOptions); const salesPerson = ticket.client().salesPersonUser(); if (salesPerson) { @@ -144,10 +151,10 @@ module.exports = Self => { await models.Chat.sendCheckingPresence(ctx, salesPerson.id, message); } - await tx.commit(); - } catch (error) { - await tx.rollback(); - throw error; + if (tx) await tx.commit(); + } catch (e) { + if (tx) await tx.rollback(); + throw e; } }; }; diff --git a/modules/ticket/back/methods/ticket/updateEditableTicket.js b/modules/ticket/back/methods/ticket/updateEditableTicket.js index 39143f8a2..15b6f7cb6 100644 --- a/modules/ticket/back/methods/ticket/updateEditableTicket.js +++ b/modules/ticket/back/methods/ticket/updateEditableTicket.js @@ -15,7 +15,7 @@ module.exports = Self => { { arg: 'data', description: 'Model instance data', - type: 'Object', + type: 'object', required: true, http: {source: 'body'} } @@ -30,12 +30,30 @@ module.exports = Self => { } }); - Self.updateEditableTicket = async(ctx, id, data) => { - let ticketIsEditable = await Self.app.models.Ticket.isEditable(ctx, id); - if (!ticketIsEditable) - throw new UserError('This ticket can not be modified'); + Self.updateEditableTicket = async(ctx, id, data, options) => { + const myOptions = {}; + let tx; - let ticket = await Self.app.models.Ticket.findById(id); - await ticket.updateAttributes(data); + if (typeof options == 'object') + Object.assign(myOptions, options); + + if (!myOptions.transaction) { + tx = await Self.beginTransaction({}); + myOptions.transaction = tx; + } + + try { + const ticketIsEditable = await Self.app.models.Ticket.isEditable(ctx, id, myOptions); + if (!ticketIsEditable) + throw new UserError('This ticket can not be modified'); + + const ticket = await Self.app.models.Ticket.findById(id, null, myOptions); + await ticket.updateAttributes(data, myOptions); + + if (tx) await tx.commit(); + } catch (e) { + if (tx) await tx.rollback(); + throw e; + } }; }; diff --git a/modules/ticket/back/methods/ticket/uploadFile.js b/modules/ticket/back/methods/ticket/uploadFile.js index e5ea465cb..4de9904e1 100644 --- a/modules/ticket/back/methods/ticket/uploadFile.js +++ b/modules/ticket/back/methods/ticket/uploadFile.js @@ -4,40 +4,40 @@ module.exports = Self => { accessType: 'WRITE', accepts: [{ arg: 'id', - type: 'Number', + type: 'number', description: 'The ticket id', http: {source: 'path'} }, { arg: 'warehouseId', - type: 'Number', + type: 'number', description: 'The warehouse id', required: true }, { arg: 'companyId', - type: 'Number', + type: 'number', description: 'The company id', required: true }, { arg: 'dmsTypeId', - type: 'Number', + type: 'number', description: 'The dms type id', required: true }, { arg: 'reference', - type: 'String', + type: 'string', required: true }, { arg: 'description', - type: 'String', + type: 'string', required: true }, { arg: 'hasFile', - type: 'Boolean', + type: 'boolean', description: 'True if has an attached file', required: true }], returns: { - type: 'Object', + type: 'object', root: true }, http: { @@ -46,31 +46,38 @@ module.exports = Self => { } }); - Self.uploadFile = async(ctx, id) => { + Self.uploadFile = async(ctx, id, options) => { const models = Self.app.models; + const myOptions = {}; + let tx; + + if (typeof options == 'object') + Object.assign(myOptions, options); + + if (!myOptions.transaction) { + tx = await Self.beginTransaction({}); + myOptions.transaction = tx; + } + const promises = []; - const tx = await Self.beginTransaction({}); - try { - const options = {transaction: tx}; - - const uploadedFiles = await models.Dms.uploadFile(ctx, options); + const uploadedFiles = await models.Dms.uploadFile(ctx, myOptions); uploadedFiles.forEach(dms => { const newTicketDms = models.TicketDms.create({ ticketFk: id, dmsFk: dms.id - }, options); + }, myOptions); promises.push(newTicketDms); }); const resolvedPromises = await Promise.all(promises); - await tx.commit(); + if (tx) await tx.commit(); return resolvedPromises; - } catch (err) { - await tx.rollback(); - throw err; + } catch (e) { + if (tx) await tx.rollback(); + throw e; } }; }; diff --git a/modules/zone/back/methods/agency/getLanded.js b/modules/zone/back/methods/agency/getLanded.js index 52ddd1f05..a662f59dd 100644 --- a/modules/zone/back/methods/agency/getLanded.js +++ b/modules/zone/back/methods/agency/getLanded.js @@ -35,7 +35,7 @@ module.exports = Self => { }); Self.getLanded = async(ctx, shipped, addressFk, agencyModeFk, warehouseFk, options) => { - let myOptions = {}; + const myOptions = {}; if (typeof options == 'object') Object.assign(myOptions, options); @@ -57,8 +57,7 @@ module.exports = Self => { agencyModeFk, warehouseFk, showExpired - ], - myOptions + ] )); const rsIndex = stmts.push('SELECT * FROM tmp.zoneGetLanded') - 1; From 4545a5c8fae74c759feb17e9704a48d7e8b097ae Mon Sep 17 00:00:00 2001 From: joan Date: Fri, 24 Sep 2021 12:51:20 +0200 Subject: [PATCH 04/47] fix(filter): single search results don't use scopeDates --- .../monitor/front/index/tickets/index.html | 3 +-- modules/monitor/front/index/tickets/index.js | 27 +++++++++++++++---- modules/ticket/front/main/index.html | 3 +-- modules/ticket/front/main/index.js | 26 +++++++++++------- 4 files changed, 41 insertions(+), 18 deletions(-) diff --git a/modules/monitor/front/index/tickets/index.html b/modules/monitor/front/index/tickets/index.html index 82adf2765..cbbea81a8 100644 --- a/modules/monitor/front/index/tickets/index.html +++ b/modules/monitor/front/index/tickets/index.html @@ -1,6 +1,5 @@ - diff --git a/modules/monitor/front/index/tickets/index.js b/modules/monitor/front/index/tickets/index.js index d8832d1b5..23febd6c6 100644 --- a/modules/monitor/front/index/tickets/index.js +++ b/modules/monitor/front/index/tickets/index.js @@ -6,13 +6,30 @@ export default class Controller extends Section { constructor($element, $) { super($element, $); - this.filterParams = this.fetchParams({ - scopeDays: 1 - }); + this.filterParams = this.fetchParams(); } - fetchParams($params) { - if (!Object.entries($params).length) + $onInit() { + if (!this.$params.q) { + this.$.$applyAsync( + () => this.$.model.applyFilter(null, this.filterParams)); + } + } + + fetchParams($params = {}) { + const excludedParams = [ + 'search', + 'clientFk', + 'orderFk', + 'refFk', + 'scopeDays' + ]; + + const hasExcludedParams = excludedParams.some(param => { + return $params && $params[param]; + }); + const hasParams = Object.entries($params).length; + if (!hasParams || !hasExcludedParams) $params.scopeDays = 1; if (typeof $params.scopeDays === 'number') { diff --git a/modules/ticket/front/main/index.html b/modules/ticket/front/main/index.html index 590d33887..82b5e58cd 100644 --- a/modules/ticket/front/main/index.html +++ b/modules/ticket/front/main/index.html @@ -10,8 +10,7 @@ panel="vn-ticket-search-panel" info="Search ticket by id or alias" model="model" - fetch-params="$ctrl.fetchParams($params)" - suggested-filter="$ctrl.filterParams"> + fetch-params="$ctrl.fetchParams($params)"> diff --git a/modules/ticket/front/main/index.js b/modules/ticket/front/main/index.js index 78334ba97..b67b6512e 100644 --- a/modules/ticket/front/main/index.js +++ b/modules/ticket/front/main/index.js @@ -2,16 +2,22 @@ import ngModule from '../module'; import ModuleMain from 'salix/components/module-main'; export default class Ticket extends ModuleMain { - constructor() { - super(); - - this.filterParams = { - scopeDays: 1 - }; - } - fetchParams($params) { - if (!Object.entries($params).length) + const excludedParams = [ + 'from', + 'to', + 'search', + 'clientFk', + 'orderFk', + 'refFk', + 'scopeDays' + ]; + + const hasExcludedParams = excludedParams.some(param => { + return $params && $params[param]; + }); + const hasParams = Object.entries($params).length; + if (!hasParams || !hasExcludedParams) $params.scopeDays = 1; if (typeof $params.scopeDays === 'number') { @@ -25,6 +31,8 @@ export default class Ticket extends ModuleMain { Object.assign($params, {from, to}); } + this.filterParams = $params; + return $params; } } From ee0e1e122b2725154efa42b2afd16f501a5b421e Mon Sep 17 00:00:00 2001 From: joan Date: Fri, 24 Sep 2021 13:02:20 +0200 Subject: [PATCH 05/47] Removed crudModel default params --- modules/ticket/front/main/index.html | 1 - modules/ticket/front/main/index.js | 2 -- 2 files changed, 3 deletions(-) diff --git a/modules/ticket/front/main/index.html b/modules/ticket/front/main/index.html index d42bcaf75..82b5e58cd 100644 --- a/modules/ticket/front/main/index.html +++ b/modules/ticket/front/main/index.html @@ -1,6 +1,5 @@ diff --git a/modules/ticket/front/main/index.js b/modules/ticket/front/main/index.js index b67b6512e..3c6318b5d 100644 --- a/modules/ticket/front/main/index.js +++ b/modules/ticket/front/main/index.js @@ -31,8 +31,6 @@ export default class Ticket extends ModuleMain { Object.assign($params, {from, to}); } - this.filterParams = $params; - return $params; } } From 6cf1737c0d706443265b93399b525fb54aff58f0 Mon Sep 17 00:00:00 2001 From: carlosjr Date: Tue, 28 Sep 2021 11:59:04 +0200 Subject: [PATCH 06/47] refactor(thermograph): temperature column now displays the correct data --- modules/travel/front/thermograph/index/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/travel/front/thermograph/index/index.html b/modules/travel/front/thermograph/index/index.html index 9dbb7dcbf..4d711613d 100644 --- a/modules/travel/front/thermograph/index/index.html +++ b/modules/travel/front/thermograph/index/index.html @@ -24,7 +24,7 @@ {{::thermograph.thermographFk}} - {{::thermograph.temperature}} + {{::thermograph.temperatureFk}} {{::thermograph.result}} {{::thermograph.warehouse.name}} {{::thermograph.created | date: 'dd/MM/yyyy'}} From e690febc7f84a4410cb8746dbb65c39f0f8c606f Mon Sep 17 00:00:00 2001 From: carlosjr Date: Wed, 29 Sep 2021 08:26:10 +0200 Subject: [PATCH 07/47] refactor(updateAll): usage of documented methods as update alias is not documented in loopback --- modules/account/back/models/ldap-config.js | 4 ++-- modules/item/back/methods/item/updateTaxes.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/account/back/models/ldap-config.js b/modules/account/back/models/ldap-config.js index 819659066..f61aa2db5 100644 --- a/modules/account/back/models/ldap-config.js +++ b/modules/account/back/models/ldap-config.js @@ -77,8 +77,8 @@ module.exports = Self => { .toString('base64'); let hash = crypto.createHash('sha1'); - hash.update(password); - hash.update(salt, 'binary'); + hash.updateAll(password); + hash.updateAll(salt, 'binary'); let digest = hash.digest('binary'); let ssha = Buffer diff --git a/modules/item/back/methods/item/updateTaxes.js b/modules/item/back/methods/item/updateTaxes.js index 70a82757a..262f4dcb1 100644 --- a/modules/item/back/methods/item/updateTaxes.js +++ b/modules/item/back/methods/item/updateTaxes.js @@ -40,7 +40,7 @@ module.exports = Self => { if (!tax.taxClassFk) throw new UserError('Tax class cannot be blank'); - promises.push(Self.app.models.ItemTaxCountry.update( + promises.push(Self.app.models.ItemTaxCountry.updateAll( {id: tax.id}, {taxClassFk: tax.taxClassFk} ), myOptions); From 392c4dcba3b1907b2ef49ee01bb3d17e8ca45811 Mon Sep 17 00:00:00 2001 From: carlosjr Date: Wed, 29 Sep 2021 08:27:18 +0200 Subject: [PATCH 08/47] refactor(sale): ticket.sale endpoints now use transactions --- .../ticket/back/methods/sale/deleteSales.js | 91 ++++++----- .../methods/sale/getClaimableFromTicket.js | 42 ++--- .../back/methods/sale/recalculatePrice.js | 37 +++-- modules/ticket/back/methods/sale/reserve.js | 105 +++++++------ .../back/methods/sale/specs/canEdit.spec.js | 65 ++++++-- .../methods/sale/specs/deleteSales.spec.js | 83 +++++----- .../sale/specs/getClaimableFromTicket.spec.js | 19 ++- .../sale/specs/recalculatePrice.spec.js | 43 ++++-- .../back/methods/sale/specs/reserve.spec.js | 73 ++++----- .../methods/sale/specs/updateConcept.spec.js | 49 +++--- .../methods/sale/specs/updatePrice.spec.js | 146 +++++++++--------- .../methods/sale/specs/updateQuantity.spec.js | 59 ++++--- .../ticket/back/methods/sale/updateConcept.js | 32 +++- .../ticket/back/methods/sale/updatePrice.js | 41 +++-- .../back/methods/sale/updateQuantity.js | 99 +++++++----- 15 files changed, 589 insertions(+), 395 deletions(-) diff --git a/modules/ticket/back/methods/sale/deleteSales.js b/modules/ticket/back/methods/sale/deleteSales.js index a604da858..c1359569d 100644 --- a/modules/ticket/back/methods/sale/deleteSales.js +++ b/modules/ticket/back/methods/sale/deleteSales.js @@ -26,54 +26,73 @@ module.exports = Self => { } }); - Self.deleteSales = async(ctx, sales, ticketId) => { + Self.deleteSales = async(ctx, sales, ticketId, options) => { const $t = ctx.req.__; // $translate const models = Self.app.models; + const myOptions = {}; + let tx; - const canEditSales = await models.Sale.canEdit(ctx, sales); + if (typeof options == 'object') + Object.assign(myOptions, options); - const ticket = await models.Ticket.findById(ticketId, { - include: { - relation: 'client', - scope: { - include: { - relation: 'salesPersonUser', - scope: { - fields: ['id', 'name'] + if (!myOptions.transaction) { + tx = await Self.beginTransaction({}); + myOptions.transaction = tx; + } + + try { + const canEditSales = await models.Sale.canEdit(ctx, sales, myOptions); + + const ticket = await models.Ticket.findById(ticketId, { + include: { + relation: 'client', + scope: { + include: { + relation: 'salesPersonUser', + scope: { + fields: ['id', 'name'] + } } } } + }, myOptions); + + const isTicketEditable = await models.Ticket.isEditable(ctx, ticketId, myOptions); + if (!isTicketEditable) + throw new UserError(`The sales of this ticket can't be modified`); + + if (!canEditSales) + throw new UserError(`Sale(s) blocked, please contact production`); + + const promises = []; + let deletions = ''; + for (let sale of sales) { + const deletedSale = models.Sale.destroyById(sale.id, myOptions); + deletions += `\r\n-${sale.itemFk}: ${sale.concept} (${sale.quantity})`; + + promises.push(deletedSale); } - }); - const isTicketEditable = await models.Ticket.isEditable(ctx, ticketId); - if (!isTicketEditable) - throw new UserError(`The sales of this ticket can't be modified`); + const salesPerson = ticket.client().salesPersonUser(); + if (salesPerson) { + const origin = ctx.req.headers.origin; - if (!canEditSales) - throw new UserError(`Sale(s) blocked, please contact production`); + const message = $t('Deleted sales from ticket', { + ticketId: ticketId, + ticketUrl: `${origin}/#!/ticket/${ticketId}/sale`, + deletions: deletions + }); + await models.Chat.sendCheckingPresence(ctx, salesPerson.id, message, myOptions); + } - const promises = []; - let deletions = ''; - for (let sale of sales) { - const deletedSale = models.Sale.destroyById(sale.id); - deletions += `\r\n-${sale.itemFk}: ${sale.concept} (${sale.quantity})`; + const deletedSales = await Promise.all(promises); - promises.push(deletedSale); + if (tx) await tx.commit(); + + return deletedSales; + } catch (e) { + if (tx) await tx.rollback(); + throw e; } - - const salesPerson = ticket.client().salesPersonUser(); - if (salesPerson) { - const origin = ctx.req.headers.origin; - - const message = $t('Deleted sales from ticket', { - ticketId: ticketId, - ticketUrl: `${origin}/#!/ticket/${ticketId}/sale`, - deletions: deletions - }); - await models.Chat.sendCheckingPresence(ctx, salesPerson.id, message); - } - - return Promise.all(promises); }; }; diff --git a/modules/ticket/back/methods/sale/getClaimableFromTicket.js b/modules/ticket/back/methods/sale/getClaimableFromTicket.js index adfb91710..4e0549a4d 100644 --- a/modules/ticket/back/methods/sale/getClaimableFromTicket.js +++ b/modules/ticket/back/methods/sale/getClaimableFromTicket.js @@ -18,26 +18,32 @@ module.exports = Self => { } }); - Self.getClaimableFromTicket = async ticketFk => { - let query = `SELECT - s.id AS saleFk, - t.id AS ticketFk, - t.landed, - s.concept, - s.itemFk, - s.quantity, - s.price, - s.discount, - t.nickname - FROM vn.ticket t - INNER JOIN vn.sale s ON s.ticketFk = t.id - LEFT JOIN vn.claimBeginning cb ON cb.saleFk = s.id + Self.getClaimableFromTicket = async(ticketFk, options) => { + const myOptions = {}; - WHERE (t.landed) >= TIMESTAMPADD(DAY, -7, CURDATE()) - AND t.id = ? AND cb.id IS NULL - ORDER BY t.landed DESC, t.id DESC`; + if (typeof options == 'object') + Object.assign(myOptions, options); - let claimableSales = await Self.rawSql(query, [ticketFk]); + const query = ` + SELECT + s.id AS saleFk, + t.id AS ticketFk, + t.landed, + s.concept, + s.itemFk, + s.quantity, + s.price, + s.discount, + t.nickname + FROM vn.ticket t + INNER JOIN vn.sale s ON s.ticketFk = t.id + LEFT JOIN vn.claimBeginning cb ON cb.saleFk = s.id + + WHERE (t.landed) >= TIMESTAMPADD(DAY, -7, CURDATE()) + AND t.id = ? AND cb.id IS NULL + ORDER BY t.landed DESC, t.id DESC`; + + const claimableSales = await Self.rawSql(query, [ticketFk], myOptions); return claimableSales; }; diff --git a/modules/ticket/back/methods/sale/recalculatePrice.js b/modules/ticket/back/methods/sale/recalculatePrice.js index 9e902d393..3ffc23c3b 100644 --- a/modules/ticket/back/methods/sale/recalculatePrice.js +++ b/modules/ticket/back/methods/sale/recalculatePrice.js @@ -20,20 +20,39 @@ module.exports = Self => { } }); - Self.recalculatePrice = async(ctx, id) => { + Self.recalculatePrice = async(ctx, id, options) => { const models = Self.app.models; + const myOptions = {}; + let tx; - const sale = await Self.findById(id); - const isEditable = await models.Ticket.isEditable(ctx, sale.ticketFk); + if (typeof options == 'object') + Object.assign(myOptions, options); - if (!isEditable) - throw new UserError(`The sales of this ticket can't be modified`); + if (!myOptions.transaction) { + tx = await Self.beginTransaction({}); + myOptions.transaction = tx; + } - const canEditSale = await models.Sale.canEdit(ctx, [id]); + try { + const sale = await Self.findById(id, null, myOptions); + const isEditable = await models.Ticket.isEditable(ctx, sale.ticketFk, myOptions); - if (!canEditSale) - throw new UserError(`Sale(s) blocked, please contact production`); + if (!isEditable) + throw new UserError(`The sales of this ticket can't be modified`); - return Self.rawSql('CALL vn.sale_calculateComponent(?, null)', [id]); + const canEditSale = await models.Sale.canEdit(ctx, [id], myOptions); + + if (!canEditSale) + throw new UserError(`Sale(s) blocked, please contact production`); + + const recalculation = await Self.rawSql('CALL vn.sale_calculateComponent(?, null)', [id], myOptions); + + if (tx) await tx.commit(); + + return recalculation; + } catch (e) { + if (tx) await tx.rollback(); + throw e; + } }; }; diff --git a/modules/ticket/back/methods/sale/reserve.js b/modules/ticket/back/methods/sale/reserve.js index 639827fa7..b368f6fc3 100644 --- a/modules/ticket/back/methods/sale/reserve.js +++ b/modules/ticket/back/methods/sale/reserve.js @@ -34,63 +34,80 @@ module.exports = Self => { } }); - Self.reserve = async(ctx, ticketId, sales, reserved) => { + Self.reserve = async(ctx, ticketId, sales, reserved, options) => { const $t = ctx.req.__; // $translate const models = Self.app.models; + const myOptions = {}; + let tx; - const isTicketEditable = await models.Ticket.isEditable(ctx, ticketId); - if (!isTicketEditable) - throw new UserError(`The sales of this ticket can't be modified`); + if (typeof options == 'object') + Object.assign(myOptions, options); - const canEditSale = await models.Sale.canEdit(ctx, sales); - - if (!canEditSale) - throw new UserError(`Sale(s) blocked, please contact production`); - - let changesMade = ''; - const promises = []; - - for (let sale of sales) { - if (sale.reserved != reserved) { - const oldState = sale.reserved ? 'reserved' : 'regular'; - const newState = reserved ? 'reserved' : 'regular'; - - const reservedSale = models.Sale.update({id: sale.id}, {reserved: reserved}); - - promises.push(reservedSale); - - changesMade += `\r\n-${sale.itemFk}: ${sale.concept} (${sale.quantity}) ${$t('State')}: ${$t(oldState)} ➔ *${$t(newState)}*`; - } + if (!myOptions.transaction) { + tx = await Self.beginTransaction({}); + myOptions.transaction = tx; } - const result = await Promise.all(promises); + try { + const isTicketEditable = await models.Ticket.isEditable(ctx, ticketId, myOptions); + if (!isTicketEditable) + throw new UserError(`The sales of this ticket can't be modified`); - const ticket = await models.Ticket.findById(ticketId, { - include: { - relation: 'client', - scope: { - include: { - relation: 'salesPersonUser', - scope: { - fields: ['id', 'name'] + const canEditSale = await models.Sale.canEdit(ctx, sales, myOptions); + + if (!canEditSale) + throw new UserError(`Sale(s) blocked, please contact production`); + + let changesMade = ''; + const promises = []; + + for (let sale of sales) { + if (sale.reserved != reserved) { + const oldState = sale.reserved ? 'reserved' : 'regular'; + const newState = reserved ? 'reserved' : 'regular'; + + const reservedSale = models.Sale.updateAll({id: sale.id}, {reserved: reserved}, myOptions); + + promises.push(reservedSale); + + changesMade += `\r\n-${sale.itemFk}: ${sale.concept} (${sale.quantity}) ${$t('State')}: ${$t(oldState)} ➔ *${$t(newState)}*`; + } + } + + const result = await Promise.all(promises); + + const ticket = await models.Ticket.findById(ticketId, { + include: { + relation: 'client', + scope: { + include: { + relation: 'salesPersonUser', + scope: { + fields: ['id', 'name'] + } } } } + }, myOptions); + + const salesPerson = ticket.client().salesPersonUser(); + if (salesPerson) { + const origin = ctx.req.headers.origin; + + const message = $t('Changed sale reserved state', { + ticketId: ticketId, + ticketUrl: `${origin}/#!/ticket/${ticketId}/sale`, + changes: changesMade + }); + await models.Chat.sendCheckingPresence(ctx, salesPerson.id, message, myOptions); } - }); - const salesPerson = ticket.client().salesPersonUser(); - if (salesPerson) { - const origin = ctx.req.headers.origin; + if (tx) await tx.commit(); - const message = $t('Changed sale reserved state', { - ticketId: ticketId, - ticketUrl: `${origin}/#!/ticket/${ticketId}/sale`, - changes: changesMade - }); - await models.Chat.sendCheckingPresence(ctx, salesPerson.id, message); + return result; + } catch (e) { + if (tx) await tx.rollback(); + throw e; } - - return result; }; }; diff --git a/modules/ticket/back/methods/sale/specs/canEdit.spec.js b/modules/ticket/back/methods/sale/specs/canEdit.spec.js index fb1e1ab87..4f6747257 100644 --- a/modules/ticket/back/methods/sale/specs/canEdit.spec.js +++ b/modules/ticket/back/methods/sale/specs/canEdit.spec.js @@ -1,36 +1,69 @@ -const app = require('vn-loopback/server/server'); +const models = require('vn-loopback/server/server').models; describe('sale canEdit()', () => { it('should return true if the role is production regardless of the saleTrackings', async() => { - const productionUserID = 49; - let ctx = {req: {accessToken: {userId: productionUserID}}}; + const tx = await models.Sale.beginTransaction({}); - const sales = [{id: 3}]; + try { + const options = {transaction: tx}; - const result = await app.models.Sale.canEdit(ctx, sales); + const productionUserID = 49; + const ctx = {req: {accessToken: {userId: productionUserID}}}; - expect(result).toEqual(true); + const sales = [{id: 3}]; + + const result = await models.Sale.canEdit(ctx, sales, options); + + expect(result).toEqual(true); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } }); it('should return true if the role is not production and none of the sales has saleTracking', async() => { - const salesPersonUserID = 18; - let ctx = {req: {accessToken: {userId: salesPersonUserID}}}; + const tx = await models.Sale.beginTransaction({}); - const sales = [{id: 10}]; + try { + const options = {transaction: tx}; - const result = await app.models.Sale.canEdit(ctx, sales); + const salesPersonUserID = 18; + const ctx = {req: {accessToken: {userId: salesPersonUserID}}}; - expect(result).toEqual(true); + const sales = [{id: 10}]; + + const result = await models.Sale.canEdit(ctx, sales, options); + + expect(result).toEqual(true); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } }); it('should return false if any of the sales has a saleTracking record', async() => { - const salesPersonUserID = 18; - let ctx = {req: {accessToken: {userId: salesPersonUserID}}}; + const tx = await models.Sale.beginTransaction({}); - const sales = [{id: 3}]; + try { + const options = {transaction: tx}; - const result = await app.models.Sale.canEdit(ctx, sales); + const salesPersonUserID = 18; + const ctx = {req: {accessToken: {userId: salesPersonUserID}}}; - expect(result).toEqual(false); + const sales = [{id: 3}]; + + const result = await models.Sale.canEdit(ctx, sales, options); + + expect(result).toEqual(false); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } }); }); diff --git a/modules/ticket/back/methods/sale/specs/deleteSales.spec.js b/modules/ticket/back/methods/sale/specs/deleteSales.spec.js index aabc38375..82cf916b3 100644 --- a/modules/ticket/back/methods/sale/specs/deleteSales.spec.js +++ b/modules/ticket/back/methods/sale/specs/deleteSales.spec.js @@ -1,38 +1,29 @@ -const app = require('vn-loopback/server/server'); +const models = require('vn-loopback/server/server').models; describe('sale deleteSales()', () => { - let sale; - let newSale; - - beforeAll(async done => { - try { - sale = await app.models.Sale.findOne({where: {id: 9}}); - sale.id = null; - newSale = await app.models.Sale.create(sale); - } catch (error) { - console.error(error); - } - - done(); - }); - it('should throw an error if the ticket of the given sales is not editable', async() => { - let ctx = { - req: { - accessToken: {userId: 9}, - headers: {origin: 'localhost:5000'}, - __: () => {} - } - }; + const tx = await models.Sale.beginTransaction({}); let error; - - const sales = [{id: 1, instance: 0}, {id: 2, instance: 1}]; - const ticketId = 2; - try { - await app.models.Sale.deleteSales(ctx, sales, ticketId); + const options = {transaction: tx}; + + const ctx = { + req: { + accessToken: {userId: 9}, + headers: {origin: 'localhost:5000'}, + __: () => {} + } + }; + + const sales = [{id: 1, instance: 0}, {id: 2, instance: 1}]; + const ticketId = 2; + + await models.Sale.deleteSales(ctx, sales, ticketId, options); + + await tx.rollback(); } catch (e) { + await tx.rollback(); error = e; } @@ -40,19 +31,33 @@ describe('sale deleteSales()', () => { }); it('should delete the sale', async() => { - let ctx = { - req: { - accessToken: {userId: 9}, - headers: {origin: 'localhost:5000'}, - __: () => {} - } - }; + const tx = await models.Sale.beginTransaction({}); - const sales = [{id: newSale.id, instance: 0}]; - const ticketId = 16; + try { + const options = {transaction: tx}; - let res = await app.models.Sale.deleteSales(ctx, sales, ticketId); + const ctx = { + req: { + accessToken: {userId: 9}, + headers: {origin: 'localhost:5000'}, + __: () => {} + } + }; + const sale = await models.Sale.findOne({where: {id: 9}}, options); + sale.id = null; + const newSale = await models.Sale.create(sale, options); - expect(res).toEqual([{count: 1}]); + const sales = [{id: newSale.id, instance: 0}]; + const ticketId = 16; + + const deletions = await models.Sale.deleteSales(ctx, sales, ticketId, options); + + expect(deletions).toEqual([{count: 1}]); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } }); }); diff --git a/modules/ticket/back/methods/sale/specs/getClaimableFromTicket.spec.js b/modules/ticket/back/methods/sale/specs/getClaimableFromTicket.spec.js index b12c22084..d7eda9965 100644 --- a/modules/ticket/back/methods/sale/specs/getClaimableFromTicket.spec.js +++ b/modules/ticket/back/methods/sale/specs/getClaimableFromTicket.spec.js @@ -1,10 +1,21 @@ -const app = require('vn-loopback/server/server'); +const models = require('vn-loopback/server/server').models; describe('sale getClaimableFromTicket()', () => { it('should return the claimable sales of a given ticket', async() => { - let claimableFromTicket = await app.models.Sale.getClaimableFromTicket(16); + const tx = await models.Sale.beginTransaction({}); - expect(claimableFromTicket[0].concept).toBe('Ranged weapon longbow 2m'); - expect(claimableFromTicket.length).toBe(3); + try { + const options = {transaction: tx}; + + const claimableFromTicket = await models.Sale.getClaimableFromTicket(16, options); + + expect(claimableFromTicket[0].concept).toBe('Ranged weapon longbow 2m'); + expect(claimableFromTicket.length).toBe(3); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } }); }); diff --git a/modules/ticket/back/methods/sale/specs/recalculatePrice.spec.js b/modules/ticket/back/methods/sale/specs/recalculatePrice.spec.js index 23d7d721b..4f6579d32 100644 --- a/modules/ticket/back/methods/sale/specs/recalculatePrice.spec.js +++ b/modules/ticket/back/methods/sale/specs/recalculatePrice.spec.js @@ -1,24 +1,43 @@ -const app = require('vn-loopback/server/server'); +const models = require('vn-loopback/server/server').models; describe('sale recalculatePrice()', () => { const saleId = 7; it('should update the sale price', async() => { - const ctx = {req: {accessToken: {userId: 9}}}; - const response = await app.models.Sale.recalculatePrice(ctx, saleId); + const tx = await models.Sale.beginTransaction({}); - expect(response.affectedRows).toBeDefined(); + try { + const options = {transaction: tx}; + + const ctx = {req: {accessToken: {userId: 9}}}; + const response = await models.Sale.recalculatePrice(ctx, saleId, options); + + expect(response.affectedRows).toBeDefined(); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } }); it('should throw an error if the ticket is not editable', async() => { - const ctx = {req: {accessToken: {userId: 9}}}; - const immutableSaleId = 1; - await app.models.Sale.recalculatePrice(ctx, immutableSaleId) - .catch(response => { - expect(response).toEqual(new Error(`The sales of this ticket can't be modified`)); - error = response; - }); + const tx = await models.Sale.beginTransaction({}); - expect(error).toBeDefined(); + let error; + try { + const options = {transaction: tx}; + + const ctx = {req: {accessToken: {userId: 9}}}; + const immutableSaleId = 1; + await models.Sale.recalculatePrice(ctx, immutableSaleId, options); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + error = e; + } + + expect(error).toEqual(new Error(`The sales of this ticket can't be modified`)); }); }); diff --git a/modules/ticket/back/methods/sale/specs/reserve.spec.js b/modules/ticket/back/methods/sale/specs/reserve.spec.js index 3752a2b6b..c4b3b4e5d 100644 --- a/modules/ticket/back/methods/sale/specs/reserve.spec.js +++ b/modules/ticket/back/methods/sale/specs/reserve.spec.js @@ -1,4 +1,4 @@ -const app = require('vn-loopback/server/server'); +const models = require('vn-loopback/server/server').models; describe('sale reserve()', () => { const ctx = { @@ -9,51 +9,54 @@ describe('sale reserve()', () => { } }; - afterAll(async done => { - let ctx = {req: {accessToken: {userId: 9}}}; - let params = { - sales: [ - {id: 7}, - {id: 8}], - ticketFk: 11, - reserved: false - }; - - await app.models.Sale.reserve(ctx, params); - - done(); - }); - it('should throw an error if the ticket can not be modified', async() => { + const tx = await models.Sale.beginTransaction({}); + let error; - const ticketId = 2; - const sales = [{id: 5}]; - const reserved = false; + try { + const options = {transaction: tx}; - await app.models.Sale.reserve(ctx, ticketId, sales, reserved) - .catch(response => { - expect(response).toEqual(new Error(`The sales of this ticket can't be modified`)); - error = response; - }); + const ticketId = 2; + const sales = [{id: 5}]; + const reserved = false; - expect(error).toBeDefined(); + await models.Sale.reserve(ctx, ticketId, sales, reserved, options); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + error = e; + } + + expect(error).toEqual(new Error(`The sales of this ticket can't be modified`)); }); it('should update the given sales of a ticket to reserved', async() => { - originalTicketSales = await app.models.Ticket.getSales(11); + const tx = await models.Sale.beginTransaction({}); - expect(originalTicketSales[0].reserved).toEqual(false); - expect(originalTicketSales[1].reserved).toEqual(false); + try { + const options = {transaction: tx}; - const ticketId = 11; - const sales = [{id: 7}, {id: 8}]; - const reserved = true; + originalTicketSales = await models.Ticket.getSales(11, options); - await app.models.Sale.reserve(ctx, ticketId, sales, reserved); + expect(originalTicketSales[0].reserved).toEqual(false); + expect(originalTicketSales[1].reserved).toEqual(false); - const reservedTicketSales = await app.models.Ticket.getSales(ticketId); + const ticketId = 11; + const sales = [{id: 7}, {id: 8}]; + const reserved = true; - expect(reservedTicketSales[0].reserved).toEqual(true); - expect(reservedTicketSales[1].reserved).toEqual(true); + await models.Sale.reserve(ctx, ticketId, sales, reserved, options); + + const reservedTicketSales = await models.Ticket.getSales(ticketId, options); + + expect(reservedTicketSales[0].reserved).toEqual(true); + expect(reservedTicketSales[1].reserved).toEqual(true); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } }); }); diff --git a/modules/ticket/back/methods/sale/specs/updateConcept.spec.js b/modules/ticket/back/methods/sale/specs/updateConcept.spec.js index 428bac390..01f610d36 100644 --- a/modules/ticket/back/methods/sale/specs/updateConcept.spec.js +++ b/modules/ticket/back/methods/sale/specs/updateConcept.spec.js @@ -1,40 +1,45 @@ -const app = require('vn-loopback/server/server'); +const models = require('vn-loopback/server/server').models; describe('sale updateConcept()', () => { const ctx = {req: {accessToken: {userId: 9}}}; const saleId = 1; - let originalSale; - - beforeAll(async done => { - originalSale = await app.models.Sale.findById(saleId); - - done(); - }); - - afterAll(async done => { - await originalSale.save(); - - done(); - }); it('should throw if ID was undefined', async() => { - let err; - const newConcept = 'I am he new concept'; + const tx = await models.Sale.beginTransaction({}); + let error; try { - await app.models.Sale.updateConcept(ctx, undefined, newConcept); + const options = {transaction: tx}; + + const newConcept = 'not going to heppen'; + + await models.Sale.updateConcept(ctx, undefined, newConcept, options); + + await tx.rollback(); } catch (e) { - err = e; + await tx.rollback(); + error = e; } - expect(err).toBeDefined(); + expect(error).toBeDefined(); }); it('should update the sale concept', async() => { - const newConcept = 'I am the new concept'; + const tx = await models.Sale.beginTransaction({}); - let response = await app.models.Sale.updateConcept(ctx, saleId, newConcept); + try { + const options = {transaction: tx}; - expect(response.concept).toEqual(newConcept); + const newConcept = 'I am the new concept'; + + let response = await models.Sale.updateConcept(ctx, saleId, newConcept, options); + + expect(response.concept).toEqual(newConcept); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } }); }); diff --git a/modules/ticket/back/methods/sale/specs/updatePrice.spec.js b/modules/ticket/back/methods/sale/specs/updatePrice.spec.js index ea8a65c27..e76511421 100644 --- a/modules/ticket/back/methods/sale/specs/updatePrice.spec.js +++ b/modules/ticket/back/methods/sale/specs/updatePrice.spec.js @@ -1,104 +1,100 @@ -const app = require('vn-loopback/server/server'); +const models = require('vn-loopback/server/server').models; describe('sale updatePrice()', () => { - let originalSale; - let originalSalesPersonMana; - let createdSaleComponent; - let saleId = 7; - let manaComponentId; - - beforeAll(async done => { - let component = await app.models.Component.findOne({where: {code: 'mana'}}); - manaComponentId = component.id; - originalSale = await app.models.Sale.findById(saleId); - originalSalesPersonMana = await app.models.WorkerMana.findById(18); - - done(); - }); + const ctx = { + req: { + accessToken: {userId: 18}, + headers: {origin: 'localhost:5000'}, + __: () => {} + } + }; + const saleId = 7; it('should throw an error if the ticket is not editable', async() => { - const ctx = { - req: { - accessToken: {userId: 18}, - headers: {origin: 'localhost:5000'}, - __: () => {} - } - }; - let immutableSaleId = 1; - let price = 5; + const tx = await models.Sale.beginTransaction({}); - await app.models.Sale.updatePrice(ctx, immutableSaleId, price) - .catch(response => { - expect(response).toEqual(new Error(`The sales of this ticket can't be modified`)); - error = response; - }); + try { + const options = {transaction: tx}; - expect(error).toBeDefined(); + const immutableSaleId = 1; + const price = 5; + + await models.Sale.updatePrice(ctx, immutableSaleId, price, options); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + error = e; + } + + expect(error).toEqual(new Error(`The sales of this ticket can't be modified`)); }); it('should return 0 if the price is an empty string', async() => { - const ctx = { - req: { - accessToken: {userId: 18}, - headers: {origin: 'localhost:5000'}, - __: () => {} - } - }; + const tx = await models.Sale.beginTransaction({}); - let price = ''; + try { + const options = {transaction: tx}; - await app.models.Sale.updatePrice(ctx, saleId, price); - let updatedSale = await app.models.Sale.findById(saleId); + const price = ''; - expect(updatedSale.price).toEqual(0); + await models.Sale.updatePrice(ctx, saleId, price, options); + const updatedSale = await models.Sale.findById(saleId, null, options); - // restores - await originalSale.updateAttributes(originalSale); - await app.models.SaleComponent.updateAll({componentFk: manaComponentId, saleFk: saleId}, {value: 0}); - await originalSalesPersonMana.updateAttributes(originalSalesPersonMana); + expect(updatedSale.price).toEqual(0); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } }); it('should now set price as a number in a string', async() => { - const ctx = { - req: { - accessToken: {userId: 18}, - headers: {origin: 'localhost:5000'}, - __: () => {} - } - }; + const tx = await models.Sale.beginTransaction({}); - let price = '8'; + try { + const options = {transaction: tx}; - await app.models.Sale.updatePrice(ctx, saleId, price); - let updatedSale = await app.models.Sale.findById(saleId); + const price = '8'; - expect(updatedSale.price).toEqual(8); + await models.Sale.updatePrice(ctx, saleId, price, options); + const updatedSale = await models.Sale.findById(saleId, null, options); - // restores - await originalSale.updateAttributes(originalSale); - await app.models.SaleComponent.updateAll({componentFk: manaComponentId, saleFk: saleId}, {value: 0}); - await originalSalesPersonMana.updateAttributes(originalSalesPersonMana); + expect(updatedSale.price).toEqual(8); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } }); - // #2736 sale updatePrice() returns inconsistent values - xit('should set price as a decimal number and check the sale has the mana component changing the salesPersonMana', async() => { - let ctx = {req: {accessToken: {userId: 18}}}; - let price = 5.4; + it('should set price as a decimal number and check the sale has the mana component changing the salesPersonMana', async() => { + const tx = await models.Sale.beginTransaction({}); - await app.models.Sale.updatePrice(ctx, saleId, price); - let updatedSale = await app.models.Sale.findById(saleId); - createdSaleComponent = await app.models.SaleComponent.findOne({where: {saleFk: saleId, componentFk: manaComponentId}}); + try { + const options = {transaction: tx}; - expect(updatedSale.price).toBe(price); - expect(createdSaleComponent.value).toEqual(-2.04); + const price = 5.4; + const originalSalesPersonMana = await models.WorkerMana.findById(18, null, options); + const manaComponent = await models.Component.findOne({where: {code: 'mana'}}, options); - let updatedSalesPersonMana = await app.models.WorkerMana.findById(18); + await models.Sale.updatePrice(ctx, saleId, price, options); + const updatedSale = await models.Sale.findById(saleId, null, options); + createdSaleComponent = await models.SaleComponent.findOne({where: {saleFk: saleId, componentFk: manaComponent.id}}, options); - expect(updatedSalesPersonMana.amount).not.toEqual(originalSalesPersonMana.amount); + expect(updatedSale.price).toBe(price); + expect(createdSaleComponent.value).toEqual(-2.04); - // restores - await originalSale.updateAttributes(originalSale); - await app.models.SaleComponent.updateAll({componentFk: manaComponentId, saleFk: saleId}, {value: 0}); - await originalSalesPersonMana.updateAttributes(originalSalesPersonMana); + const updatedSalesPersonMana = await models.WorkerMana.findById(18, null, options); + + expect(updatedSalesPersonMana.amount).not.toEqual(originalSalesPersonMana.amount); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } }); }); diff --git a/modules/ticket/back/methods/sale/specs/updateQuantity.spec.js b/modules/ticket/back/methods/sale/specs/updateQuantity.spec.js index dabdac384..4c961faab 100644 --- a/modules/ticket/back/methods/sale/specs/updateQuantity.spec.js +++ b/modules/ticket/back/methods/sale/specs/updateQuantity.spec.js @@ -1,4 +1,4 @@ -const app = require('vn-loopback/server/server'); +const models = require('vn-loopback/server/server').models; describe('sale updateQuantity()', () => { const ctx = { @@ -10,44 +10,61 @@ describe('sale updateQuantity()', () => { }; it('should throw an error if the quantity is not a number', async() => { + const tx = await models.Sale.beginTransaction({}); + let error; + try { + const options = {transaction: tx}; - await app.models.Sale.updateQuantity(ctx, 1, 'wrong quantity!') - .catch(response => { - expect(response).toEqual(new Error('The value should be a number')); - error = response; - }); + await models.Sale.updateQuantity(ctx, 1, 'wrong quantity!', options); - expect(error).toBeDefined(); + await tx.rollback(); + } catch (e) { + await tx.rollback(); + error = e; + } + + expect(error).toEqual(new Error('The value should be a number')); }); it('should throw an error if the quantity is greater than it should be', async() => { + const tx = await models.Sale.beginTransaction({}); + let error; + try { + const options = {transaction: tx}; - await app.models.Sale.updateQuantity(ctx, 1, 99) - .catch(response => { - expect(response).toEqual(new Error('The new quantity should be smaller than the old one')); - error = response; - }); + await models.Sale.updateQuantity(ctx, 1, 99, options); - expect(error).toBeDefined(); + await tx.rollback(); + } catch (e) { + await tx.rollback(); + error = e; + } + + expect(error).toEqual(new Error('The new quantity should be smaller than the old one')); }); it('should update the quantity of a given sale current line', async() => { - let originalLineData = await app.models.Sale.findOne({where: {id: 1}, fields: ['quantity']}); + const tx = await models.Sale.beginTransaction({}); - expect(originalLineData.quantity).toEqual(5); + try { + const options = {transaction: tx}; - await app.models.Sale.updateQuantity(ctx, 1, 4); + const originalLine = await models.Sale.findOne({where: {id: 1}, fields: ['quantity']}, options); - let modifiedLineData = await app.models.Sale.findOne({where: {id: 1}, fields: ['quantity']}); + expect(originalLine.quantity).toEqual(5); - expect(modifiedLineData.quantity).toEqual(4); + await models.Sale.updateQuantity(ctx, 1, 4, options); - await app.models.Sale.update({id: 1}, {quantity: 5}); + const modifiedLine = await models.Sale.findOne({where: {id: 1}, fields: ['quantity']}, options); - let resetLineDataValues = await app.models.Sale.findOne({where: {id: 1}, fields: ['quantity']}); + expect(modifiedLine.quantity).toEqual(4); - expect(resetLineDataValues.quantity).toEqual(5); + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } }); }); diff --git a/modules/ticket/back/methods/sale/updateConcept.js b/modules/ticket/back/methods/sale/updateConcept.js index 6a5f3375f..0730f85e2 100644 --- a/modules/ticket/back/methods/sale/updateConcept.js +++ b/modules/ticket/back/methods/sale/updateConcept.js @@ -24,15 +24,35 @@ module.exports = Self => { } }); - Self.updateConcept = async(ctx, id, newConcept) => { + Self.updateConcept = async(ctx, id, newConcept, options) => { const models = Self.app.models; - const currentLine = await models.Sale.findById(id); + const myOptions = {}; + let tx; - const canEditSale = await models.Sale.canEdit(ctx, [id]); + if (typeof options == 'object') + Object.assign(myOptions, options); - if (!canEditSale) - throw new UserError(`Sale(s) blocked, please contact production`); + if (!myOptions.transaction) { + tx = await Self.beginTransaction({}); + myOptions.transaction = tx; + } - return await currentLine.updateAttributes({concept: newConcept}); + try { + const currentLine = await models.Sale.findById(id, null, myOptions); + + const canEditSale = await models.Sale.canEdit(ctx, [id], myOptions); + + if (!canEditSale) + throw new UserError(`Sale(s) blocked, please contact production`); + + const line = await currentLine.updateAttributes({concept: newConcept}, myOptions); + + if (tx) await tx.commit(); + + return line; + } catch (e) { + if (tx) await tx.rollback(); + throw e; + } }; }; diff --git a/modules/ticket/back/methods/sale/updatePrice.js b/modules/ticket/back/methods/sale/updatePrice.js index cb86296c9..fa1705e55 100644 --- a/modules/ticket/back/methods/sale/updatePrice.js +++ b/modules/ticket/back/methods/sale/updatePrice.js @@ -28,14 +28,21 @@ module.exports = Self => { } }); - Self.updatePrice = async(ctx, id, newPrice) => { + Self.updatePrice = async(ctx, id, newPrice, options) => { const $t = ctx.req.__; // $translate const models = Self.app.models; - const tx = await Self.beginTransaction({}); + const myOptions = {}; + let tx; + + if (typeof options == 'object') + Object.assign(myOptions, options); + + if (!myOptions.transaction) { + tx = await Self.beginTransaction({}); + myOptions.transaction = tx; + } try { - const options = {transaction: tx}; - const filter = { include: { relation: 'ticket', @@ -57,22 +64,22 @@ module.exports = Self => { } }; - const sale = await models.Sale.findById(id, filter, options); + const sale = await models.Sale.findById(id, filter, myOptions); - const isEditable = await models.Ticket.isEditable(ctx, sale.ticketFk); + const isEditable = await models.Ticket.isEditable(ctx, sale.ticketFk, myOptions); if (!isEditable) throw new UserError(`The sales of this ticket can't be modified`); - const canEditSale = await models.Sale.canEdit(ctx, [id]); + const canEditSale = await models.Sale.canEdit(ctx, [id], myOptions); if (!canEditSale) throw new UserError(`Sale(s) blocked, please contact production`); const oldPrice = sale.price; const userId = ctx.req.accessToken.userId; - const usesMana = await models.WorkerMana.findOne({where: {workerFk: userId}, fields: 'amount'}, options); + const usesMana = await models.WorkerMana.findOne({where: {workerFk: userId}, fields: 'amount'}, myOptions); const componentCode = usesMana ? 'mana' : 'buyerDiscount'; - const discount = await models.Component.findOne({where: {code: componentCode}}, options); + const discount = await models.Component.findOne({where: {code: componentCode}}, myOptions); const componentId = discount.id; const componentValue = newPrice - sale.price; @@ -80,23 +87,23 @@ module.exports = Self => { componentFk: componentId, saleFk: id }; - const saleComponent = await models.SaleComponent.findOne({where}, options); + const saleComponent = await models.SaleComponent.findOne({where}, myOptions); if (saleComponent) { await models.SaleComponent.updateAll(where, { value: saleComponent.value + componentValue - }, options); + }, myOptions); } else { await models.SaleComponent.create({ saleFk: id, componentFk: componentId, value: componentValue - }, options); + }, myOptions); } - await sale.updateAttributes({price: newPrice}, options); + await sale.updateAttributes({price: newPrice}, myOptions); query = `CALL vn.manaSpellersRequery(?)`; - await Self.rawSql(query, [userId], options); + await Self.rawSql(query, [userId], myOptions); const salesPerson = sale.ticket().client().salesPersonUser(); if (salesPerson) { @@ -111,14 +118,14 @@ module.exports = Self => { ticketUrl: `${origin}/#!/ticket/${sale.ticket().id}/sale`, itemUrl: `${origin}/#!/item/${sale.itemFk}/summary` }); - await models.Chat.sendCheckingPresence(ctx, salesPerson.id, message); + await models.Chat.sendCheckingPresence(ctx, salesPerson.id, message, myOptions); } - await tx.commit(); + if (tx) await tx.commit(); return sale; } catch (error) { - await tx.rollback(); + if (tx) await tx.rollback(); throw error; } }; diff --git a/modules/ticket/back/methods/sale/updateQuantity.js b/modules/ticket/back/methods/sale/updateQuantity.js index 62e09f1f5..24e3736f3 100644 --- a/modules/ticket/back/methods/sale/updateQuantity.js +++ b/modules/ticket/back/methods/sale/updateQuantity.js @@ -26,60 +26,77 @@ module.exports = Self => { } }); - Self.updateQuantity = async(ctx, id, newQuantity) => { - const $t = ctx.req.__; // $translate + Self.updateQuantity = async(ctx, id, newQuantity, options) => { const models = Self.app.models; + const $t = ctx.req.__; // $translate + const myOptions = {}; + let tx; - const canEditSale = await models.Sale.canEdit(ctx, [id]); + if (typeof options == 'object') + Object.assign(myOptions, options); - if (!canEditSale) - throw new UserError(`Sale(s) blocked, please contact production`); + if (!myOptions.transaction) { + tx = await Self.beginTransaction({}); + myOptions.transaction = tx; + } - if (isNaN(newQuantity)) - throw new UserError(`The value should be a number`); + try { + const canEditSale = await models.Sale.canEdit(ctx, [id], myOptions); - const filter = { - include: { - relation: 'ticket', - scope: { - include: { - relation: 'client', - scope: { - include: { - relation: 'salesPersonUser', - scope: { - fields: ['id', 'name'] + if (!canEditSale) + throw new UserError(`Sale(s) blocked, please contact production`); + + if (isNaN(newQuantity)) + throw new UserError(`The value should be a number`); + + const filter = { + include: { + relation: 'ticket', + scope: { + include: { + relation: 'client', + scope: { + include: { + relation: 'salesPersonUser', + scope: { + fields: ['id', 'name'] + } } } } } } + }; + + const sale = await models.Sale.findById(id, filter, myOptions); + + if (newQuantity > sale.quantity) + throw new UserError('The new quantity should be smaller than the old one'); + + const oldQuantity = sale.quantity; + const result = await sale.updateAttributes({quantity: newQuantity}, myOptions); + + const salesPerson = sale.ticket().client().salesPersonUser(); + if (salesPerson) { + const origin = ctx.req.headers.origin; + const message = $t('Changed sale quantity', { + ticketId: sale.ticket().id, + itemId: sale.itemFk, + concept: sale.concept, + oldQuantity: oldQuantity, + newQuantity: newQuantity, + ticketUrl: `${origin}/#!/ticket/${sale.ticket().id}/sale`, + itemUrl: `${origin}/#!/item/${sale.itemFk}/summary` + }); + await models.Chat.sendCheckingPresence(ctx, salesPerson.id, message, myOptions); } - }; - const sale = await models.Sale.findById(id, filter); + if (tx) await tx.commit(); - if (newQuantity > sale.quantity) - throw new UserError('The new quantity should be smaller than the old one'); - - const oldQuantity = sale.quantity; - const result = await sale.updateAttributes({quantity: newQuantity}); - - const salesPerson = sale.ticket().client().salesPersonUser(); - if (salesPerson) { - const origin = ctx.req.headers.origin; - const message = $t('Changed sale quantity', { - ticketId: sale.ticket().id, - itemId: sale.itemFk, - concept: sale.concept, - oldQuantity: oldQuantity, - newQuantity: newQuantity, - ticketUrl: `${origin}/#!/ticket/${sale.ticket().id}/sale`, - itemUrl: `${origin}/#!/item/${sale.itemFk}/summary` - }); - await models.Chat.sendCheckingPresence(ctx, salesPerson.id, message); + return result; + } catch (error) { + if (tx) await tx.rollback(); + throw error; } - - return result; }; }; From 1ec20e250c5ff8442ce08bd57e9b2b9fb864bec3 Mon Sep 17 00:00:00 2001 From: joan Date: Fri, 1 Oct 2021 12:41:31 +0200 Subject: [PATCH 09/47] feat(invoice): Send invoice and delivery-note on CSV format --- front/core/components/menu/menu.js | 4 +- front/core/components/menu/style.scss | 11 +++ front/core/components/popover/index.js | 39 +++++++-- front/core/services/email.js | 12 +++ front/core/services/report.js | 15 ++++ .../invoiceOut/front/descriptor/index.html | 47 +++++++++-- modules/invoiceOut/front/descriptor/index.js | 17 +++- .../invoiceOut/front/descriptor/locale/es.yml | 4 +- .../ticket/front/descriptor-menu/index.html | 75 +++++++++++++++-- modules/ticket/front/descriptor-menu/index.js | 19 ++++- .../front/descriptor-menu/locale/es.yml | 8 ++ modules/ticket/front/descriptor/locale/es.yml | 2 - print/core/email.js | 23 +++++- print/core/router.js | 7 +- print/methods/csv.js | 31 +++++++ print/methods/csv/delivery-note/index.js | 82 +++++++++++++++++++ print/methods/csv/delivery-note/sql/sales.sql | 35 ++++++++ .../methods/csv/delivery-note/sql/ticket.sql | 9 ++ print/methods/csv/invoice/index.js | 82 +++++++++++++++++++ print/methods/csv/invoice/sql/invoice.sql | 9 ++ print/methods/csv/invoice/sql/sales.sql | 35 ++++++++ .../reports/delivery-note/delivery-note.js | 3 + 22 files changed, 533 insertions(+), 36 deletions(-) create mode 100644 modules/ticket/front/descriptor-menu/locale/es.yml create mode 100644 print/methods/csv.js create mode 100644 print/methods/csv/delivery-note/index.js create mode 100644 print/methods/csv/delivery-note/sql/sales.sql create mode 100644 print/methods/csv/delivery-note/sql/ticket.sql create mode 100644 print/methods/csv/invoice/index.js create mode 100644 print/methods/csv/invoice/sql/invoice.sql create mode 100644 print/methods/csv/invoice/sql/sales.sql diff --git a/front/core/components/menu/menu.js b/front/core/components/menu/menu.js index d0c649004..e0d968e2f 100755 --- a/front/core/components/menu/menu.js +++ b/front/core/components/menu/menu.js @@ -3,8 +3,8 @@ import Popover from '../popover'; import './style.scss'; export default class Menu extends Popover { - show(parent) { - super.show(parent); + show(parent, direction) { + super.show(parent, direction); this.windowEl.addEventListener('click', () => this.hide()); } } diff --git a/front/core/components/menu/style.scss b/front/core/components/menu/style.scss index 92f437243..6125c0e5b 100644 --- a/front/core/components/menu/style.scss +++ b/front/core/components/menu/style.scss @@ -1,7 +1,18 @@ @import "./effects"; +@import "variables"; .vn-menu { vn-item, .vn-item { @extend %clickable; } + + vn-item.dropdown:after, + .vn-item.dropdown:after { + font-family: 'Material Icons'; + content: 'keyboard_arrow_right'; + position: absolute; + color: $color-spacer; + font-size: 1.5em; + right: 0 + } } diff --git a/front/core/components/popover/index.js b/front/core/components/popover/index.js index d78179ab9..9e68d176e 100644 --- a/front/core/components/popover/index.js +++ b/front/core/components/popover/index.js @@ -24,11 +24,13 @@ export default class Popover extends Popup { * * @param {HTMLElement|Event} parent Overrides the parent property */ - show(parent) { + show(parent, direction) { if (parent instanceof Event) parent = event.target; if (parent) this.parent = parent; + if (direction) this.direction = direction; + console.log(direction); super.show(); this.content = this.popup.querySelector('.content'); this.$timeout(() => this.relocate(), 10); @@ -58,6 +60,7 @@ export default class Popover extends Popup { * Repositions the popover to a correct location relative to the parent. */ relocate() { + console.log(this.direction); if (!(this.parent && this._shown && this.displayMode == 'relative')) return; @@ -89,21 +92,43 @@ export default class Popover extends Popup { let width = clamp(popoverRect.width, parentRect.width, maxWith); let height = popoverRect.height; - let left = parentRect.left + parentRect.width / 2 - width / 2; - left = clamp(left, margin, maxRight - width); + let left; + if (this.direction == 'left') { + left = parentRect.left + parentRect.width; + left = clamp(left, margin, maxRight - width); + } else { + left = parentRect.left + parentRect.width / 2 - width / 2; + left = clamp(left, margin, maxRight - width); + } + /* let left = parentRect.left + parentRect.width / 2 - width / 2; + left = clamp(left, margin, maxRight - width); */ - let top = parentRect.top + parentRect.height + arrowOffset; + let top; + if (this.direction == 'left') + top = parentRect.top; + else + top = parentRect.top + parentRect.height + arrowOffset; let showTop = top + height > maxBottom; if (showTop) top = parentRect.top - height - arrowOffset; top = Math.max(top, margin); - if (showTop) + if (this.direction == 'left') + arrowStyle.left = `0`; + else if (showTop) arrowStyle.bottom = `0`; else arrowStyle.top = `0`; - let arrowLeft = (parentRect.left - left) + parentRect.width / 2; - arrowLeft = clamp(arrowLeft, arrowHeight, width - arrowHeight); + let arrowLeft; + if (this.direction == 'left') { + arrowLeft = 0; + let arrowTop = arrowOffset; + // arrowLeft = clamp(arrowLeft, arrowHeight, width - arrowHeight); + arrowStyle.top = `${arrowTop}px`; + } else { + arrowLeft = (parentRect.left - left) + parentRect.width / 2; + arrowLeft = clamp(arrowLeft, arrowHeight, width - arrowHeight); + } arrowStyle.left = `${arrowLeft}px`; style.top = `${top}px`; diff --git a/front/core/services/email.js b/front/core/services/email.js index 4385eed5f..23eae0202 100644 --- a/front/core/services/email.js +++ b/front/core/services/email.js @@ -18,6 +18,18 @@ class Email { return this.$http.get(`email/${template}`, {params}) .then(() => this.vnApp.showMessage(this.$t('Notification sent!'))); } + + /** + * Sends an email displaying a notification when it's sent. + * + * @param {String} template The email report name + * @param {Object} params The email parameters + * @return {Promise} Promise resolved when it's sent + */ + sendCSV(template, params) { + return this.$http.get(`csv/${template}/send`, {params}) + .then(() => this.vnApp.showMessage(this.$t('Notification sent!'))); + } } Email.$inject = ['$http', '$translate', 'vnApp']; diff --git a/front/core/services/report.js b/front/core/services/report.js index 32ccb52a3..12d33789f 100644 --- a/front/core/services/report.js +++ b/front/core/services/report.js @@ -20,6 +20,21 @@ class Report { const serializedParams = this.$httpParamSerializer(params); window.open(`api/report/${report}?${serializedParams}`); } + + /** + * Shows a report in another window, automatically adds the authorization + * token to params. + * + * @param {String} report The report name + * @param {Object} params The report parameters + */ + showCSV(report, params) { + params = Object.assign({ + authorization: this.vnToken.token + }, params); + const serializedParams = this.$httpParamSerializer(params); + window.open(`api/csv/${report}/download?${serializedParams}`); + } } Report.$inject = ['$httpParamSerializer', 'vnToken']; diff --git a/modules/invoiceOut/front/descriptor/index.html b/modules/invoiceOut/front/descriptor/index.html index 1da487d15..584983379 100644 --- a/modules/invoiceOut/front/descriptor/index.html +++ b/modules/invoiceOut/front/descriptor/index.html @@ -2,18 +2,49 @@ module="invoiceOut" description="$ctrl.invoiceOut.ref"> - - Show invoice PDF - - + + + Show as PDF + + + Show as CSV + + + + + - Send invoice PDF + Send invoice... + + + + + Send PDF + + + Send CSV + + + this.entity = res.data); } + showInvoiceCSV() { + this.vnReport.showCSV('invoice', { + recipientId: this.invoiceOut.client.id, + invoiceId: this.id, + }); + } + sendInvoice($data) { return this.vnEmail.send('invoice', { recipientId: this.invoiceOut.client.id, @@ -67,6 +74,14 @@ class Controller extends Descriptor { invoiceId: this.id }); } + + sendDeliveryNoteCSV($data) { + return this.vnEmail.sendCSV('delivery-note', { + recipientId: this.ticket.client.id, + recipient: $data.email, + ticketId: this.id + }); + } } ngModule.vnComponent('vnInvoiceOutDescriptor', { diff --git a/modules/invoiceOut/front/descriptor/locale/es.yml b/modules/invoiceOut/front/descriptor/locale/es.yml index ec9cd3310..68ce7af84 100644 --- a/modules/invoiceOut/front/descriptor/locale/es.yml +++ b/modules/invoiceOut/front/descriptor/locale/es.yml @@ -2,8 +2,10 @@ Volume exceded: Volumen excedido Volume: Volumen Client card: Ficha del cliente Invoice ticket list: Listado de tickets de la factura -Show invoice PDF: Ver factura en PDF +Show invoice...: Ver factura... +Send invoice...: Enviar factura... Send invoice PDF: Enviar factura en PDF +Send invoice CSV: Enviar factura en CSV Delete Invoice: Eliminar factura Clone Invoice: Clonar factura InvoiceOut deleted: Factura eliminada diff --git a/modules/ticket/front/descriptor-menu/index.html b/modules/ticket/front/descriptor-menu/index.html index 4f65fe008..b26246b3c 100644 --- a/modules/ticket/front/descriptor-menu/index.html +++ b/modules/ticket/front/descriptor-menu/index.html @@ -2,6 +2,7 @@ icon="more_vert" vn-popover="menu"> + Add turn - Show Delivery Note + + + + Show as PDF + + + Show as CSV + + + - Send Delivery Note + + + + + Send PDF + + + Send CSV + + + - - + --> + + + + Are you sure you want to send it? + + + + + + + + + + + + + Are you sure you want to send it? + + + + + + + + { for (file of files) { const fileCopy = Object.assign({}, file); + const fileName = fileCopy.filename; + + if (options.overrideAttachments && !fileName.includes('.png')) continue; + if (fileCopy.cid) { const templatePath = `${componentPath}/${file.path}`; const fullFilePath = path.resolve(__dirname, templatePath); fileCopy.path = path.resolve(__dirname, fullFilePath); } else { - const reportName = fileCopy.filename.replace('.pdf', ''); + const reportName = fileName.replace('.pdf', ''); const report = new Report(reportName, this.args); fileCopy.content = await report.toPdfStream(); } @@ -71,9 +81,14 @@ class Email extends Component { if (this.attachments) await getAttachments(this.path, this.attachments); + if (options.attachments) { + for (let attachment of options.attachments) + attachments.push(attachment); + } + const localeSubject = await this.getSubject(); const replyTo = this.args.replyTo || this.args.auth.email; - const options = { + const mailOptions = { to: this.args.recipient, replyTo: replyTo, subject: localeSubject, @@ -81,7 +96,7 @@ class Email extends Component { attachments: attachments }; - return smtp.send(options); + return smtp.send(mailOptions); } } diff --git a/print/core/router.js b/print/core/router.js index feaea214b..c0f20dd9a 100644 --- a/print/core/router.js +++ b/print/core/router.js @@ -8,9 +8,10 @@ module.exports = app => { const methods = []; // Get all methods - methodsDir.forEach(method => { - methods.push(method.replace('.js', '')); - }); + for (let method of methodsDir) { + if (method.includes('.js')) + methods.push(method.replace('.js', '')); + } // Auth middleware const paths = []; diff --git a/print/methods/csv.js b/print/methods/csv.js new file mode 100644 index 000000000..4f4cdf2af --- /dev/null +++ b/print/methods/csv.js @@ -0,0 +1,31 @@ +module.exports = app => { + app.use('/api/csv/delivery-note', require('./csv/delivery-note')(app)); + app.use('/api/csv/invoice', require('./csv/invoice')(app)); + + app.toCSV = function toCSV(rows) { + const [columns] = rows; + let content = Object.keys(columns).join('\t'); + for (let row of rows) { + const values = Object.values(row); + const finalValues = values.map(value => { + if (value instanceof Date) return formatDate(value); + if (value === null) return ''; + return value; + }); + content += '\n'; + content += finalValues.join('\t'); + } + return content; + }; + + function formatDate(date) { + return new Intl.DateTimeFormat('es', { + year: 'numeric', + month: 'numeric', + day: 'numeric', + hour: '2-digit', + minute: '2-digit', + second: '2-digit' + }).format(date); + } +}; diff --git a/print/methods/csv/delivery-note/index.js b/print/methods/csv/delivery-note/index.js new file mode 100644 index 000000000..9ef0e33fa --- /dev/null +++ b/print/methods/csv/delivery-note/index.js @@ -0,0 +1,82 @@ +const express = require('express'); +const router = new express.Router(); +const path = require('path'); +const db = require('../../../core/database'); +const sqlPath = path.join(__dirname, 'sql'); + +module.exports = app => { + router.get('/preview', async function(req, res, next) { + try { + const reqArgs = req.args; + if (!reqArgs.ticketId) + throw new Error('The argument ticketId is required'); + + const ticketId = reqArgs.ticketId; + const sales = await db.rawSqlFromDef(`${sqlPath}/sales`, [ticketId]); + const content = app.toCSV(sales); + const fileName = `ticket_${ticketId}.csv`; + + res.setHeader('Content-type', 'application/json; charset=utf-8'); + res.setHeader('Content-Disposition', `inline; filename="${fileName}"`); + res.end(content); + } catch (error) { + next(error); + } + }); + + router.get('/download', async function(req, res, next) { + try { + const reqArgs = req.args; + if (!reqArgs.ticketId) + throw new Error('The argument ticketId is required'); + + const ticketId = reqArgs.ticketId; + const sales = await db.rawSqlFromDef(`${sqlPath}/sales`, [ticketId]); + const content = app.toCSV(sales); + const fileName = `ticket_${ticketId}.csv`; + + res.setHeader('Content-type', 'text/csv'); + res.setHeader('Content-Disposition', `inline; filename="${fileName}"`); + res.end(content); + } catch (error) { + next(error); + } + }); + + const Email = require('../../../core/email'); + router.get('/send', async function(req, res, next) { + try { + const reqArgs = req.args; + if (!reqArgs.ticketId) + throw new Error('The argument ticketId is required'); + + const ticketId = reqArgs.ticketId; + const ticket = await db.findOneFromDef(`${sqlPath}/ticket`, [ticketId]); + const sales = await db.rawSqlFromDef(`${sqlPath}/sales`, [ticketId]); + + const args = Object.assign({ + ticketId: (String(ticket.id)), + recipientId: ticket.clientFk, + recipient: ticket.recipient, + replyTo: ticket.salesPersonEmail + }, reqArgs); + + const content = app.toCSV(sales); + const fileName = `ticket_${ticketId}.csv`; + const email = new Email('delivery-note', args); + await email.send({ + overrideAttachments: true, + attachments: [{ + filename: fileName, + content: content + }] + }); + + res.status(200).json({message: 'ok'}); + } catch (error) { + next(error); + } + }); + + return router; +}; diff --git a/print/methods/csv/delivery-note/sql/sales.sql b/print/methods/csv/delivery-note/sql/sales.sql new file mode 100644 index 000000000..e5b419571 --- /dev/null +++ b/print/methods/csv/delivery-note/sql/sales.sql @@ -0,0 +1,35 @@ +SELECT io.ref Invoice, + io.issued InvoiceDate, + s.ticketFk Ticket, + s.itemFk Item, + s.concept Description, + i.size, + i.subName Producer, + s.quantity Quantity, + s.price Price, + s.discount Discount, + s.created Created, + tc.code Taxcode, + tc.description TaxDescription, + i.tag5, + i.value5, + i.tag6, + i.value6, + i.tag7, + i.value7, + i.tag8, + i.value8, + i.tag9, + i.value9, + i.tag10, + i.value10 +FROM vn.sale s + JOIN vn.ticket t ON t.id = s.ticketFk + JOIN vn.item i ON i.id = s.itemFk + JOIN vn.supplier s2 ON s2.id = t.companyFk + JOIN vn.itemTaxCountry itc ON itc.itemFk = i.id + AND itc.countryFk = s2.countryFk + JOIN vn.taxClass tc ON tc.id = itc.taxClassFk + LEFT JOIN vn.invoiceOut io ON io.id = t.refFk +WHERE s.ticketFk = ? +ORDER BY s.ticketFk, s.created \ No newline at end of file diff --git a/print/methods/csv/delivery-note/sql/ticket.sql b/print/methods/csv/delivery-note/sql/ticket.sql new file mode 100644 index 000000000..b80c7c42c --- /dev/null +++ b/print/methods/csv/delivery-note/sql/ticket.sql @@ -0,0 +1,9 @@ +SELECT + t.id, + t.clientFk, + c.email recipient, + eu.email salesPersonEmail +FROM ticket t + JOIN client c ON c.id = t.clientFk + LEFT JOIN account.emailUser eu ON eu.userFk = c.salesPersonFk +WHERE t.id = ? \ No newline at end of file diff --git a/print/methods/csv/invoice/index.js b/print/methods/csv/invoice/index.js new file mode 100644 index 000000000..8f325be02 --- /dev/null +++ b/print/methods/csv/invoice/index.js @@ -0,0 +1,82 @@ +const express = require('express'); +const router = new express.Router(); +const path = require('path'); +const db = require('../../../core/database'); +const sqlPath = path.join(__dirname, 'sql'); + +module.exports = app => { + router.get('/preview', async function(req, res, next) { + try { + const reqArgs = req.args; + if (!reqArgs.invoiceId) + throw new Error('The argument invoiceId is required'); + + const invoiceId = reqArgs.invoiceId; + const sales = await db.rawSqlFromDef(`${sqlPath}/sales`, [invoiceId]); + const content = app.toCSV(sales); + const fileName = `invoice_${invoiceId}.csv`; + + res.setHeader('Content-type', 'application/json; charset=utf-8'); + res.setHeader('Content-Disposition', `inline; filename="${fileName}"`); + res.end(content); + } catch (error) { + next(error); + } + }); + + router.get('/download', async function(req, res, next) { + try { + const reqArgs = req.args; + if (!reqArgs.invoiceId) + throw new Error('The argument invoiceId is required'); + + const invoiceId = reqArgs.invoiceId; + const sales = await db.rawSqlFromDef(`${sqlPath}/sales`, [invoiceId]); + const content = app.toCSV(sales); + const fileName = `invoice_${invoiceId}.csv`; + + res.setHeader('Content-type', 'text/csv'); + res.setHeader('Content-Disposition', `inline; filename="${fileName}"`); + res.end(content); + } catch (error) { + next(error); + } + }); + + const Email = require('../../../core/email'); + router.get('/send', async function(req, res, next) { + try { + const reqArgs = req.args; + if (!reqArgs.invoiceId) + throw new Error('The argument invoiceId is required'); + + const invoiceId = reqArgs.invoiceId; + const invoice = await db.findOneFromDef(`${sqlPath}/invoice`, [invoiceId]); + const sales = await db.rawSqlFromDef(`${sqlPath}/sales`, [invoiceId]); + + const args = Object.assign({ + invoiceId: (String(invoice.id)), + recipientId: invoice.clientFk, + recipient: invoice.recipient, + replyTo: invoice.salesPersonEmail + }, reqArgs); + + const content = app.toCSV(sales); + const fileName = `invoice_${invoiceId}.csv`; + const email = new Email('invoice', args); + await email.send({ + overrideAttachments: true, + attachments: [{ + filename: fileName, + content: content + }] + }); + + res.status(200).json({message: 'ok'}); + } catch (error) { + next(error); + } + }); + + return router; +}; diff --git a/print/methods/csv/invoice/sql/invoice.sql b/print/methods/csv/invoice/sql/invoice.sql new file mode 100644 index 000000000..853aaddc0 --- /dev/null +++ b/print/methods/csv/invoice/sql/invoice.sql @@ -0,0 +1,9 @@ +SELECT + io.id, + io.clientFk, + c.email recipient, + eu.email salesPersonEmail +FROM invoiceOut io + JOIN client c ON c.id = io.clientFk + LEFT JOIN account.emailUser eu ON eu.userFk = c.salesPersonFk +WHERE io.id = ? \ No newline at end of file diff --git a/print/methods/csv/invoice/sql/sales.sql b/print/methods/csv/invoice/sql/sales.sql new file mode 100644 index 000000000..34b5af1f7 --- /dev/null +++ b/print/methods/csv/invoice/sql/sales.sql @@ -0,0 +1,35 @@ +SELECT io.ref Invoice, + io.issued InvoiceDate, + s.ticketFk Ticket, + s.itemFk Item, + s.concept Description, + i.size, + i.subName Producer, + s.quantity Quantity, + s.price Price, + s.discount Discount, + s.created Created, + tc.code Taxcode, + tc.description TaxDescription, + i.tag5, + i.value5, + i.tag6, + i.value6, + i.tag7, + i.value7, + i.tag8, + i.value8, + i.tag9, + i.value9, + i.tag10, + i.value10 +FROM sale s + JOIN ticket t ON t.id = s.ticketFk + JOIN item i ON i.id = s.itemFk + JOIN supplier s2 ON s2.id = t.companyFk + JOIN itemTaxCountry itc ON itc.itemFk = i.id + AND itc.countryFk = s2.countryFk + JOIN taxClass tc ON tc.id = itc.taxClassFk + JOIN invoiceOut io ON io.ref = t.refFk +WHERE io.id = ? +ORDER BY s.ticketFk, s.created \ No newline at end of file diff --git a/print/templates/reports/delivery-note/delivery-note.js b/print/templates/reports/delivery-note/delivery-note.js index 549759651..9b3328d05 100755 --- a/print/templates/reports/delivery-note/delivery-note.js +++ b/print/templates/reports/delivery-note/delivery-note.js @@ -29,6 +29,9 @@ module.exports = { const hash = md5(this.signature.id.toString()).substring(0, 3); const file = `${config.storage.root}/${hash}/${this.signature.id}.png`; + + if (!fs.existsSync(file)) return null; + const src = fs.readFileSync(file); const base64 = Buffer.from(src, 'utf8').toString('base64'); From 55a2ec83da3a3767564b54ee90201f84b6f27dac Mon Sep 17 00:00:00 2001 From: carlosjr Date: Thu, 7 Oct 2021 09:25:35 +0200 Subject: [PATCH 10/47] fix(jasmine): changed backend unit tests default timeout to 6 from 5 secs to avoid initial queries to timeout --- gulpfile.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/gulpfile.js b/gulpfile.js index 73b325449..efd1d15ba 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -94,8 +94,11 @@ async function launchBackTest(done) { await new Promise((resolve, reject) => { const jasmine = require('gulp-jasmine'); - let options = { + const options = { + verbose: false, + includeStackTrace: false, errorOnFail: false, + timeout: 6000, config: {} }; From cb7d1b24e85838af2f2bd74f54af74958902e9b1 Mon Sep 17 00:00:00 2001 From: carlosjr Date: Thu, 7 Oct 2021 09:57:07 +0200 Subject: [PATCH 11/47] refactor(ticket): all ticket endpoints are using transactions now --- .../ticket/back/methods/expedition/filter.js | 13 +- .../methods/expedition/specs/filter.spec.js | 21 +++ .../back/methods/packaging/listPackaging.js | 18 +- .../packaging/specs/listPackaging.spec.js | 20 +- .../methods/sale-tracking/listSaleTracking.js | 27 +-- .../specs/listSaleTracking.spec.js | 36 +++- .../back/methods/state/editableStates.js | 21 ++- .../methods/state/specs/editableState.spec.js | 75 ++++++-- .../back/methods/ticket-dms/removeFile.js | 38 +++- .../ticket-dms/specs/removeFile.spec.js | 25 ++- .../back/methods/ticket-request/confirm.js | 64 ++++--- .../back/methods/ticket-request/deny.js | 42 +++-- .../back/methods/ticket-request/filter.js | 18 +- .../ticket-request/specs/confirm.spec.js | 107 ++++++----- .../methods/ticket-request/specs/deny.spec.js | 29 ++- .../ticket-request/specs/filter.spec.js | 171 ++++++++++++++---- .../methods/ticket-tracking/setDelivered.js | 63 ++++--- .../specs/setDelivered.spec.js | 61 +++---- .../back/methods/ticket-weekly/filter.js | 27 +-- .../ticket-weekly/specs/filter.spec.js | 92 +++++++--- 20 files changed, 653 insertions(+), 315 deletions(-) create mode 100644 modules/ticket/back/methods/expedition/specs/filter.spec.js diff --git a/modules/ticket/back/methods/expedition/filter.js b/modules/ticket/back/methods/expedition/filter.js index 817630eec..5eb7510b7 100644 --- a/modules/ticket/back/methods/expedition/filter.js +++ b/modules/ticket/back/methods/expedition/filter.js @@ -7,13 +7,13 @@ module.exports = Self => { accepts: [ { arg: 'filter', - type: 'Object', + type: 'object', description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string', http: {source: 'query'}, }, ], returns: { - type: ['Object'], + type: ['object'], root: true, }, http: { @@ -22,7 +22,12 @@ module.exports = Self => { }, }); - Self.filter = async filter => { + Self.filter = async(filter, options) => { + const myOptions = {}; + + if (typeof options == 'object') + Object.assign(myOptions, options); + const stmt = new ParameterizedSQL( `SELECT e.id, @@ -55,6 +60,6 @@ module.exports = Self => { `); stmt.merge(Self.buildSuffix(filter, 'e')); - return await Self.rawStmt(stmt); + return Self.rawStmt(stmt, myOptions); }; }; diff --git a/modules/ticket/back/methods/expedition/specs/filter.spec.js b/modules/ticket/back/methods/expedition/specs/filter.spec.js new file mode 100644 index 000000000..85e98da4a --- /dev/null +++ b/modules/ticket/back/methods/expedition/specs/filter.spec.js @@ -0,0 +1,21 @@ +const models = require('vn-loopback/server/server').models; + +describe('expedition filter()', () => { + it('should return the expeditions matching the filter', async() => { + const tx = await models.Expedition.beginTransaction({}); + + try { + const options = {transaction: tx}; + + const filter = {where: {packagingFk: 1}}; + const response = await models.Expedition.filter(filter, options); + + expect(response.length).toEqual(10); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); +}); diff --git a/modules/ticket/back/methods/packaging/listPackaging.js b/modules/ticket/back/methods/packaging/listPackaging.js index 174630f29..c26bdbda6 100644 --- a/modules/ticket/back/methods/packaging/listPackaging.js +++ b/modules/ticket/back/methods/packaging/listPackaging.js @@ -7,13 +7,13 @@ module.exports = Self => { accessType: 'READ', accepts: [{ arg: 'filter', - type: 'Object', + type: 'object', required: false, description: 'Filter defining where and paginated data', http: {source: 'query'} }], returns: { - type: ['Object'], + type: ['object'], root: true }, http: { @@ -22,9 +22,14 @@ module.exports = Self => { } }); - Self.listPackaging = async filter => { - let conn = Self.dataSource.connector; - let stmt = new ParameterizedSQL( + Self.listPackaging = async(filter, options) => { + const conn = Self.dataSource.connector; + const myOptions = {}; + + if (typeof options == 'object') + Object.assign(myOptions, options); + + const stmt = new ParameterizedSQL( `SELECT name, itemFk, packagingFk FROM (SELECT i.name, i.id itemFk, p.id packagingFk FROM item i @@ -33,6 +38,7 @@ module.exports = Self => { ); stmt.merge(conn.makeSuffix(filter)); - return conn.executeStmt(stmt); + + return conn.executeStmt(stmt, myOptions); }; }; diff --git a/modules/ticket/back/methods/packaging/specs/listPackaging.spec.js b/modules/ticket/back/methods/packaging/specs/listPackaging.spec.js index 9633093f1..3d07b90f9 100644 --- a/modules/ticket/back/methods/packaging/specs/listPackaging.spec.js +++ b/modules/ticket/back/methods/packaging/specs/listPackaging.spec.js @@ -1,12 +1,22 @@ -const app = require('vn-loopback/server/server'); +const models = require('vn-loopback/server/server').models; describe('ticket listPackaging()', () => { it('should return the packaging', async() => { - let filter = {where: {packagingFk: 1}}; - let response = await app.models.Packaging.listPackaging(filter); + const tx = await models.Packaging.beginTransaction({}); - expect(response[0].name).toBeDefined(); - expect(response[0].name).toEqual('Container ammo box 1m'); + try { + const options = {transaction: tx}; + + const filter = {where: {packagingFk: 1}}; + const response = await models.Packaging.listPackaging(filter, options); + + expect(response[0].name).toEqual('Container ammo box 1m'); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } }); }); diff --git a/modules/ticket/back/methods/sale-tracking/listSaleTracking.js b/modules/ticket/back/methods/sale-tracking/listSaleTracking.js index 0bcb94c03..c0d63ef62 100644 --- a/modules/ticket/back/methods/sale-tracking/listSaleTracking.js +++ b/modules/ticket/back/methods/sale-tracking/listSaleTracking.js @@ -7,11 +7,11 @@ module.exports = Self => { accessType: 'READ', accepts: [{ arg: 'filter', - type: 'Object', + type: 'object', description: 'Filter defining where and paginated data' }], returns: { - type: ['Object'], + type: ['object'], root: true }, http: { @@ -20,8 +20,13 @@ module.exports = Self => { } }); - Self.listSaleTracking = async filter => { - let stmt = new ParameterizedSQL(` + Self.listSaleTracking = async(filter, options) => { + const myOptions = {}; + + if (typeof options == 'object') + Object.assign(myOptions, options); + + const stmt = new ParameterizedSQL(` SELECT st.id, s.ticketFk, @@ -41,9 +46,9 @@ module.exports = Self => { stmt.merge(Self.makeSuffix(filter)); - let trackings = await Self.rawStmt(stmt); + const trackings = await Self.rawStmt(stmt, myOptions); - let salesFilter = { + const salesFilter = { include: [ { relation: 'item' @@ -52,14 +57,14 @@ module.exports = Self => { where: {ticketFk: filter.where.ticketFk} }; - let sales = await Self.app.models.Sale.find(salesFilter); + const sales = await Self.app.models.Sale.find(salesFilter, myOptions); - trackings.forEach(tracking => { - sales.forEach(sale => { + for (const tracking of trackings) { + for (const sale of sales) { if (tracking.itemFk == sale.itemFk) tracking.item = sale.item(); - }); - }); + } + } return trackings; }; diff --git a/modules/ticket/back/methods/sale-tracking/specs/listSaleTracking.spec.js b/modules/ticket/back/methods/sale-tracking/specs/listSaleTracking.spec.js index 7b19f45bb..d51c56874 100644 --- a/modules/ticket/back/methods/sale-tracking/specs/listSaleTracking.spec.js +++ b/modules/ticket/back/methods/sale-tracking/specs/listSaleTracking.spec.js @@ -1,17 +1,39 @@ -const app = require('vn-loopback/server/server'); +const models = require('vn-loopback/server/server').models; describe('ticket listSaleTracking()', () => { it('should call the listSaleTracking method and return the response', async() => { - let filter = {where: {ticketFk: 1}}; - let result = await app.models.SaleTracking.listSaleTracking(filter); + const tx = await models.SaleTracking.beginTransaction({}); - expect(result.length).toEqual(4); + try { + const options = {transaction: tx}; + + const filter = {where: {ticketFk: 1}}; + const result = await models.SaleTracking.listSaleTracking(filter, options); + + expect(result.length).toEqual(4); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } }); it(`should call the listSaleTracking method and return zero if doesn't have lines`, async() => { - let filter = {where: {ticketFk: 2}}; - let result = await app.models.SaleTracking.listSaleTracking(filter); + const tx = await models.SaleTracking.beginTransaction({}); - expect(result.length).toEqual(0); + try { + const options = {transaction: tx}; + + const filter = {where: {ticketFk: 2}}; + const result = await models.SaleTracking.listSaleTracking(filter, options); + + expect(result.length).toEqual(0); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } }); }); diff --git a/modules/ticket/back/methods/state/editableStates.js b/modules/ticket/back/methods/state/editableStates.js index c1cbda799..2c90ac43b 100644 --- a/modules/ticket/back/methods/state/editableStates.js +++ b/modules/ticket/back/methods/state/editableStates.js @@ -1,4 +1,3 @@ - module.exports = Self => { Self.remoteMethodCtx('editableStates', { description: 'Gets the editable states according the user role ', @@ -8,7 +7,7 @@ module.exports = Self => { type: 'object' }, returns: { - type: ['Object'], + type: ['object'], root: true }, http: { @@ -17,14 +16,18 @@ module.exports = Self => { } }); - Self.editableStates = async(ctx, filter) => { - let userId = ctx.req.accessToken.userId; - let models = Self.app.models; - let statesList = await models.State.find({where: filter.where}); + Self.editableStates = async(ctx, filter, options) => { + const models = Self.app.models; + const userId = ctx.req.accessToken.userId; + const myOptions = {}; - let isProduction = await models.Account.hasRole(userId, 'production'); - let isSalesPerson = await models.Account.hasRole(userId, 'salesPerson'); - let isAdministrative = await models.Account.hasRole(userId, 'administrative'); + if (typeof options == 'object') + Object.assign(myOptions, options); + + let statesList = await models.State.find({where: filter.where}, myOptions); + const isProduction = await models.Account.hasRole(userId, 'production', myOptions); + const isSalesPerson = await models.Account.hasRole(userId, 'salesPerson', myOptions); + const isAdministrative = await models.Account.hasRole(userId, 'administrative', myOptions); if (isProduction || isAdministrative) return statesList; diff --git a/modules/ticket/back/methods/state/specs/editableState.spec.js b/modules/ticket/back/methods/state/specs/editableState.spec.js index fc0b80494..c75242be0 100644 --- a/modules/ticket/back/methods/state/specs/editableState.spec.js +++ b/modules/ticket/back/methods/state/specs/editableState.spec.js @@ -1,34 +1,73 @@ -const app = require('vn-loopback/server/server'); +const models = require('vn-loopback/server/server').models; describe('ticket editableStates()', () => { const filter = {where: {name: {like: '%%'}}}; it('should return the expected state for the given role', async() => { - const productionRole = 49; - const ctx = {req: {accessToken: {userId: productionRole}}}; + const tx = await models.State.beginTransaction({}); - let result = await app.models.State.editableStates(ctx, filter); - let deliveredState = result.some(state => state.code == 'DELIVERED'); + try { + const options = {transaction: tx}; - expect(deliveredState).toBeTruthy(); + const productionRole = 49; + const ctx = {req: {accessToken: {userId: productionRole}}}; + + const editableStates = await models.State.editableStates(ctx, filter, options); + + const deliveredState = editableStates.some(state => state.code == 'DELIVERED'); + + expect(deliveredState).toBeTruthy(); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } }); it(`should return the expected states by a specific role`, async() => { - const productionRole = 18; - const ctx = {req: {accessToken: {userId: productionRole}}}; - let result = await app.models.State.editableStates(ctx, filter); - let deliveredState = result.some(state => state.code == 'DELIVERED'); - let pickerDesignedState = result.some(state => state.code == 'PICKER_DESIGNED'); + const tx = await models.State.beginTransaction({}); - expect(deliveredState).toBeFalsy(); - expect(pickerDesignedState).toBeTruthy(); + try { + const options = {transaction: tx}; + + const productionRole = 18; + const ctx = {req: {accessToken: {userId: productionRole}}}; + + const editableStates = await models.State.editableStates(ctx, filter, options); + + const deliveredState = editableStates.some(state => state.code == 'DELIVERED'); + + const pickerDesignedState = editableStates.some(state => state.code == 'PICKER_DESIGNED'); + + expect(deliveredState).toBeFalsy(); + expect(pickerDesignedState).toBeTruthy(); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } }); it(`should return again the expected state by a specific role`, async() => { - const employeeRole = 1; - const ctx = {req: {accessToken: {userId: employeeRole}}}; - let result = await app.models.State.editableStates(ctx, filter); - let pickerDesignedState = result.some(state => state.code == 'PICKER_DESIGNED'); + const tx = await models.State.beginTransaction({}); - expect(pickerDesignedState).toBeTruthy(); + try { + const options = {transaction: tx}; + + const employeeRole = 1; + const ctx = {req: {accessToken: {userId: employeeRole}}}; + + const editableStates = await models.State.editableStates(ctx, filter, options); + + const pickerDesignedState = editableStates.some(state => state.code == 'PICKER_DESIGNED'); + + expect(pickerDesignedState).toBeTruthy(); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } }); }); diff --git a/modules/ticket/back/methods/ticket-dms/removeFile.js b/modules/ticket/back/methods/ticket-dms/removeFile.js index 52a0c524f..f48dc7fef 100644 --- a/modules/ticket/back/methods/ticket-dms/removeFile.js +++ b/modules/ticket/back/methods/ticket-dms/removeFile.js @@ -4,12 +4,12 @@ module.exports = Self => { accessType: 'WRITE', accepts: { arg: 'id', - type: 'Number', + type: 'number', description: 'The document id', http: {source: 'path'} }, returns: { - type: 'Object', + type: 'object', root: true }, http: { @@ -18,16 +18,36 @@ module.exports = Self => { } }); - Self.removeFile = async(ctx, id) => { + Self.removeFile = async(ctx, id, options) => { const models = Self.app.models; - const targetTicketDms = await models.TicketDms.findById(id); - const targetDms = await models.Dms.findById(targetTicketDms.dmsFk); - const trashDmsType = await models.DmsType.findOne({where: {code: 'trash'}}); + const myOptions = {}; + let tx; - await models.Dms.removeFile(ctx, targetTicketDms.dmsFk); - await targetTicketDms.destroy(); + if (typeof options == 'object') + Object.assign(myOptions, options); - return targetDms.updateAttribute('dmsTypeFk', trashDmsType.id); + if (!myOptions.transaction) { + tx = await Self.beginTransaction({}); + myOptions.transaction = tx; + } + + try { + const targetTicketDms = await models.TicketDms.findById(id, null, myOptions); + const targetDms = await models.Dms.findById(targetTicketDms.dmsFk, null, myOptions); + const trashDmsType = await models.DmsType.findOne({where: {code: 'trash'}}, myOptions); + + await models.Dms.removeFile(ctx, targetTicketDms.dmsFk, myOptions); + await targetTicketDms.destroy(myOptions); + + await targetDms.updateAttribute('dmsTypeFk', trashDmsType.id, myOptions); + + if (tx) await tx.commit(); + + return targetDms; + } catch (e) { + if (tx) await tx.rollback(); + throw e; + } }; }; diff --git a/modules/ticket/back/methods/ticket-dms/specs/removeFile.spec.js b/modules/ticket/back/methods/ticket-dms/specs/removeFile.spec.js index 1cd3b16cb..9296984c3 100644 --- a/modules/ticket/back/methods/ticket-dms/specs/removeFile.spec.js +++ b/modules/ticket/back/methods/ticket-dms/specs/removeFile.spec.js @@ -1,18 +1,25 @@ -const app = require('vn-loopback/server/server'); +const models = require('vn-loopback/server/server').models; describe('TicketDms removeFile()', () => { const ticketDmsId = 1; it(`should return an error for a user without enough privileges`, async() => { - let clientId = 1101; - let ctx = {req: {accessToken: {userId: clientId}}}; + const tx = await models.TicketDms.beginTransaction({}); let error; - await app.models.TicketDms.removeFile(ctx, ticketDmsId).catch(e => { - error = e; - }).finally(() => { - expect(error.message).toEqual(`You don't have enough privileges`); - }); + try { + const options = {transaction: tx}; - expect(error).toBeDefined(); + const clientId = 1101; + const ctx = {req: {accessToken: {userId: clientId}}}; + + await models.TicketDms.removeFile(ctx, ticketDmsId, options); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + error = e; + } + + expect(error.message).toEqual(`You don't have enough privileges`); }); }); diff --git a/modules/ticket/back/methods/ticket-request/confirm.js b/modules/ticket/back/methods/ticket-request/confirm.js index ce4bfdccb..f7f7fbc2a 100644 --- a/modules/ticket/back/methods/ticket-request/confirm.js +++ b/modules/ticket/back/methods/ticket-request/confirm.js @@ -6,22 +6,22 @@ module.exports = Self => { accessType: 'WRITE', accepts: [{ arg: 'id', - type: 'Integer', + type: 'number', required: true, description: 'The request ID', }, { arg: 'itemFk', - type: 'Integer', + type: 'number', required: true, description: 'The requested item ID', }, { arg: 'quantity', - type: 'Integer', + type: 'number', required: true, description: 'The requested item quantity', }], returns: { - type: 'Object', + type: 'object', root: true }, http: { @@ -30,25 +30,37 @@ module.exports = Self => { } }); - Self.confirm = async ctx => { + Self.confirm = async(ctx, options) => { const userId = ctx.req.accessToken.userId; const models = Self.app.models; - const tx = await Self.beginTransaction({}); const $t = ctx.req.__; // $translate - let sale; + const myOptions = {}; + let tx; + + if (typeof options == 'object') + Object.assign(myOptions, options); + + if (!myOptions.transaction) { + tx = await Self.beginTransaction({}); + myOptions.transaction = tx; + } try { - let options = {transaction: tx}; - - let item = await models.Item.findById(ctx.args.itemFk, null, options); + const item = await models.Item.findById(ctx.args.itemFk, null, myOptions); if (!item) throw new UserError(`That item doesn't exists`); - let request = await models.TicketRequest.findById(ctx.args.id, { + const request = await models.TicketRequest.findById(ctx.args.id, { include: {relation: 'ticket'} - }, options); + }, myOptions); + + const itemStock = await models.Item.getVisibleAvailable( + ctx.args.itemFk, + request.ticket().warehouseFk, + request.ticket().shipped, + myOptions + ); - const itemStock = await models.Item.getVisibleAvailable(ctx.args.itemFk, request.ticket().warehouseFk, request.ticket().shipped); const isAvailable = itemStock.available > 0; if (!isAvailable) @@ -57,23 +69,24 @@ module.exports = Self => { if (request.saleFk) throw new UserError(`This request already contains a sale`); - sale = await models.Sale.create({ + const sale = await models.Sale.create({ ticketFk: request.ticketFk, itemFk: ctx.args.itemFk, quantity: ctx.args.quantity, concept: item.name - }, options); + }, myOptions); await request.updateAttributes({ saleFk: sale.id, itemFk: sale.itemFk, isOk: true - }, options); + }, myOptions); - query = `CALL vn.sale_calculateComponent(?, NULL)`; - await Self.rawSql(query, [sale.id], options); + const query = `CALL vn.sale_calculateComponent(?, NULL)`; + await Self.rawSql(query, [sale.id], myOptions); const origin = ctx.req.headers.origin; const requesterId = request.requesterFk; + const message = $t('Bought units from buy request', { quantity: sale.quantity, concept: sale.concept, @@ -82,10 +95,9 @@ module.exports = Self => { url: `${origin}/#!/ticket/${sale.ticketFk}/summary`, urlItem: `${origin}/#!/item/${sale.itemFk}/summary` }); - await models.Chat.sendCheckingPresence(ctx, requesterId, message); + await models.Chat.sendCheckingPresence(ctx, requesterId, message, myOptions); - // log - let logRecord = { + const logRecord = { originFk: sale.ticketFk, userFk: userId, action: 'update', @@ -99,14 +111,14 @@ module.exports = Self => { } }; - await Self.app.models.TicketLog.create(logRecord); + await Self.app.models.TicketLog.create(logRecord, myOptions); - await tx.commit(); + if (tx) await tx.commit(); return sale; - } catch (error) { - await tx.rollback(); - throw error; + } catch (e) { + if (tx) await tx.rollback(); + throw e; } }; }; diff --git a/modules/ticket/back/methods/ticket-request/deny.js b/modules/ticket/back/methods/ticket-request/deny.js index e663ef1bc..5b79a57cb 100644 --- a/modules/ticket/back/methods/ticket-request/deny.js +++ b/modules/ticket/back/methods/ticket-request/deny.js @@ -4,7 +4,7 @@ module.exports = Self => { accessType: 'WRITE', accepts: [{ arg: 'id', - type: 'Integer', + type: 'number', required: true, description: 'The request ID', }, { @@ -23,17 +23,37 @@ module.exports = Self => { } }); - Self.deny = async ctx => { - let userId = ctx.req.accessToken.userId; - let worker = await Self.app.models.Worker.findOne({where: {userFk: userId}}); + Self.deny = async(ctx, options) => { + const myOptions = {}; + let tx; - let params = { - isOk: false, - attenderFk: worker.id, - response: ctx.args.observation, - }; + if (typeof options == 'object') + Object.assign(myOptions, options); - let request = await Self.app.models.TicketRequest.findById(ctx.args.id); - return request.updateAttributes(params); + if (!myOptions.transaction) { + tx = await Self.beginTransaction({}); + myOptions.transaction = tx; + } + + try { + const userId = ctx.req.accessToken.userId; + const worker = await Self.app.models.Worker.findOne({where: {userFk: userId}}, myOptions); + + const params = { + isOk: false, + attenderFk: worker.id, + response: ctx.args.observation, + }; + + const request = await Self.app.models.TicketRequest.findById(ctx.args.id, null, myOptions); + await request.updateAttributes(params, myOptions); + + if (tx) await tx.commit(); + + return request; + } catch (e) { + if (tx) await tx.rollback(); + throw e; + } }; }; diff --git a/modules/ticket/back/methods/ticket-request/filter.js b/modules/ticket/back/methods/ticket-request/filter.js index 9b864f632..62c58ea95 100644 --- a/modules/ticket/back/methods/ticket-request/filter.js +++ b/modules/ticket/back/methods/ticket-request/filter.js @@ -68,9 +68,13 @@ module.exports = Self => { } }); - Self.filter = async(ctx, filter) => { - let conn = Self.dataSource.connector; - let userId = ctx.req.accessToken.userId; + Self.filter = async(ctx, filter, options) => { + const conn = Self.dataSource.connector; + const userId = ctx.req.accessToken.userId; + const myOptions = {}; + + if (typeof options == 'object') + Object.assign(myOptions, options); if (ctx.args.mine) ctx.args.attenderFk = userId; @@ -111,9 +115,7 @@ module.exports = Self => { filter = mergeFilters(filter, {where}); - let stmt; - - stmt = new ParameterizedSQL( + const stmt = new ParameterizedSQL( `SELECT tr.id, tr.ticketFk, @@ -149,8 +151,6 @@ module.exports = Self => { LEFT JOIN account.user ua ON ua.id = wka.userFk`); stmt.merge(conn.makeSuffix(filter)); - let result = await conn.executeStmt(stmt); - - return result; + return conn.executeStmt(stmt, myOptions); }; }; diff --git a/modules/ticket/back/methods/ticket-request/specs/confirm.spec.js b/modules/ticket/back/methods/ticket-request/specs/confirm.spec.js index 2068fdfdd..49413cf44 100644 --- a/modules/ticket/back/methods/ticket-request/specs/confirm.spec.js +++ b/modules/ticket/back/methods/ticket-request/specs/confirm.spec.js @@ -1,4 +1,4 @@ -const app = require('vn-loopback/server/server'); +const models = require('vn-loopback/server/server').models; describe('ticket-request confirm()', () => { let ctx = { @@ -12,74 +12,89 @@ describe('ticket-request confirm()', () => { }; it(`should throw an error if the item doesn't exist`, async() => { - ctx.args = {itemFk: 999}; + const tx = await models.TicketRequest.beginTransaction({}); let error; try { - await app.models.TicketRequest.confirm(ctx); - } catch (err) { - error = err; + const options = {transaction: tx}; + + ctx.args = {itemFk: 999}; + await models.TicketRequest.confirm(ctx, options); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + error = e; } expect(error.message).toEqual(`That item doesn't exists`); }); it('should throw an error if the item is not available', async() => { - const requestId = 5; - const itemId = 4; - const quantity = 99999; - - ctx.args = { - itemFk: itemId, - id: requestId, - quantity: quantity - }; + const tx = await models.TicketRequest.beginTransaction({}); let error; - try { - await app.models.TicketRequest.confirm(ctx); - } catch (err) { - error = err; + const options = {transaction: tx}; + + const requestId = 5; + const itemId = 4; + const quantity = 99999; + + ctx.args = { + itemFk: itemId, + id: requestId, + quantity: quantity + }; + + await models.TicketRequest.confirm(ctx, options); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + error = e; } expect(error.message).toEqual(`This item is not available`); }); it(`should throw if there's a sale id`, async() => { - const requestId = 4; - const itemId = 1; - const quantity = 10; - - ctx.args = { - itemFk: itemId, - id: requestId, - quantity: quantity - }; - - const request = await app.models.TicketRequest.findById(requestId); - - expect(request.saleFk).toBeNull(); - - await request.updateAttributes({saleFk: 2}); - - ctx.args = { - itemFk: itemId, - id: requestId, - quantity: quantity - }; + const tx = await models.TicketRequest.beginTransaction({}); let error; - try { - await app.models.TicketRequest.confirm(ctx); - } catch (err) { - error = err; + const options = {transaction: tx}; + + const requestId = 4; + const itemId = 1; + const quantity = 10; + + ctx.args = { + itemFk: itemId, + id: requestId, + quantity: quantity + }; + + const request = await models.TicketRequest.findById(requestId, null, options); + + expect(request.saleFk).toBeNull(); + + await request.updateAttributes({saleFk: 2}, options); + + ctx.args = { + itemFk: itemId, + id: requestId, + quantity: quantity + }; + + await models.TicketRequest.confirm(ctx, options); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + error = e; } expect(error.message).toEqual(`This request already contains a sale`); - - // restores - await request.updateAttributes({saleFk: null}); }); }); diff --git a/modules/ticket/back/methods/ticket-request/specs/deny.spec.js b/modules/ticket/back/methods/ticket-request/specs/deny.spec.js index 04152fa21..523c5f065 100644 --- a/modules/ticket/back/methods/ticket-request/specs/deny.spec.js +++ b/modules/ticket/back/methods/ticket-request/specs/deny.spec.js @@ -1,25 +1,22 @@ -const app = require('vn-loopback/server/server'); +const models = require('vn-loopback/server/server').models; describe('ticket-request deny()', () => { - let request; - afterAll(async done => { - let params = { - isOk: null, - attenderFk: request.attenderFk, - response: null, - }; + it('should return the dinied ticket request', async() => { + const tx = await models.TicketRequest.beginTransaction({}); - await request.updateAttributes(params); - done(); - }); + try { + const options = {transaction: tx}; - it('should return all ticket requests', async() => { - let ctx = {req: {accessToken: {userId: 9}}, args: {id: 4, observation: 'my observation'}}; + const ctx = {req: {accessToken: {userId: 9}}, args: {id: 4, observation: 'my observation'}}; - request = await app.models.TicketRequest.findById(ctx.args.id); + const result = await models.TicketRequest.deny(ctx, options); - let result = await app.models.TicketRequest.deny(ctx); + expect(result.id).toEqual(4); - expect(result.id).toEqual(4); + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } }); }); diff --git a/modules/ticket/back/methods/ticket-request/specs/filter.spec.js b/modules/ticket/back/methods/ticket-request/specs/filter.spec.js index 82bdfbd38..ae004a024 100644 --- a/modules/ticket/back/methods/ticket-request/specs/filter.spec.js +++ b/modules/ticket/back/methods/ticket-request/specs/filter.spec.js @@ -1,85 +1,184 @@ -const app = require('vn-loopback/server/server'); +const models = require('vn-loopback/server/server').models; describe('ticket-request filter()', () => { const userId = 9; let ctx = {req: {accessToken: {userId: userId}}}; it('should now return all ticket requests', async() => { - ctx.args = {}; + const tx = await models.TicketRequest.beginTransaction({}); - const result = await app.models.TicketRequest.filter(ctx); + try { + const options = {transaction: tx}; - expect(result.length).toEqual(3); + ctx.args = {}; + + const result = await models.TicketRequest.filter(ctx, options); + + expect(result.length).toEqual(3); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } }); it('should return the ticket request matching a generic search value which is the ticket ID', async() => { - ctx.args = {search: 11}; + const tx = await models.TicketRequest.beginTransaction({}); - const result = await app.models.TicketRequest.filter(ctx); - const requestId = result[0].id; + try { + const options = {transaction: tx}; - expect(requestId).toEqual(4); + ctx.args = {search: 11}; + + const result = await models.TicketRequest.filter(ctx, options); + const requestId = result[0].id; + + expect(requestId).toEqual(4); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } }); it('should return the ticket request matching a generic search value which is the client address alias', async() => { - ctx.args = {search: 'NY roofs'}; + const tx = await models.TicketRequest.beginTransaction({}); - const result = await app.models.TicketRequest.filter(ctx); - const requestId = result[0].id; + try { + const options = {transaction: tx}; - expect(requestId).toEqual(4); + ctx.args = {search: 'NY roofs'}; + + const result = await models.TicketRequest.filter(ctx, options); + const requestId = result[0].id; + + expect(requestId).toEqual(4); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } }); it('should return the ticket request matching the ticket ID', async() => { - ctx.args = {ticketFk: 11}; - const result = await app.models.TicketRequest.filter(ctx); - const requestId = result[0].id; + const tx = await models.TicketRequest.beginTransaction({}); - expect(requestId).toEqual(4); + try { + const options = {transaction: tx}; + + ctx.args = {ticketFk: 11}; + const result = await models.TicketRequest.filter(ctx, options); + const requestId = result[0].id; + + expect(requestId).toEqual(4); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } }); it('should return the ticket request matching the atender ID', async() => { - ctx.args = {attenderFk: 35}; + const tx = await models.TicketRequest.beginTransaction({}); - const result = await app.models.TicketRequest.filter(ctx); - const requestId = result[0].id; + try { + const options = {transaction: tx}; - expect(requestId).toEqual(3); + ctx.args = {attenderFk: 35}; + + const result = await models.TicketRequest.filter(ctx, options); + const requestId = result[0].id; + + expect(requestId).toEqual(3); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } }); it('should return the ticket request matching the isOk triple-state', async() => { - ctx.args = {isOk: null}; + const tx = await models.TicketRequest.beginTransaction({}); - const result = await app.models.TicketRequest.filter(ctx); - const requestId = result[0].id; + try { + const options = {transaction: tx}; - expect(requestId).toEqual(3); + ctx.args = {isOk: null}; + + const result = await models.TicketRequest.filter(ctx, options); + const requestId = result[0].id; + + expect(requestId).toEqual(3); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } }); it('should return the ticket request matching the client ID', async() => { - ctx.args = {clientFk: 1102}; + const tx = await models.TicketRequest.beginTransaction({}); - const result = await app.models.TicketRequest.filter(ctx); - const requestId = result[0].id; + try { + const options = {transaction: tx}; - expect(requestId).toEqual(4); + ctx.args = {clientFk: 1102}; + + const result = await models.TicketRequest.filter(ctx, options); + const requestId = result[0].id; + + expect(requestId).toEqual(4); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } }); it('should return the ticket request matching the warehouse ID', async() => { - ctx.args = {warehouse: 1}; + const tx = await models.TicketRequest.beginTransaction({}); - const result = await app.models.TicketRequest.filter(ctx, {order: 'id'}); - const requestId = result[0].id; + try { + const options = {transaction: tx}; - expect(requestId).toEqual(3); + ctx.args = {warehouse: 1}; + + const result = await models.TicketRequest.filter(ctx, {order: 'id'}, options); + const requestId = result[0].id; + + expect(requestId).toEqual(3); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } }); it('should return the ticket request matching the salesPerson ID', async() => { - ctx.args = {salesPersonFk: 18}; + const tx = await models.TicketRequest.beginTransaction({}); - const result = await app.models.TicketRequest.filter(ctx); - const requestId = result[0].id; + try { + const options = {transaction: tx}; - expect(requestId).toEqual(3); + ctx.args = {salesPersonFk: 18}; + + const result = await models.TicketRequest.filter(ctx, options); + const requestId = result[0].id; + + expect(requestId).toEqual(3); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } }); }); diff --git a/modules/ticket/back/methods/ticket-tracking/setDelivered.js b/modules/ticket/back/methods/ticket-tracking/setDelivered.js index 509f5b446..bd6e32dcf 100644 --- a/modules/ticket/back/methods/ticket-tracking/setDelivered.js +++ b/modules/ticket/back/methods/ticket-tracking/setDelivered.js @@ -6,13 +6,13 @@ module.exports = Self => { { arg: 'ticketIds', description: 'the array of ticket ids to set as delivered', - type: ['Number'], + type: ['number'], required: true, http: {source: 'body'} } ], returns: { - type: 'Object', + type: 'object', root: true }, http: { @@ -21,30 +21,47 @@ module.exports = Self => { } }); - Self.setDelivered = async(ctx, ticketIds) => { - let userId = ctx.req.accessToken.userId; - let models = Self.app.models; + Self.setDelivered = async(ctx, ticketIds, options) => { + const userId = ctx.req.accessToken.userId; + const models = Self.app.models; + const myOptions = {}; + let tx; - let state = await models.State.findOne({ - where: { - code: 'delivered' - }, - fields: ['id', 'name', 'alertLevel', 'code'] - }); + if (typeof options == 'object') + Object.assign(myOptions, options); - let worker = await models.Worker.findOne({where: {userFk: userId}}); - - let promises = []; - for (let id of ticketIds) { - let promise = models.TicketTracking.changeState(ctx, { - stateFk: state.id, - workerFk: worker.id, - ticketFk: id - }); - promises.push(promise); + if (!myOptions.transaction) { + tx = await Self.beginTransaction({}); + myOptions.transaction = tx; } - await Promise.all(promises); - return state; + try { + const state = await models.State.findOne({ + where: { + code: 'delivered' + }, + fields: ['id', 'name', 'alertLevel', 'code'] + }, myOptions); + + const worker = await models.Worker.findOne({where: {userFk: userId}}, myOptions); + + const promises = []; + for (const id of ticketIds) { + const promise = models.TicketTracking.changeState(ctx, { + stateFk: state.id, + workerFk: worker.id, + ticketFk: id + }, myOptions); + promises.push(promise); + } + await Promise.all(promises); + + if (tx) await tx.commit(); + + return state; + } catch (e) { + if (tx) await tx.rollback(); + throw e; + } }; }; 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 042ae0a1f..80c6055e5 100644 --- a/modules/ticket/back/methods/ticket-tracking/specs/setDelivered.spec.js +++ b/modules/ticket/back/methods/ticket-tracking/specs/setDelivered.spec.js @@ -1,4 +1,4 @@ -const app = require('vn-loopback/server/server'); +const models = require('vn-loopback/server/server').models; const LoopBackContext = require('loopback-context'); describe('ticket setDelivered()', () => { @@ -7,50 +7,41 @@ describe('ticket setDelivered()', () => { accessToken: {userId: userId}, }; - let ticketOne; - let ticketTwo; - beforeAll(async done => { spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ active: activeCtx }); - try { - let originalTicketOne = await app.models.Ticket.findById(8); - let originalTicketTwo = await app.models.Ticket.findById(10); - - originalTicketOne.id = null; - originalTicketTwo.id = null; - - ticketOne = await app.models.Ticket.create(originalTicketOne); - ticketTwo = await app.models.Ticket.create(originalTicketTwo); - } catch (error) { - console.error(error); - } - - done(); - }); - - afterAll(async done => { - try { - await app.models.Ticket.destroyById(ticketOne.id); - await app.models.Ticket.destroyById(ticketTwo.id); - } catch (error) { - console.error(error); - } - done(); }); it('should return the state which has been applied to the given tickets', async() => { - let ctx = {req: {accessToken: {userId: 49}}}; - let delivered = await app.models.State.findOne({where: {code: 'delivered'}, fields: ['id']}); + const tx = await models.TicketTracking.beginTransaction({}); - let params = [ticketOne.id, ticketTwo.id]; - let state = await app.models.TicketTracking.setDelivered(ctx, params); + try { + const options = {transaction: tx}; - expect(state.id).toEqual(delivered.id); + const ctx = {req: {accessToken: {userId: 49}}}; - // restores - await app.models.TicketTracking.destroyById(state.id); + const originalTicketOne = await models.Ticket.findById(8, null, options); + const originalTicketTwo = await models.Ticket.findById(10, null, options); + + originalTicketOne.id = null; + originalTicketTwo.id = null; + + const ticketOne = await models.Ticket.create(originalTicketOne, options); + const ticketTwo = await models.Ticket.create(originalTicketTwo, options); + + const delivered = await models.State.findOne({where: {code: 'delivered'}, fields: ['id']}, options); + + const params = [ticketOne.id, ticketTwo.id]; + const state = await models.TicketTracking.setDelivered(ctx, params, options); + + expect(state.id).toEqual(delivered.id); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } }); }); diff --git a/modules/ticket/back/methods/ticket-weekly/filter.js b/modules/ticket/back/methods/ticket-weekly/filter.js index ef00aff9b..0bf92d542 100644 --- a/modules/ticket/back/methods/ticket-weekly/filter.js +++ b/modules/ticket/back/methods/ticket-weekly/filter.js @@ -10,18 +10,18 @@ module.exports = Self => { accepts: [ { arg: 'filter', - type: 'Object', + type: 'object', description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string', http: {source: 'query'} }, { arg: 'search', - type: 'String', + type: 'string', description: `If it's and integer searchs by id, otherwise it searchs by client id`, http: {source: 'query'} } ], returns: { - type: ['Object'], + type: ['object'], root: true }, http: { @@ -30,10 +30,14 @@ module.exports = Self => { } }); - Self.filter = async(ctx, filter) => { - let conn = Self.dataSource.connector; + Self.filter = async(ctx, filter, options) => { + const conn = Self.dataSource.connector; + const myOptions = {}; - let where = buildFilter(ctx.args, (param, value) => { + if (typeof options == 'object') + Object.assign(myOptions, options); + + const where = buildFilter(ctx.args, (param, value) => { switch (param) { case 'search': return {or: [ @@ -46,10 +50,9 @@ module.exports = Self => { filter = mergeFilters(ctx.args.filter, {where}); - let stmts = []; - let stmt; + const stmts = []; - stmt = new ParameterizedSQL( + const stmt = new ParameterizedSQL( `SELECT t.id AS ticketFk, c.id AS clientFk, c.name AS clientName, tw.weekDay, wh.name AS warehouseName, u.id AS workerFk, u.name AS userName, u.nickName, tw.agencyModeFk FROM ticketWeekly tw @@ -60,10 +63,10 @@ module.exports = Self => { ); stmt.merge(conn.makeSuffix(filter)); - let itemsIndex = stmts.push(stmt) - 1; + const itemsIndex = stmts.push(stmt) - 1; - let sql = ParameterizedSQL.join(stmts, ';'); - let result = await conn.executeStmt(sql); + const sql = ParameterizedSQL.join(stmts, ';'); + const result = await conn.executeStmt(sql, myOptions); return itemsIndex === 0 ? result : result[itemsIndex]; }; }; diff --git a/modules/ticket/back/methods/ticket-weekly/specs/filter.spec.js b/modules/ticket/back/methods/ticket-weekly/specs/filter.spec.js index 690fa669b..411bbe014 100644 --- a/modules/ticket/back/methods/ticket-weekly/specs/filter.spec.js +++ b/modules/ticket/back/methods/ticket-weekly/specs/filter.spec.js @@ -1,43 +1,89 @@ -const app = require('vn-loopback/server/server'); +const models = require('vn-loopback/server/server').models; describe('ticket-weekly filter()', () => { const authUserId = 9; it('should all return the tickets matching the filter', async() => { - const filter = {order: 't.id ASC'}; - const ctx = {req: {accessToken: {userId: authUserId}}, args: {filter: filter}}; - const result = await app.models.TicketWeekly.filter(ctx); + const tx = await models.TicketWeekly.beginTransaction({}); - const firstRow = result[0]; + try { + const options = {transaction: tx}; - expect(firstRow.ticketFk).toEqual(1); - expect(result.length).toEqual(5); + const filter = {order: 't.id ASC'}; + + const ctx = {req: {accessToken: {userId: authUserId}}, args: {filter: filter}}; + + const result = await models.TicketWeekly.filter(ctx, null, options); + + const firstRow = result[0]; + + expect(firstRow.ticketFk).toEqual(1); + expect(result.length).toEqual(5); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } }); it('should return the ticket with id one', async() => { - const ctx = {req: {accessToken: {userId: authUserId}}, args: {search: 2}}; - const filter = {}; - const result = await app.models.TicketWeekly.filter(ctx, filter); - const firstRow = result[0]; + const tx = await models.TicketWeekly.beginTransaction({}); - expect(firstRow.ticketFk).toEqual(2); + try { + const options = {transaction: tx}; + + const ctx = {req: {accessToken: {userId: authUserId}}, args: {search: 2}}; + + const result = await models.TicketWeekly.filter(ctx, null, options); + const firstRow = result[0]; + + expect(firstRow.ticketFk).toEqual(2); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } }); it('should return the ticket matching the client name', async() => { - const ctx = {req: {accessToken: {userId: authUserId}}, args: {search: 'bruce'}}; - const filter = {}; - const result = await app.models.TicketWeekly.filter(ctx, filter); - const firstRow = result[0]; + const tx = await models.TicketWeekly.beginTransaction({}); - expect(firstRow.clientName).toEqual('Bruce Wayne'); + try { + const options = {transaction: tx}; + + const ctx = {req: {accessToken: {userId: authUserId}}, args: {search: 'bruce'}}; + + const result = await models.TicketWeekly.filter(ctx, null, options); + const firstRow = result[0]; + + expect(firstRow.clientName).toEqual('Bruce Wayne'); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } }); it('should return the ticket matching the client id', async() => { - const ctx = {req: {accessToken: {userId: authUserId}}, args: {search: 1101}}; - const filter = {}; - const result = await app.models.TicketWeekly.filter(ctx, filter); - const firstRow = result[0]; + const tx = await models.TicketWeekly.beginTransaction({}); - expect(firstRow.clientFk).toEqual(1101); - expect(firstRow.clientName).toEqual('Bruce Wayne'); + try { + const options = {transaction: tx}; + + const ctx = {req: {accessToken: {userId: authUserId}}, args: {search: 1101}}; + + const result = await models.TicketWeekly.filter(ctx, null, options); + const firstRow = result[0]; + + expect(firstRow.clientFk).toEqual(1101); + expect(firstRow.clientName).toEqual('Bruce Wayne'); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } }); }); From 82a14088d02892842740073d7decb9555f5d38fe Mon Sep 17 00:00:00 2001 From: joan Date: Thu, 7 Oct 2021 10:04:50 +0200 Subject: [PATCH 12/47] Added options to invoiceOut --- front/core/services/email.js | 2 +- front/core/services/report.js | 2 +- .../invoiceOut/front/descriptor/index.html | 35 +++++++++++---- modules/invoiceOut/front/descriptor/index.js | 16 +++---- .../invoiceOut/front/descriptor/locale/es.yml | 4 +- .../ticket/front/descriptor-menu/index.html | 45 ++++++++----------- modules/ticket/front/descriptor-menu/index.js | 12 ++--- .../front/descriptor-menu/locale/es.yml | 8 ++-- 8 files changed, 67 insertions(+), 57 deletions(-) diff --git a/front/core/services/email.js b/front/core/services/email.js index 23eae0202..633b13a26 100644 --- a/front/core/services/email.js +++ b/front/core/services/email.js @@ -26,7 +26,7 @@ class Email { * @param {Object} params The email parameters * @return {Promise} Promise resolved when it's sent */ - sendCSV(template, params) { + sendCsv(template, params) { return this.$http.get(`csv/${template}/send`, {params}) .then(() => this.vnApp.showMessage(this.$t('Notification sent!'))); } diff --git a/front/core/services/report.js b/front/core/services/report.js index 12d33789f..c58a0ee0e 100644 --- a/front/core/services/report.js +++ b/front/core/services/report.js @@ -28,7 +28,7 @@ class Report { * @param {String} report The report name * @param {Object} params The report parameters */ - showCSV(report, params) { + showCsv(report, params) { params = Object.assign({ authorization: this.vnToken.token }, params); diff --git a/modules/invoiceOut/front/descriptor/index.html b/modules/invoiceOut/front/descriptor/index.html index 584983379..1210a69e5 100644 --- a/modules/invoiceOut/front/descriptor/index.html +++ b/modules/invoiceOut/front/descriptor/index.html @@ -18,7 +18,7 @@ Show as PDF Show as CSV @@ -34,12 +34,12 @@ Send PDF Send CSV @@ -136,15 +136,32 @@ message="You are going to regenerate the invoice PDF document"> - - + + Are you sure you want to send it? + ng-model="sendPdfConfirmation.data.email"> + + + + + + + + + + + + Are you sure you want to send it? + diff --git a/modules/invoiceOut/front/descriptor/index.js b/modules/invoiceOut/front/descriptor/index.js index 69fb3e503..399fd1ba7 100644 --- a/modules/invoiceOut/front/descriptor/index.js +++ b/modules/invoiceOut/front/descriptor/index.js @@ -22,7 +22,7 @@ class Controller extends Descriptor { .then(() => this.vnApp.showSuccess(this.$t('InvoiceOut booked'))); } - createInvoicePdf() { + createPdfInvoice() { const invoiceId = this.invoiceOut.id; return this.$http.post(`InvoiceOuts/${invoiceId}/createPdf`) .then(() => { @@ -60,14 +60,14 @@ class Controller extends Descriptor { .then(res => this.entity = res.data); } - showInvoiceCSV() { - this.vnReport.showCSV('invoice', { + showCsvInvoice() { + this.vnReport.showCsv('invoice', { recipientId: this.invoiceOut.client.id, invoiceId: this.id, }); } - sendInvoice($data) { + sendPdfInvoice($data) { return this.vnEmail.send('invoice', { recipientId: this.invoiceOut.client.id, recipient: $data.email, @@ -75,11 +75,11 @@ class Controller extends Descriptor { }); } - sendDeliveryNoteCSV($data) { - return this.vnEmail.sendCSV('delivery-note', { - recipientId: this.ticket.client.id, + sendCsvInvoice($data) { + return this.vnEmail.sendCsv('invoice', { + recipientId: this.invoiceOut.client.id, recipient: $data.email, - ticketId: this.id + invoiceId: this.id }); } } diff --git a/modules/invoiceOut/front/descriptor/locale/es.yml b/modules/invoiceOut/front/descriptor/locale/es.yml index 68ce7af84..3aff4840f 100644 --- a/modules/invoiceOut/front/descriptor/locale/es.yml +++ b/modules/invoiceOut/front/descriptor/locale/es.yml @@ -4,8 +4,8 @@ Client card: Ficha del cliente Invoice ticket list: Listado de tickets de la factura Show invoice...: Ver factura... Send invoice...: Enviar factura... -Send invoice PDF: Enviar factura en PDF -Send invoice CSV: Enviar factura en CSV +Send PDF invoice: Enviar factura en PDF +Send CSV invoice: Enviar factura en CSV Delete Invoice: Eliminar factura Clone Invoice: Clonar factura InvoiceOut deleted: Factura eliminada diff --git a/modules/ticket/front/descriptor-menu/index.html b/modules/ticket/front/descriptor-menu/index.html index b26246b3c..8b683b862 100644 --- a/modules/ticket/front/descriptor-menu/index.html +++ b/modules/ticket/front/descriptor-menu/index.html @@ -16,16 +16,16 @@ - Show Delivery Note + Show Delivery Note... Show as PDF Show as CSV @@ -35,17 +35,17 @@ - Send Delivery Note + Send Delivery Note... Send PDF Send CSV @@ -109,7 +109,7 @@ Make invoice - - - + + vn-id="sendPdfConfirmation" + on-accept="$ctrl.sendPdfDeliveryNote($data)" + message="Send PDF Delivery Note"> Are you sure you want to send it? + ng-model="sendPdfConfirmation.data.email"> @@ -189,15 +182,15 @@ - + + vn-id="sendCsvConfirmation" + on-accept="$ctrl.sendCsvDeliveryNote($data)" + message="Send CSV Delivery Note"> Are you sure you want to send it? + ng-model="sendCsvConfirmation.data.email"> @@ -271,8 +264,8 @@ diff --git a/modules/ticket/front/descriptor-menu/index.js b/modules/ticket/front/descriptor-menu/index.js index 8ef79f195..ca701f606 100644 --- a/modules/ticket/front/descriptor-menu/index.js +++ b/modules/ticket/front/descriptor-menu/index.js @@ -111,21 +111,21 @@ class Controller extends Section { }); } - showDeliveryNote() { + showPdfDeliveryNote() { this.vnReport.show('delivery-note', { recipientId: this.ticket.client.id, ticketId: this.id, }); } - showDeliveryNoteCSV() { - this.vnReport.showCSV('delivery-note', { + showCsvDeliveryNote() { + this.vnReport.showCsv('delivery-note', { recipientId: this.ticket.client.id, ticketId: this.id, }); } - sendDeliveryNote($data) { + sendPdfDeliveryNote($data) { return this.vnEmail.send('delivery-note', { recipientId: this.ticket.client.id, recipient: $data.email, @@ -133,8 +133,8 @@ class Controller extends Section { }); } - sendDeliveryNoteCSV($data) { - return this.vnEmail.sendCSV('delivery-note', { + sendCsvDeliveryNote($data) { + return this.vnEmail.sendCsv('delivery-note', { recipientId: this.ticket.client.id, recipient: $data.email, ticketId: this.id diff --git a/modules/ticket/front/descriptor-menu/locale/es.yml b/modules/ticket/front/descriptor-menu/locale/es.yml index aa6551808..1f4ee710c 100644 --- a/modules/ticket/front/descriptor-menu/locale/es.yml +++ b/modules/ticket/front/descriptor-menu/locale/es.yml @@ -1,8 +1,8 @@ -Show Delivery Note: Ver albarán -Send Delivery Note: Enviar albarán +Show Delivery Note...: Ver albarán... +Send Delivery Note...: Enviar albarán... Show as PDF: Ver como PDF Show as CSV: Ver como CSV Send PDF: Enviar PDF Send CSV: Enviar CSV -Send Delivery Note CSV: Enviar albarán en CSV -Send Delivery Note PDF: Enviar albarán en PDF \ No newline at end of file +Send CSV Delivery Note: Enviar albarán en CSV +Send PDF Delivery Note: Enviar albarán en PDF \ No newline at end of file From e6b60d73f1a97ad8bf20644f9e804e79a306c519 Mon Sep 17 00:00:00 2001 From: joan Date: Thu, 7 Oct 2021 13:36:23 +0200 Subject: [PATCH 13/47] Added unit tests --- modules/invoiceOut/front/descriptor/index.js | 46 ++++---- .../invoiceOut/front/descriptor/index.spec.js | 101 +++++++++++++++--- modules/ticket/front/descriptor-menu/index.js | 2 +- .../front/descriptor-menu/index.spec.js | 94 +++++++++++++--- 4 files changed, 188 insertions(+), 55 deletions(-) diff --git a/modules/invoiceOut/front/descriptor/index.js b/modules/invoiceOut/front/descriptor/index.js index 6685602a0..129fe16d1 100644 --- a/modules/invoiceOut/front/descriptor/index.js +++ b/modules/invoiceOut/front/descriptor/index.js @@ -14,29 +14,6 @@ class Controller extends Descriptor { return this.aclService.hasAny(['invoicing']); } - deleteInvoiceOut() { - return this.$http.post(`InvoiceOuts/${this.id}/delete`) - .then(() => this.$state.go('invoiceOut.index')) - .then(() => this.vnApp.showSuccess(this.$t('InvoiceOut deleted'))); - } - - bookInvoiceOut() { - return this.$http.post(`InvoiceOuts/${this.invoiceOut.ref}/book`) - .then(() => this.$state.reload()) - .then(() => this.vnApp.showSuccess(this.$t('InvoiceOut booked'))); - } - - createPdfInvoice() { - const invoiceId = this.invoiceOut.id; - return this.$http.post(`InvoiceOuts/${invoiceId}/createPdf`) - .then(() => this.reload()) - .then(() => { - const snackbarMessage = this.$t( - `The invoice PDF document has been regenerated`); - this.vnApp.showSuccess(snackbarMessage); - }); - } - get filter() { if (this.invoiceOut) return JSON.stringify({refFk: this.invoiceOut.ref}); @@ -76,6 +53,29 @@ class Controller extends Descriptor { // Prevents error when not defined } + deleteInvoiceOut() { + return this.$http.post(`InvoiceOuts/${this.id}/delete`) + .then(() => this.$state.go('invoiceOut.index')) + .then(() => this.vnApp.showSuccess(this.$t('InvoiceOut deleted'))); + } + + bookInvoiceOut() { + return this.$http.post(`InvoiceOuts/${this.invoiceOut.ref}/book`) + .then(() => this.$state.reload()) + .then(() => this.vnApp.showSuccess(this.$t('InvoiceOut booked'))); + } + + createPdfInvoice() { + const invoiceId = this.invoiceOut.id; + return this.$http.post(`InvoiceOuts/${invoiceId}/createPdf`) + .then(() => this.reload()) + .then(() => { + const snackbarMessage = this.$t( + `The invoice PDF document has been regenerated`); + this.vnApp.showSuccess(snackbarMessage); + }); + } + showCsvInvoice() { this.vnReport.showCsv('invoice', { recipientId: this.invoiceOut.client.id, diff --git a/modules/invoiceOut/front/descriptor/index.spec.js b/modules/invoiceOut/front/descriptor/index.spec.js index 0a5494b9a..12430d44d 100644 --- a/modules/invoiceOut/front/descriptor/index.spec.js +++ b/modules/invoiceOut/front/descriptor/index.spec.js @@ -3,30 +3,20 @@ import './index'; describe('vnInvoiceOutDescriptor', () => { let controller; let $httpBackend; - const invoiceOut = {id: 1}; + let $httpParamSerializer; + const invoiceOut = { + id: 1, + client: {id: 1101} + }; beforeEach(ngModule('invoiceOut')); - beforeEach(inject(($componentController, _$httpBackend_) => { + beforeEach(inject(($componentController, _$httpParamSerializer_, _$httpBackend_) => { $httpBackend = _$httpBackend_; + $httpParamSerializer = _$httpParamSerializer_; controller = $componentController('vnInvoiceOutDescriptor', {$element: null}); })); - describe('createInvoicePdf()', () => { - it('should make a query and show a success snackbar', () => { - jest.spyOn(controller.vnApp, 'showSuccess'); - - controller.invoiceOut = invoiceOut; - - $httpBackend.whenGET(`InvoiceOuts/${invoiceOut.id}`).respond(); - $httpBackend.expectPOST(`InvoiceOuts/${invoiceOut.id}/createPdf`).respond(); - controller.createInvoicePdf(); - $httpBackend.flush(); - - expect(controller.vnApp.showSuccess).toHaveBeenCalled(); - }); - }); - describe('loadData()', () => { it(`should perform a get query to store the invoice in data into the controller`, () => { const id = 1; @@ -39,4 +29,81 @@ describe('vnInvoiceOutDescriptor', () => { expect(controller.invoiceOut).toEqual(response); }); }); + + describe('createPdfInvoice()', () => { + it('should make a query to the createPdf() endpoint and show a success snackbar', () => { + jest.spyOn(controller.vnApp, 'showSuccess'); + + controller.invoiceOut = invoiceOut; + + $httpBackend.whenGET(`InvoiceOuts/${invoiceOut.id}`).respond(); + $httpBackend.expectPOST(`InvoiceOuts/${invoiceOut.id}/createPdf`).respond(); + controller.createPdfInvoice(); + $httpBackend.flush(); + + expect(controller.vnApp.showSuccess).toHaveBeenCalled(); + }); + }); + + describe('showCsvInvoice()', () => { + it('should make a query to the csv invoice download endpoint and show a message snackbar', () => { + jest.spyOn(window, 'open').mockReturnThis(); + + controller.invoiceOut = invoiceOut; + + const expectedParams = { + invoiceId: invoiceOut.id, + recipientId: invoiceOut.client.id + }; + const serializedParams = $httpParamSerializer(expectedParams); + const expectedPath = `api/csv/invoice/download?${serializedParams}`; + controller.showCsvInvoice(); + + expect(window.open).toHaveBeenCalledWith(expectedPath); + }); + }); + + describe('sendPdfInvoice()', () => { + it('should make a query to the email invoice endpoint and show a message snackbar', () => { + jest.spyOn(controller.vnApp, 'showMessage'); + + controller.invoiceOut = invoiceOut; + + const $data = {email: 'brucebanner@gothamcity.com'}; + const expectedParams = { + invoiceId: invoiceOut.id, + recipient: $data.email, + recipientId: invoiceOut.client.id + }; + const serializedParams = $httpParamSerializer(expectedParams); + + $httpBackend.expectGET(`email/invoice?${serializedParams}`).respond(); + controller.sendPdfInvoice($data); + $httpBackend.flush(); + + expect(controller.vnApp.showMessage).toHaveBeenCalled(); + }); + }); + + describe('sendCsvInvoice()', () => { + it('should make a query to the csv invoice send endpoint and show a message snackbar', () => { + jest.spyOn(controller.vnApp, 'showMessage'); + + controller.invoiceOut = invoiceOut; + + const $data = {email: 'brucebanner@gothamcity.com'}; + const expectedParams = { + invoiceId: invoiceOut.id, + recipient: $data.email, + recipientId: invoiceOut.client.id + }; + const serializedParams = $httpParamSerializer(expectedParams); + + $httpBackend.expectGET(`csv/invoice/send?${serializedParams}`).respond(); + controller.sendCsvInvoice($data); + $httpBackend.flush(); + + expect(controller.vnApp.showMessage).toHaveBeenCalled(); + }); + }); }); diff --git a/modules/ticket/front/descriptor-menu/index.js b/modules/ticket/front/descriptor-menu/index.js index 6292acbd8..142f44989 100644 --- a/modules/ticket/front/descriptor-menu/index.js +++ b/modules/ticket/front/descriptor-menu/index.js @@ -242,7 +242,7 @@ class Controller extends Section { .then(() => this.vnApp.showSuccess(this.$t('Ticket invoiced'))); } - createInvoicePdf() { + createPdfInvoice() { const invoiceId = this.ticket.invoiceOut.id; return this.$http.post(`InvoiceOuts/${invoiceId}/createPdf`) .then(() => this.reload()) diff --git a/modules/ticket/front/descriptor-menu/index.spec.js b/modules/ticket/front/descriptor-menu/index.spec.js index eabb77235..5413545fe 100644 --- a/modules/ticket/front/descriptor-menu/index.spec.js +++ b/modules/ticket/front/descriptor-menu/index.spec.js @@ -2,6 +2,7 @@ import './index.js'; describe('Ticket Component vnTicketDescriptorMenu', () => { let $httpBackend; + let $httpParamSerializer; let controller; let $state; @@ -25,8 +26,9 @@ describe('Ticket Component vnTicketDescriptorMenu', () => { beforeEach(ngModule('ticket')); - beforeEach(inject(($componentController, _$httpBackend_, _$state_) => { + beforeEach(inject(($componentController, _$httpBackend_, _$httpParamSerializer_, _$state_) => { $httpBackend = _$httpBackend_; + $httpParamSerializer = _$httpParamSerializer_; $state = _$state_; $state.params.id = 16; $state.getCurrentPath = () => [null, {state: {name: 'ticket'}}]; @@ -104,31 +106,33 @@ describe('Ticket Component vnTicketDescriptorMenu', () => { }); }); - describe('showDeliveryNote()', () => { + describe('showPdfDeliveryNote()', () => { it('should open a new window showing a delivery note PDF document', () => { - jest.spyOn(controller.vnReport, 'show'); + jest.spyOn(window, 'open').mockReturnThis(); - window.open = jasmine.createSpy('open'); - const params = { - recipientId: ticket.client.id, - ticketId: ticket.id + const expectedParams = { + ticketId: ticket.id, + recipientId: ticket.client.id }; - controller.showDeliveryNote(); + const serializedParams = $httpParamSerializer(expectedParams); + const expectedPath = `api/report/delivery-note?${serializedParams}`; + controller.showPdfDeliveryNote(); - expect(controller.vnReport.show).toHaveBeenCalledWith('delivery-note', params); + expect(window.open).toHaveBeenCalledWith(expectedPath); }); }); - describe('sendDeliveryNote()', () => { + describe('sendPdfDeliveryNote()', () => { it('should make a query and call vnApp.showMessage()', () => { jest.spyOn(controller.vnEmail, 'send'); + const $data = {email: 'brucebanner@gothamcity.com'}; const params = { - recipient: ticket.client.email, + recipient: $data.email, recipientId: ticket.client.id, ticketId: ticket.id }; - controller.sendDeliveryNote(); + controller.sendPdfDeliveryNote($data); expect(controller.vnEmail.send).toHaveBeenCalledWith('delivery-note', params); }); @@ -149,13 +153,13 @@ describe('Ticket Component vnTicketDescriptorMenu', () => { }); }); - describe('createInvoicePdf()', () => { + describe('createPdfInvoice()', () => { it('should make a query and show a success snackbar', () => { jest.spyOn(controller.vnApp, 'showSuccess'); $httpBackend.whenGET(`Tickets/16`).respond(); $httpBackend.expectPOST(`InvoiceOuts/${ticket.invoiceOut.id}/createPdf`).respond(); - controller.createInvoicePdf(); + controller.createPdfInvoice(); $httpBackend.flush(); expect(controller.vnApp.showSuccess).toHaveBeenCalled(); @@ -222,4 +226,66 @@ describe('Ticket Component vnTicketDescriptorMenu', () => { }); }); }); + + xdescribe('showCsvInvoice()', () => { + it('should make a query to the csv invoice download endpoint and show a message snackbar', () => { + jest.spyOn(window, 'open').mockReturnThis(); + + controller.invoiceOut = invoiceOut; + + const expectedParams = { + invoiceId: invoiceOut.id, + recipientId: invoiceOut.client.id + }; + const serializedParams = $httpParamSerializer(expectedParams); + const expectedPath = `api/csv/invoice/download?${serializedParams}`; + controller.showCsvInvoice(); + + expect(window.open).toHaveBeenCalledWith(expectedPath); + }); + }); + + xdescribe('sendPdfInvoice()', () => { + it('should make a query to the email invoice endpoint and show a message snackbar', () => { + jest.spyOn(controller.vnApp, 'showMessage'); + + controller.invoiceOut = invoiceOut; + + const $data = {email: 'brucebanner@gothamcity.com'}; + const expectedParams = { + invoiceId: invoiceOut.id, + recipient: $data.email, + recipientId: invoiceOut.client.id + }; + const serializedParams = $httpParamSerializer(expectedParams); + + $httpBackend.expectGET(`email/invoice?${serializedParams}`).respond(); + controller.sendPdfInvoice($data); + $httpBackend.flush(); + + expect(controller.vnApp.showMessage).toHaveBeenCalled(); + }); + }); + + xdescribe('sendCsvInvoice()', () => { + it('should make a query to the csv invoice send endpoint and show a message snackbar', () => { + jest.spyOn(controller.vnApp, 'showMessage'); + + controller.invoiceOut = invoiceOut; + + const $data = {email: 'brucebanner@gothamcity.com'}; + const expectedParams = { + invoiceId: invoiceOut.id, + recipient: $data.email, + recipientId: invoiceOut.client.id + }; + const serializedParams = $httpParamSerializer(expectedParams); + + $httpBackend.expectGET(`csv/invoice/send?${serializedParams}`).respond(); + controller.sendCsvInvoice($data); + $httpBackend.flush(); + + expect(controller.vnApp.showMessage).toHaveBeenCalled(); + }); + }); }); From e641a947b381059fac172e193f7cf35e39372e94 Mon Sep 17 00:00:00 2001 From: joan Date: Fri, 8 Oct 2021 09:51:42 +0200 Subject: [PATCH 14/47] Updated unit tests --- front/core/components/popover/index.js | 3 +- .../front/descriptor-menu/index.spec.js | 98 +++++++------------ print/templates/reports/invoice/invoice.js | 1 - 3 files changed, 37 insertions(+), 65 deletions(-) diff --git a/front/core/components/popover/index.js b/front/core/components/popover/index.js index 9e68d176e..9567102db 100644 --- a/front/core/components/popover/index.js +++ b/front/core/components/popover/index.js @@ -30,7 +30,7 @@ export default class Popover extends Popup { if (parent) this.parent = parent; if (direction) this.direction = direction; - console.log(direction); + super.show(); this.content = this.popup.querySelector('.content'); this.$timeout(() => this.relocate(), 10); @@ -60,7 +60,6 @@ export default class Popover extends Popup { * Repositions the popover to a correct location relative to the parent. */ relocate() { - console.log(this.direction); if (!(this.parent && this._shown && this.displayMode == 'relative')) return; diff --git a/modules/ticket/front/descriptor-menu/index.spec.js b/modules/ticket/front/descriptor-menu/index.spec.js index 5413545fe..e9486bcd0 100644 --- a/modules/ticket/front/descriptor-menu/index.spec.js +++ b/modules/ticket/front/descriptor-menu/index.spec.js @@ -138,6 +138,42 @@ describe('Ticket Component vnTicketDescriptorMenu', () => { }); }); + describe('showCsvDeliveryNote()', () => { + it('should make a query to the csv delivery-note download endpoint and show a message snackbar', () => { + jest.spyOn(window, 'open').mockReturnThis(); + + const expectedParams = { + ticketId: ticket.id, + recipientId: ticket.client.id + }; + const serializedParams = $httpParamSerializer(expectedParams); + const expectedPath = `api/csv/delivery-note/download?${serializedParams}`; + controller.showCsvDeliveryNote(); + + expect(window.open).toHaveBeenCalledWith(expectedPath); + }); + }); + + describe('sendCsvDeliveryNote()', () => { + it('should make a query to the csv delivery-note send endpoint and show a message snackbar', () => { + jest.spyOn(controller.vnApp, 'showMessage'); + + const $data = {email: 'brucebanner@gothamcity.com'}; + const expectedParams = { + ticketId: ticket.id, + recipient: $data.email, + recipientId: ticket.client.id, + }; + const serializedParams = $httpParamSerializer(expectedParams); + + $httpBackend.expectGET(`csv/delivery-note/send?${serializedParams}`).respond(); + controller.sendCsvDeliveryNote($data); + $httpBackend.flush(); + + expect(controller.vnApp.showMessage).toHaveBeenCalled(); + }); + }); + describe('makeInvoice()', () => { it('should make a query and call $state.reload() method', () => { jest.spyOn(controller, 'reload').mockReturnThis(); @@ -226,66 +262,4 @@ describe('Ticket Component vnTicketDescriptorMenu', () => { }); }); }); - - xdescribe('showCsvInvoice()', () => { - it('should make a query to the csv invoice download endpoint and show a message snackbar', () => { - jest.spyOn(window, 'open').mockReturnThis(); - - controller.invoiceOut = invoiceOut; - - const expectedParams = { - invoiceId: invoiceOut.id, - recipientId: invoiceOut.client.id - }; - const serializedParams = $httpParamSerializer(expectedParams); - const expectedPath = `api/csv/invoice/download?${serializedParams}`; - controller.showCsvInvoice(); - - expect(window.open).toHaveBeenCalledWith(expectedPath); - }); - }); - - xdescribe('sendPdfInvoice()', () => { - it('should make a query to the email invoice endpoint and show a message snackbar', () => { - jest.spyOn(controller.vnApp, 'showMessage'); - - controller.invoiceOut = invoiceOut; - - const $data = {email: 'brucebanner@gothamcity.com'}; - const expectedParams = { - invoiceId: invoiceOut.id, - recipient: $data.email, - recipientId: invoiceOut.client.id - }; - const serializedParams = $httpParamSerializer(expectedParams); - - $httpBackend.expectGET(`email/invoice?${serializedParams}`).respond(); - controller.sendPdfInvoice($data); - $httpBackend.flush(); - - expect(controller.vnApp.showMessage).toHaveBeenCalled(); - }); - }); - - xdescribe('sendCsvInvoice()', () => { - it('should make a query to the csv invoice send endpoint and show a message snackbar', () => { - jest.spyOn(controller.vnApp, 'showMessage'); - - controller.invoiceOut = invoiceOut; - - const $data = {email: 'brucebanner@gothamcity.com'}; - const expectedParams = { - invoiceId: invoiceOut.id, - recipient: $data.email, - recipientId: invoiceOut.client.id - }; - const serializedParams = $httpParamSerializer(expectedParams); - - $httpBackend.expectGET(`csv/invoice/send?${serializedParams}`).respond(); - controller.sendCsvInvoice($data); - $httpBackend.flush(); - - expect(controller.vnApp.showMessage).toHaveBeenCalled(); - }); - }); }); diff --git a/print/templates/reports/invoice/invoice.js b/print/templates/reports/invoice/invoice.js index 3e8734306..b56a5533c 100755 --- a/print/templates/reports/invoice/invoice.js +++ b/print/templates/reports/invoice/invoice.js @@ -95,7 +95,6 @@ module.exports = { }, ticketSubtotal(ticket) { let subTotal = 0.00; - console.log(ticket.sales); for (let sale of ticket.sales) subTotal += this.saleImport(sale); From 1e93f221d8a222facf6988f4ec1e168db3d19aff Mon Sep 17 00:00:00 2001 From: carlosjr Date: Fri, 8 Oct 2021 15:41:02 +0200 Subject: [PATCH 15/47] refactor(readme): removed a dupe --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 32377c115..1e3ad5e9e 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,6 @@ Required applications. * Node.js = 14.x LTS * Docker * Git -* Docker You will need to install globally the following items. ``` From 440f4d270cab2e0ac065ac62aee22d8108c1221d Mon Sep 17 00:00:00 2001 From: carlosjr Date: Mon, 11 Oct 2021 11:18:11 +0200 Subject: [PATCH 16/47] refactor(launchBackTest): setted default timeout back to 5 secs --- gulpfile.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gulpfile.js b/gulpfile.js index efd1d15ba..59c79c154 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -98,7 +98,7 @@ async function launchBackTest(done) { verbose: false, includeStackTrace: false, errorOnFail: false, - timeout: 6000, + timeout: 5000, config: {} }; From 25e0e67c00e6159bdcf9dbc4a5f5432d508b6939 Mon Sep 17 00:00:00 2001 From: carlosjr Date: Mon, 11 Oct 2021 11:19:20 +0200 Subject: [PATCH 17/47] refactor(extensions): removed awaits from returned promises --- e2e/helpers/extensions.js | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/e2e/helpers/extensions.js b/e2e/helpers/extensions.js index 71f834476..133801f38 100644 --- a/e2e/helpers/extensions.js +++ b/e2e/helpers/extensions.js @@ -108,7 +108,7 @@ let actions = { }, getState: async function() { - return await this.evaluate(() => { + return this.evaluate(() => { let $state = angular.element(document.body).injector().get('$state'); return $state.current.name; }); @@ -194,7 +194,7 @@ let actions = { }, getProperty: async function(selector, property) { - return await this.evaluate((selector, property) => { + return this.evaluate((selector, property) => { return document.querySelector(selector)[property].replace(/\s+/g, ' ').trim(); }, selector, property); }, @@ -202,7 +202,7 @@ let actions = { getClassName: async function(selector) { const element = await this.$(selector); const handle = await element.getProperty('className'); - return await handle.jsonValue(); + return handle.jsonValue(); }, waitPropertyLength: async function(selector, property, minLength) { @@ -210,7 +210,7 @@ let actions = { const element = document.querySelector(selector); return element && element[property] != null && element[property] !== '' && element[property].length >= minLength; }, {}, selector, property, minLength); - return await this.getProperty(selector, property); + return this.getProperty(selector, property); }, expectPropertyValue: async function(selector, property, value) { @@ -219,7 +219,7 @@ let actions = { builtSelector = await this.selectorFormater(selector); try { - return await this.waitForFunction((selector, property, value) => { + return this.waitForFunction((selector, property, value) => { const element = document.querySelector(selector); return element[property] == value; }, {}, builtSelector, property, value); @@ -239,7 +239,7 @@ let actions = { return element && element[property] != null && element[property] !== ''; }, {}, builtSelector, property); - return await this.getProperty(builtSelector, property); + return this.getProperty(builtSelector, property); } catch (error) { throw new Error(`couldn't get property: ${property} of ${builtSelector}, ${error}`); } @@ -261,7 +261,7 @@ let actions = { await this.waitForSelector(selector); await this.waitForFunction(checkVisibility, {}, selector); - return await this.click(selector); + return this.click(selector); }, writeOnEditableTD: async function(selector, text) { @@ -274,7 +274,7 @@ let actions = { focusElement: async function(selector) { await this.waitForSelector(selector); - return await this.evaluate(selector => { + return this.evaluate(selector => { let element = document.querySelector(selector); element.focus(); }, selector); @@ -282,19 +282,19 @@ let actions = { isVisible: async function(selector) { await this.waitForSelector(selector); - return await this.evaluate(checkVisibility, selector); + return this.evaluate(checkVisibility, selector); }, waitImgLoad: async function(selector) { await this.waitForSelector(selector); - return await this.waitForFunction(selector => { + return this.waitForFunction(selector => { const imageReady = document.querySelector(selector).complete; return imageReady; }, {}, selector); }, countElement: async function(selector) { - return await this.evaluate(selector => { + return this.evaluate(selector => { return document.querySelectorAll(selector).length; }, selector); }, @@ -312,7 +312,7 @@ let actions = { waitForClassNotPresent: async function(selector, className) { await this.waitForSelector(selector); - return await this.waitForFunction((selector, className) => { + return this.waitForFunction((selector, className) => { if (!document.querySelector(selector).classList.contains(className)) return true; }, {}, selector, className); @@ -320,7 +320,7 @@ let actions = { waitForClassPresent: async function(selector, className) { await this.waitForSelector(selector); - return await this.waitForFunction((elementSelector, targetClass) => { + return this.waitForFunction((elementSelector, targetClass) => { if (document.querySelector(elementSelector).classList.contains(targetClass)) return true; }, {}, selector, className); @@ -387,13 +387,13 @@ let actions = { const innerText = document.querySelector(selector).innerText; return innerText != null && innerText != ''; }, {}, selector); - return await this.evaluate(selector => { + return this.evaluate(selector => { return document.querySelector(selector).innerText; }, selector); }, waitForEmptyInnerText: async function(selector) { - return await this.waitFunction(selector => { + return this.waitFunction(selector => { return document.querySelector(selector).innerText == ''; }, selector); }, @@ -521,7 +521,7 @@ let actions = { checkboxState: async function(selector) { await this.waitForSelector(selector); - return await this.evaluate(selector => { + return this.evaluate(selector => { let checkbox = document.querySelector(selector); switch (checkbox.$ctrl.field) { case null: @@ -536,14 +536,14 @@ let actions = { isDisabled: async function(selector) { await this.waitForSelector(selector); - return await this.evaluate(selector => { + return this.evaluate(selector => { let element = document.querySelector(selector); return element.$ctrl.disabled; }, selector); }, waitForStylePresent: async function(selector, property, value) { - return await this.waitForFunction((selector, property, value) => { + return this.waitForFunction((selector, property, value) => { const element = document.querySelector(selector); return element.style[property] == value; }, {}, selector, property, value); @@ -631,7 +631,7 @@ export function extendPage(page) { for (let name in actions) { page[name] = async(...args) => { try { - return await actions[name].apply(page, args); + return actions[name].apply(page, args); } catch (err) { let stringArgs = args .map(i => typeof i == 'function' ? 'Function' : i) From ce5a29496efc9b36cdade9279f66a052cee3fe5c Mon Sep 17 00:00:00 2001 From: carlosjr Date: Mon, 11 Oct 2021 11:20:15 +0200 Subject: [PATCH 18/47] refactor(puppeteer): default timeout setted back to 5 from 4 secs --- e2e/helpers/puppeteer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e/helpers/puppeteer.js b/e2e/helpers/puppeteer.js index 02ef82b1b..4840d38c3 100644 --- a/e2e/helpers/puppeteer.js +++ b/e2e/helpers/puppeteer.js @@ -38,7 +38,7 @@ export async function getBrowser() { }); }); page = extendPage(page); - page.setDefaultTimeout(4000); + page.setDefaultTimeout(5000); await page.goto(defaultURL, {waitUntil: 'load'}); return {page, close: browser.close.bind(browser)}; } From a0a01de937ff23babe014e1778bbe823c4420c1e Mon Sep 17 00:00:00 2001 From: joan Date: Wed, 13 Oct 2021 14:17:45 +0200 Subject: [PATCH 19/47] fix(salesMonitor): now sorts correctly by practical and theorical hour Refs: 3219 --- .../back/methods/sales-monitor/salesFilter.js | 12 +- .../monitor/front/index/tickets/index.html | 152 ++++++------------ modules/monitor/front/index/tickets/index.js | 6 +- 3 files changed, 60 insertions(+), 110 deletions(-) diff --git a/modules/monitor/back/methods/sales-monitor/salesFilter.js b/modules/monitor/back/methods/sales-monitor/salesFilter.js index 1b56d87f7..cec8026ff 100644 --- a/modules/monitor/back/methods/sales-monitor/salesFilter.js +++ b/modules/monitor/back/methods/sales-monitor/salesFilter.js @@ -196,7 +196,6 @@ module.exports = Self => { t.id, t.shipped, CAST(DATE(t.shipped) AS CHAR) AS shippedDate, - HOUR(t.shipped) AS shippedHour, t.nickname, t.refFk, t.routeFk, @@ -218,11 +217,10 @@ module.exports = Self => { u.name AS userName, c.salesPersonFk, z.hour AS zoneLanding, - HOUR(z.hour) AS zoneHour, - MINUTE(z.hour) AS zoneMinute, z.name AS zoneName, z.id AS zoneFk, - CAST(z.hour AS CHAR) AS hour, + th.preparationHour, + TIME_FORMAT(z.hour, '%H:%i') AS theoreticalhour, TIME_FORMAT(zed.etc, '%H:%i') AS practicalHour FROM ticket t LEFT JOIN invoiceOut io ON t.refFk = io.ref @@ -236,7 +234,11 @@ module.exports = Self => { LEFT JOIN client c ON c.id = t.clientFk LEFT JOIN worker wk ON wk.id = c.salesPersonFk LEFT JOIN account.user u ON u.id = wk.userFk - LEFT JOIN zoneEstimatedDelivery zed ON zed.zoneFk = t.zoneFk`); + LEFT JOIN zoneEstimatedDelivery zed ON zed.zoneFk = t.zoneFk + JOIN ( + SELECT t.id, TIME_FORMAT(t.shipped, '%H:%i') AS preparationHour + FROM ticket AS t + ) AS th ON th.id = t.id`); if (args.orderFk) { stmt.merge({ diff --git a/modules/monitor/front/index/tickets/index.html b/modules/monitor/front/index/tickets/index.html index 82adf2765..4e8bf0e47 100644 --- a/modules/monitor/front/index/tickets/index.html +++ b/modules/monitor/front/index/tickets/index.html @@ -1,31 +1,28 @@ - + order="shippedDate DESC, preparationHour ASC, zoneLanding ASC, id"> - Tickets monitor - + - + @@ -37,8 +34,8 @@ Client Salesperson Date - Prep. - Theoretical + Prep. + Theoretical Practical Province State @@ -48,61 +45,37 @@ - - + - + - + - - + - + - {{::ticket.nickname}} - + {{::ticket.userName | dashIfEmpty}} @@ -116,23 +89,16 @@ {{::ticket.practicalHour | date: 'HH:mm'}} {{::ticket.province}} - + {{::ticket.refFk}} - + {{::ticket.state}} - {{::ticket.zoneName | dashIfEmpty}} @@ -143,70 +109,48 @@ - + }" vn-tooltip="Go to lines" icon="icon-lines"> - + - + - + - + - + - + - + Filter by selection - + Exclude selection - + Remove filter - + Remove all filters - + Copy value - + \ No newline at end of file diff --git a/modules/monitor/front/index/tickets/index.js b/modules/monitor/front/index/tickets/index.js index d8832d1b5..a224ecac6 100644 --- a/modules/monitor/front/index/tickets/index.js +++ b/modules/monitor/front/index/tickets/index.js @@ -68,8 +68,12 @@ export default class Controller extends Section { return {'c.salesPersonFk': value}; case 'provinceFk': return {'a.provinceFk': value}; - case 'hour': + case 'theoreticalHour': return {'z.hour': value}; + case 'practicalHour': + return {'zed.etc': value}; + case 'preparationHour': + return {'th.preparationHour': value}; case 'shipped': return {'t.shipped': { between: this.dateRange(value)} From 491cca2bd6802b2fb104f1b12deb526c42328e62 Mon Sep 17 00:00:00 2001 From: joan Date: Wed, 13 Oct 2021 14:19:29 +0200 Subject: [PATCH 20/47] Removed empty spaces --- .../monitor/front/index/tickets/index.html | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/modules/monitor/front/index/tickets/index.html b/modules/monitor/front/index/tickets/index.html index 4e8bf0e47..f5f9339fc 100644 --- a/modules/monitor/front/index/tickets/index.html +++ b/modules/monitor/front/index/tickets/index.html @@ -1,19 +1,19 @@ - - From d951ca02f05cf9d0068a55ce48c8cd7d307dff90 Mon Sep 17 00:00:00 2001 From: joan Date: Wed, 13 Oct 2021 14:21:42 +0200 Subject: [PATCH 21/47] Fixed format --- .../monitor/front/index/tickets/index.html | 134 +++++++++++++----- 1 file changed, 95 insertions(+), 39 deletions(-) diff --git a/modules/monitor/front/index/tickets/index.html b/modules/monitor/front/index/tickets/index.html index f5f9339fc..76127d4f2 100644 --- a/modules/monitor/front/index/tickets/index.html +++ b/modules/monitor/front/index/tickets/index.html @@ -1,13 +1,13 @@ - - Tickets monitor - + - + @@ -45,37 +48,61 @@ - - + - + - + - - + - + - {{::ticket.nickname}} - + {{::ticket.userName | dashIfEmpty}} @@ -89,16 +116,23 @@ {{::ticket.practicalHour | date: 'HH:mm'}} {{::ticket.province}} - + {{::ticket.refFk}} - + {{::ticket.state}} - {{::ticket.zoneName | dashIfEmpty}} @@ -109,48 +143,70 @@ - + }" + vn-tooltip="Go to lines" + icon="icon-lines"> - + - + - + - + - + - + - + Filter by selection - + Exclude selection - + Remove filter - + Remove all filters - + Copy value - \ No newline at end of file + From 31e160559b613ea8e967e915d86def7a49edbab2 Mon Sep 17 00:00:00 2001 From: joan Date: Wed, 13 Oct 2021 14:17:45 +0200 Subject: [PATCH 22/47] fix(salesMonitor): now sorts correctly by practical and theorical hour Refs: 3219 --- .../back/methods/sales-monitor/salesFilter.js | 12 +- .../monitor/front/index/tickets/index.html | 152 ++++++------------ modules/monitor/front/index/tickets/index.js | 6 +- 3 files changed, 60 insertions(+), 110 deletions(-) diff --git a/modules/monitor/back/methods/sales-monitor/salesFilter.js b/modules/monitor/back/methods/sales-monitor/salesFilter.js index 6483a906a..1bf4451ca 100644 --- a/modules/monitor/back/methods/sales-monitor/salesFilter.js +++ b/modules/monitor/back/methods/sales-monitor/salesFilter.js @@ -197,7 +197,6 @@ module.exports = Self => { t.id, t.shipped, CAST(DATE(t.shipped) AS CHAR) AS shippedDate, - HOUR(t.shipped) AS shippedHour, t.nickname, t.refFk, t.routeFk, @@ -219,11 +218,10 @@ module.exports = Self => { u.name AS userName, c.salesPersonFk, z.hour AS zoneLanding, - HOUR(z.hour) AS zoneHour, - MINUTE(z.hour) AS zoneMinute, z.name AS zoneName, z.id AS zoneFk, - CAST(z.hour AS CHAR) AS hour, + th.preparationHour, + TIME_FORMAT(z.hour, '%H:%i') AS theoreticalhour, TIME_FORMAT(zed.etc, '%H:%i') AS practicalHour FROM ticket t LEFT JOIN invoiceOut io ON t.refFk = io.ref @@ -237,7 +235,11 @@ module.exports = Self => { LEFT JOIN client c ON c.id = t.clientFk LEFT JOIN worker wk ON wk.id = c.salesPersonFk LEFT JOIN account.user u ON u.id = wk.userFk - LEFT JOIN zoneEstimatedDelivery zed ON zed.zoneFk = t.zoneFk`); + LEFT JOIN zoneEstimatedDelivery zed ON zed.zoneFk = t.zoneFk + JOIN ( + SELECT t.id, TIME_FORMAT(t.shipped, '%H:%i') AS preparationHour + FROM ticket AS t + ) AS th ON th.id = t.id`); if (args.orderFk) { stmt.merge({ diff --git a/modules/monitor/front/index/tickets/index.html b/modules/monitor/front/index/tickets/index.html index 82adf2765..4e8bf0e47 100644 --- a/modules/monitor/front/index/tickets/index.html +++ b/modules/monitor/front/index/tickets/index.html @@ -1,31 +1,28 @@ - + order="shippedDate DESC, preparationHour ASC, zoneLanding ASC, id"> - Tickets monitor - + - + @@ -37,8 +34,8 @@ Client Salesperson Date - Prep. - Theoretical + Prep. + Theoretical Practical Province State @@ -48,61 +45,37 @@ - - + - + - + - - + - + - {{::ticket.nickname}} - + {{::ticket.userName | dashIfEmpty}} @@ -116,23 +89,16 @@ {{::ticket.practicalHour | date: 'HH:mm'}} {{::ticket.province}} - + {{::ticket.refFk}} - + {{::ticket.state}} - {{::ticket.zoneName | dashIfEmpty}} @@ -143,70 +109,48 @@ - + }" vn-tooltip="Go to lines" icon="icon-lines"> - + - + - + - + - + - + - + Filter by selection - + Exclude selection - + Remove filter - + Remove all filters - + Copy value - + \ No newline at end of file diff --git a/modules/monitor/front/index/tickets/index.js b/modules/monitor/front/index/tickets/index.js index d8832d1b5..a224ecac6 100644 --- a/modules/monitor/front/index/tickets/index.js +++ b/modules/monitor/front/index/tickets/index.js @@ -68,8 +68,12 @@ export default class Controller extends Section { return {'c.salesPersonFk': value}; case 'provinceFk': return {'a.provinceFk': value}; - case 'hour': + case 'theoreticalHour': return {'z.hour': value}; + case 'practicalHour': + return {'zed.etc': value}; + case 'preparationHour': + return {'th.preparationHour': value}; case 'shipped': return {'t.shipped': { between: this.dateRange(value)} From b2cdfd9785a922f94caf2da04fc85b6d9f60a33d Mon Sep 17 00:00:00 2001 From: joan Date: Wed, 13 Oct 2021 14:19:29 +0200 Subject: [PATCH 23/47] Removed empty spaces --- .../monitor/front/index/tickets/index.html | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/modules/monitor/front/index/tickets/index.html b/modules/monitor/front/index/tickets/index.html index 4e8bf0e47..f5f9339fc 100644 --- a/modules/monitor/front/index/tickets/index.html +++ b/modules/monitor/front/index/tickets/index.html @@ -1,19 +1,19 @@ - - From 1b9b918812c115459ffda119e616405c4c9f7bd2 Mon Sep 17 00:00:00 2001 From: joan Date: Wed, 13 Oct 2021 14:21:42 +0200 Subject: [PATCH 24/47] Fixed format --- .../monitor/front/index/tickets/index.html | 134 +++++++++++++----- 1 file changed, 95 insertions(+), 39 deletions(-) diff --git a/modules/monitor/front/index/tickets/index.html b/modules/monitor/front/index/tickets/index.html index f5f9339fc..76127d4f2 100644 --- a/modules/monitor/front/index/tickets/index.html +++ b/modules/monitor/front/index/tickets/index.html @@ -1,13 +1,13 @@ - - Tickets monitor - + - + @@ -45,37 +48,61 @@ - - + - + - + - - + - + - {{::ticket.nickname}} - + {{::ticket.userName | dashIfEmpty}} @@ -89,16 +116,23 @@ {{::ticket.practicalHour | date: 'HH:mm'}} {{::ticket.province}} - + {{::ticket.refFk}} - + {{::ticket.state}} - {{::ticket.zoneName | dashIfEmpty}} @@ -109,48 +143,70 @@ - + }" + vn-tooltip="Go to lines" + icon="icon-lines"> - + - + - + - + - + - + - + Filter by selection - + Exclude selection - + Remove filter - + Remove all filters - + Copy value - \ No newline at end of file + From c0e1f2f0dc2e45d197193d71fa25aa100bd47243 Mon Sep 17 00:00:00 2001 From: joan Date: Wed, 13 Oct 2021 14:55:53 +0200 Subject: [PATCH 25/47] Changed column order --- modules/monitor/back/methods/sales-monitor/salesFilter.js | 8 ++------ modules/monitor/front/index/tickets/index.html | 2 +- modules/monitor/front/index/tickets/index.js | 2 -- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/modules/monitor/back/methods/sales-monitor/salesFilter.js b/modules/monitor/back/methods/sales-monitor/salesFilter.js index 1bf4451ca..5d49f07df 100644 --- a/modules/monitor/back/methods/sales-monitor/salesFilter.js +++ b/modules/monitor/back/methods/sales-monitor/salesFilter.js @@ -220,7 +220,7 @@ module.exports = Self => { z.hour AS zoneLanding, z.name AS zoneName, z.id AS zoneFk, - th.preparationHour, + TIME_FORMAT(t.shipped, '%H:%i') AS preparationHour, TIME_FORMAT(z.hour, '%H:%i') AS theoreticalhour, TIME_FORMAT(zed.etc, '%H:%i') AS practicalHour FROM ticket t @@ -235,11 +235,7 @@ module.exports = Self => { LEFT JOIN client c ON c.id = t.clientFk LEFT JOIN worker wk ON wk.id = c.salesPersonFk LEFT JOIN account.user u ON u.id = wk.userFk - LEFT JOIN zoneEstimatedDelivery zed ON zed.zoneFk = t.zoneFk - JOIN ( - SELECT t.id, TIME_FORMAT(t.shipped, '%H:%i') AS preparationHour - FROM ticket AS t - ) AS th ON th.id = t.id`); + LEFT JOIN zoneEstimatedDelivery zed ON zed.zoneFk = t.zoneFk`); if (args.orderFk) { stmt.merge({ diff --git a/modules/monitor/front/index/tickets/index.html b/modules/monitor/front/index/tickets/index.html index 76127d4f2..45db04ca0 100644 --- a/modules/monitor/front/index/tickets/index.html +++ b/modules/monitor/front/index/tickets/index.html @@ -37,7 +37,7 @@ Client Salesperson Date - Prep. + Prep. Theoretical Practical Province diff --git a/modules/monitor/front/index/tickets/index.js b/modules/monitor/front/index/tickets/index.js index a224ecac6..9d8a911e8 100644 --- a/modules/monitor/front/index/tickets/index.js +++ b/modules/monitor/front/index/tickets/index.js @@ -72,8 +72,6 @@ export default class Controller extends Section { return {'z.hour': value}; case 'practicalHour': return {'zed.etc': value}; - case 'preparationHour': - return {'th.preparationHour': value}; case 'shipped': return {'t.shipped': { between: this.dateRange(value)} From e278491ad2bdbcf55ebc3433db74c0acc8eaab39 Mon Sep 17 00:00:00 2001 From: joan Date: Thu, 14 Oct 2021 08:48:57 +0200 Subject: [PATCH 26/47] refactor(order): index filter optimization --- modules/order/back/methods/order/filter.js | 23 ++++++++++++---------- modules/order/front/index/index.html | 2 +- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/modules/order/back/methods/order/filter.js b/modules/order/back/methods/order/filter.js index ef6ea8a44..bd987dd5b 100644 --- a/modules/order/back/methods/order/filter.js +++ b/modules/order/back/methods/order/filter.js @@ -119,7 +119,7 @@ module.exports = Self => { case 'sourceApp': return {'o.source_app': value}; case 'ticketFk': - return {'ort.ticketFk': value}; + return {'ot.ticketFk': value}; case 'isConfirmed': return {'o.confirmed': value ? 1 : 0}; case 'myTeam': @@ -137,7 +137,10 @@ module.exports = Self => { let stmt; stmt = new ParameterizedSQL( - `SELECT + `CREATE TEMPORARY TABLE tmp.filter + (INDEX (id)) + ENGINE = MEMORY + SELECT o.id, o.total, o.date_send landed, @@ -168,20 +171,20 @@ module.exports = Self => { LEFT JOIN ticket t ON t.id = ot.ticketFk LEFT JOIN zoneEstimatedDelivery zed ON zed.zoneFk = t.zoneFk`); - if (args && args.ticketFk) { - stmt.merge({ - sql: `LEFT JOIN orderTicket ort ON ort.orderFk = o.id` - }); - } - stmt.merge(conn.makeWhere(filter.where)); - stmt.merge(`GROUP BY o.id`); stmt.merge(conn.makePagination(filter)); stmts.push(stmt); + stmt = new ParameterizedSQL(`SELECT * FROM tmp.filter`); + stmt.merge(`GROUP BY id`); + stmt.merge(conn.makeOrderBy(filter.order)); + const ordersIndex = stmts.push(stmt) - 1; + + stmts.push(`DROP TEMPORARY TABLE tmp.filter`); + const sql = ParameterizedSQL.join(stmts, ';'); const result = await conn.executeStmt(sql); - return result; + return result[ordersIndex]; }; }; diff --git a/modules/order/front/index/index.html b/modules/order/front/index/index.html index 288e81226..a2a4a5226 100644 --- a/modules/order/front/index/index.html +++ b/modules/order/front/index/index.html @@ -17,7 +17,7 @@ Landed Hour Agency - Total + Total From 35a2a716026e27c2f1fbdc6ac2439e08c217c87f Mon Sep 17 00:00:00 2001 From: carlosjr Date: Thu, 14 Oct 2021 16:16:00 +0200 Subject: [PATCH 27/47] refactor(sales): transaction correctly passed to findById --- .../ticket/back/methods/ticket/transferSales.js | 2 +- package-lock.json | 16 ++++++++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/modules/ticket/back/methods/ticket/transferSales.js b/modules/ticket/back/methods/ticket/transferSales.js index e196b7c19..49529135c 100644 --- a/modules/ticket/back/methods/ticket/transferSales.js +++ b/modules/ticket/back/methods/ticket/transferSales.js @@ -170,7 +170,7 @@ module.exports = Self => { // Update original sale const rest = originalSale.quantity - sale.quantity; - const originalInstance = await models.Sale.findById(sale.id, options); + const originalInstance = await models.Sale.findById(sale.id, null, options); await originalInstance.updateAttribute('quantity', rest, options); // Clone sale with new quantity diff --git a/package-lock.json b/package-lock.json index e1a4831b0..645c55238 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5655,6 +5655,7 @@ }, "node_modules/devtools-protocol": { "version": "0.0.847576", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.847576.tgz", "integrity": "sha512-0M8kobnSQE0Jmly7Mhbeq0W/PpZfnuK+WjN2ZRVPbGqYwCHCioAVp84H0TcLimgECcN5H976y5QiXMGBC9JKmg==" }, "node_modules/diff": { @@ -16896,6 +16897,7 @@ }, "node_modules/puppeteer": { "version": "7.1.0", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-7.1.0.tgz", "integrity": "sha512-lqOLzqCKdh7yUAHvK6LxgOpQrL8Bv1/jvS8MLDXxcNms2rlM3E8p/Wlwc7efbRZ0twxTzUeqjN5EqrTwxOwc9g==", "hasInstallScript": true, "dependencies": { @@ -21105,8 +21107,9 @@ } }, "node_modules/unbzip2-stream": { - "version": "1.4.3", - "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.3.3.tgz", + "integrity": "sha512-fUlAF7U9Ah1Q6EieQ4x4zLNejrRvDWUYmxXUpN3uziFYCHapjWFaCAnreY9bGgxzaMCFAPPpYNng57CypwJVhg==", "dependencies": { "buffer": "^5.2.1", "through": "^2.3.8" @@ -21114,6 +21117,7 @@ }, "node_modules/unbzip2-stream/node_modules/buffer": { "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", "funding": [ { @@ -27925,6 +27929,7 @@ }, "devtools-protocol": { "version": "0.0.847576", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.847576.tgz", "integrity": "sha512-0M8kobnSQE0Jmly7Mhbeq0W/PpZfnuK+WjN2ZRVPbGqYwCHCioAVp84H0TcLimgECcN5H976y5QiXMGBC9JKmg==" }, "diff": { @@ -36716,6 +36721,7 @@ }, "puppeteer": { "version": "7.1.0", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-7.1.0.tgz", "integrity": "sha512-lqOLzqCKdh7yUAHvK6LxgOpQrL8Bv1/jvS8MLDXxcNms2rlM3E8p/Wlwc7efbRZ0twxTzUeqjN5EqrTwxOwc9g==", "requires": { "debug": "^4.1.0", @@ -40017,8 +40023,9 @@ } }, "unbzip2-stream": { - "version": "1.4.3", - "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.3.3.tgz", + "integrity": "sha512-fUlAF7U9Ah1Q6EieQ4x4zLNejrRvDWUYmxXUpN3uziFYCHapjWFaCAnreY9bGgxzaMCFAPPpYNng57CypwJVhg==", "requires": { "buffer": "^5.2.1", "through": "^2.3.8" @@ -40026,6 +40033,7 @@ "dependencies": { "buffer": { "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", "requires": { "base64-js": "^1.3.1", From 9644c6b9c13d4fd435a8249a6c4950dd13dab281 Mon Sep 17 00:00:00 2001 From: carlosjr Date: Thu, 14 Oct 2021 16:16:49 +0200 Subject: [PATCH 28/47] refactor(puppeteer): left comments with paths to firefox and chrome binaries for future references --- e2e/helpers/puppeteer.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/e2e/helpers/puppeteer.js b/e2e/helpers/puppeteer.js index 4840d38c3..b8dc8cfe3 100644 --- a/e2e/helpers/puppeteer.js +++ b/e2e/helpers/puppeteer.js @@ -5,11 +5,14 @@ import {url as defaultURL} from './config'; export async function getBrowser() { const args = [ - `--no-sandbox`, - `--window-size=${ 1920 },${ 1080 }` + '--no-sandbox', + `--window-size=${ 1920 },${ 1080 }`, + // '--disable-dev-shm-usage' + // '--full-memory-crash-report', + // '--unlimited-storage' ]; - let env = process.env; + const env = process.env; if (env.E2E_DEBUG) { args.push('--auto-open-devtools-for-tabs'); @@ -22,6 +25,9 @@ export async function getBrowser() { defaultViewport: null, headless: headless, slowMo: 0, // slow down by ms + // ignoreDefaultArgs: ['--disable-extensions'], + // executablePath: '/usr/bin/google-chrome-stable', + // executablePath: '/usr/bin/firefox-developer-edition', }); let page = (await browser.pages())[0]; From b81d6b022ccf1f1a6bba2d80b9194fdd1b43e174 Mon Sep 17 00:00:00 2001 From: carlosjr Date: Thu, 14 Oct 2021 16:18:04 +0200 Subject: [PATCH 29/47] refactor(buy): removed width limit for a column that was breaking e2e behavior --- modules/entry/front/buy/import/style.scss | 6 ------ 1 file changed, 6 deletions(-) diff --git a/modules/entry/front/buy/import/style.scss b/modules/entry/front/buy/import/style.scss index 8426d4169..9b2fb7688 100644 --- a/modules/entry/front/buy/import/style.scss +++ b/modules/entry/front/buy/import/style.scss @@ -1,9 +1,3 @@ -vn-entry-buy-import { - .vn-table > tbody td:nth-child(1) { - width: 250px - } -} - .itemFilter { vn-table.scrollable { height: 500px From 946151c96692f9c5430cb4fd787e87b223494ee5 Mon Sep 17 00:00:00 2001 From: carlosjr Date: Thu, 14 Oct 2021 16:20:49 +0200 Subject: [PATCH 30/47] refactor(e2e): waitForTimeouts needed for descriptors more menu --- e2e/paths/04-item/08_regularize.spec.js | 1 + e2e/paths/05-ticket/09_weekly.spec.js | 2 ++ e2e/paths/05-ticket/12_descriptor.spec.js | 5 +++++ e2e/paths/05-ticket/14_create_ticket.spec.js | 1 + e2e/paths/05-ticket/15_create_ticket_from_client.spec.js | 1 + e2e/paths/09-invoice-in/02_descriptor.spec.js | 2 ++ e2e/paths/09-invoice-out/03_manualInvoice.spec.js | 2 ++ e2e/paths/10-travel/03_descriptor.spec.js | 3 +++ e2e/paths/11-zone/02_descriptor.spec.js | 1 + e2e/paths/14-account/01_create_and_basic_data.spec.js | 1 + 10 files changed, 19 insertions(+) diff --git a/e2e/paths/04-item/08_regularize.spec.js b/e2e/paths/04-item/08_regularize.spec.js index 97c45643f..6a4b85d06 100644 --- a/e2e/paths/04-item/08_regularize.spec.js +++ b/e2e/paths/04-item/08_regularize.spec.js @@ -107,6 +107,7 @@ describe('Item regularize path', () => { }); it('should regularize the item once more', async() => { + await page.waitForTimeout(1000); // initialization of functionality takes about 100ms to work await page.waitToClick(selectors.itemDescriptor.moreMenu); await page.waitToClick(selectors.itemDescriptor.moreMenuRegularizeButton); await page.write(selectors.itemDescriptor.regularizeQuantity, '100'); diff --git a/e2e/paths/05-ticket/09_weekly.spec.js b/e2e/paths/05-ticket/09_weekly.spec.js index 2392de28f..abee26e0a 100644 --- a/e2e/paths/05-ticket/09_weekly.spec.js +++ b/e2e/paths/05-ticket/09_weekly.spec.js @@ -28,6 +28,7 @@ describe('Ticket descriptor path', () => { }); it('should add the ticket to thursday turn using the descriptor more menu', async() => { + await page.waitForTimeout(1000); // initialization of functionality takes about 100ms to work await page.waitToClick(selectors.ticketDescriptor.moreMenu); await page.waitToClick(selectors.ticketDescriptor.moreMenuAddToTurn); await page.waitToClick(selectors.ticketDescriptor.thursdayButton); @@ -63,6 +64,7 @@ describe('Ticket descriptor path', () => { }); it('should add the ticket to saturday turn using the descriptor more menu', async() => { + await page.waitForTimeout(1000); // initialization of functionality takes about 100ms to work await page.waitToClick(selectors.ticketDescriptor.moreMenu); await page.waitToClick(selectors.ticketDescriptor.moreMenuAddToTurn); await page.waitToClick(selectors.ticketDescriptor.saturdayButton); diff --git a/e2e/paths/05-ticket/12_descriptor.spec.js b/e2e/paths/05-ticket/12_descriptor.spec.js index 08534f8e4..247f91699 100644 --- a/e2e/paths/05-ticket/12_descriptor.spec.js +++ b/e2e/paths/05-ticket/12_descriptor.spec.js @@ -22,6 +22,7 @@ describe('Ticket descriptor path', () => { }); it(`should update the shipped hour using the descriptor menu`, async() => { + await page.waitForTimeout(1000); // initialization of functionality takes about 100ms to work await page.waitToClick(selectors.ticketDescriptor.moreMenu); await page.waitToClick(selectors.ticketDescriptor.moreMenuChangeShippedHour); await page.pickTime(selectors.ticketDescriptor.changeShippedHour, '08:15'); @@ -65,6 +66,7 @@ describe('Ticket descriptor path', () => { describe('Restore ticket', () => { it('should restore the ticket using the descriptor menu', async() => { + await page.waitForTimeout(1000); // initialization of functionality takes about 100ms to work await page.waitToClick(selectors.ticketDescriptor.moreMenu); await page.waitToClick(selectors.ticketDescriptor.moreMenuRestoreTicket); await page.waitToClick(selectors.ticketDescriptor.acceptDialog); @@ -82,6 +84,7 @@ describe('Ticket descriptor path', () => { }); it('should open the add stowaway dialog', async() => { + await page.waitForTimeout(1000); // initialization of functionality takes about 100ms to work await page.waitForFunction(() => { let element = document.querySelector('vn-ticket-descriptor-menu'); return element.$ctrl.canShowStowaway === true; @@ -114,6 +117,7 @@ describe('Ticket descriptor path', () => { }); it('should delete the stowaway', async() => { + await page.waitForTimeout(1000); // initialization of functionality takes about 100ms to work await page.waitToClick(selectors.ticketDescriptor.moreMenu); await page.waitForContentLoaded(); await page.waitToClick(selectors.ticketDescriptor.moreMenuDeleteStowawayButton); @@ -176,6 +180,7 @@ describe('Ticket descriptor path', () => { describe('SMS', () => { it('should send the payment SMS using the descriptor menu', async() => { + await page.waitForTimeout(1000); // initialization of functionality takes about 100ms to work await page.waitToClick(selectors.ticketDescriptor.moreMenu); await page.waitForContentLoaded(); await page.waitToClick(selectors.ticketDescriptor.moreMenuPaymentSMS); diff --git a/e2e/paths/05-ticket/14_create_ticket.spec.js b/e2e/paths/05-ticket/14_create_ticket.spec.js index bfaa08775..bd5d86489 100644 --- a/e2e/paths/05-ticket/14_create_ticket.spec.js +++ b/e2e/paths/05-ticket/14_create_ticket.spec.js @@ -62,6 +62,7 @@ describe('Ticket create path', () => { }); it('should make the previously created ticket the stowaway of the current ticket', async() => { + await page.waitForTimeout(1000); // initialization of functionality takes about 100ms to work await page.waitToClick(selectors.ticketDescriptor.moreMenu); await page.waitToClick(selectors.ticketDescriptor.moreMenuAddStowaway); await page.waitToClick(selectors.ticketDescriptor.addStowawayDialogFirstTicket); diff --git a/e2e/paths/05-ticket/15_create_ticket_from_client.spec.js b/e2e/paths/05-ticket/15_create_ticket_from_client.spec.js index a68ce894e..914e6ea20 100644 --- a/e2e/paths/05-ticket/15_create_ticket_from_client.spec.js +++ b/e2e/paths/05-ticket/15_create_ticket_from_client.spec.js @@ -17,6 +17,7 @@ describe('Ticket create from client path', () => { }); it('should click the create simple ticket on the descriptor menu', async() => { + await page.waitForTimeout(1000); // initialization of functionality takes about 100ms to work await page.waitToClick(selectors.clientDescriptor.moreMenu); await page.waitToClick(selectors.clientDescriptor.simpleTicketButton); await page.waitForState('ticket.create'); diff --git a/e2e/paths/09-invoice-in/02_descriptor.spec.js b/e2e/paths/09-invoice-in/02_descriptor.spec.js index 02bbce7ac..20102b210 100644 --- a/e2e/paths/09-invoice-in/02_descriptor.spec.js +++ b/e2e/paths/09-invoice-in/02_descriptor.spec.js @@ -18,6 +18,7 @@ describe('InvoiceIn descriptor path', () => { }); it('should clone the invoiceIn using the descriptor more menu', async() => { + await page.waitForTimeout(1000); // initialization of functionality takes about 100ms to work await page.waitToClick(selectors.invoiceInDescriptor.moreMenu); await page.waitToClick(selectors.invoiceInDescriptor.moreMenuCloneInvoiceIn); await page.waitToClick(selectors.invoiceInDescriptor.acceptButton); @@ -31,6 +32,7 @@ describe('InvoiceIn descriptor path', () => { }); it('should delete the cloned invoiceIn using the descriptor more menu', async() => { + await page.waitForTimeout(1000); // initialization of functionality takes about 100ms to work await page.waitToClick(selectors.invoiceInDescriptor.moreMenu); await page.waitToClick(selectors.invoiceInDescriptor.moreMenuDeleteInvoiceIn); await page.waitToClick(selectors.invoiceInDescriptor.acceptButton); diff --git a/e2e/paths/09-invoice-out/03_manualInvoice.spec.js b/e2e/paths/09-invoice-out/03_manualInvoice.spec.js index 396f84bfb..cbf9f8935 100644 --- a/e2e/paths/09-invoice-out/03_manualInvoice.spec.js +++ b/e2e/paths/09-invoice-out/03_manualInvoice.spec.js @@ -16,6 +16,7 @@ describe('InvoiceOut manual invoice path', () => { }); it('should open the manual invoice form', async() => { + await page.waitForTimeout(1000); // initialization of functionality takes about 100ms to work await page.waitToClick(selectors.invoiceOutIndex.createInvoice); await page.waitToClick(selectors.invoiceOutIndex.createManualInvoice); await page.waitForSelector(selectors.invoiceOutIndex.manualInvoiceForm); @@ -44,6 +45,7 @@ describe('InvoiceOut manual invoice path', () => { }); it('should now open the manual invoice form', async() => { + await page.waitForTimeout(1000); // initialization of functionality takes about 100ms to work await page.waitToClick(selectors.invoiceOutIndex.createInvoice); await page.waitToClick(selectors.invoiceOutIndex.createManualInvoice); await page.waitForSelector(selectors.invoiceOutIndex.manualInvoiceForm); diff --git a/e2e/paths/10-travel/03_descriptor.spec.js b/e2e/paths/10-travel/03_descriptor.spec.js index 619228f35..19f62b80a 100644 --- a/e2e/paths/10-travel/03_descriptor.spec.js +++ b/e2e/paths/10-travel/03_descriptor.spec.js @@ -34,6 +34,7 @@ describe('Travel descriptor path', () => { }); it('should be redirected to the create entry view', async() => { + await page.waitForTimeout(1000); // initialization of functionality takes about 100ms to work await page.waitToClick(selectors.travelDescriptor.dotMenu); await page.waitToClick(selectors.travelDescriptor.dotMenuAddEntry); await page.waitForState('entry.create'); @@ -89,6 +90,7 @@ describe('Travel descriptor path', () => { }); it('should be redirected to the create travel when using the clone option of the dot menu', async() => { + await page.waitForTimeout(1000); // initialization of functionality takes about 100ms to work await page.waitToClick(selectors.travelDescriptor.dotMenu); await page.waitToClick(selectors.travelDescriptor.dotMenuClone); await page.respondToDialog('accept'); @@ -114,6 +116,7 @@ describe('Travel descriptor path', () => { }); it('should atempt to clone the travel and its entries using the descriptor menu but receive an error', async() => { + await page.waitForTimeout(1000); // initialization of functionality takes about 100ms to work await page.waitToClick(selectors.travelDescriptor.dotMenu); await page.waitToClick(selectors.travelDescriptor.dotMenuCloneWithEntries); await page.waitToClick(selectors.travelDescriptor.acceptClonation); diff --git a/e2e/paths/11-zone/02_descriptor.spec.js b/e2e/paths/11-zone/02_descriptor.spec.js index 1de84d601..fdf33c898 100644 --- a/e2e/paths/11-zone/02_descriptor.spec.js +++ b/e2e/paths/11-zone/02_descriptor.spec.js @@ -17,6 +17,7 @@ describe('Zone descriptor path', () => { }); it('should eliminate the zone using the descriptor option', async() => { + await page.waitForTimeout(1000); // initialization of functionality takes about 100ms to work await page.waitToClick(selectors.zoneDescriptor.menu); await page.waitToClick(selectors.zoneDescriptor.deleteZone); await page.respondToDialog('accept'); diff --git a/e2e/paths/14-account/01_create_and_basic_data.spec.js b/e2e/paths/14-account/01_create_and_basic_data.spec.js index 5a07119e7..37b785558 100644 --- a/e2e/paths/14-account/01_create_and_basic_data.spec.js +++ b/e2e/paths/14-account/01_create_and_basic_data.spec.js @@ -91,6 +91,7 @@ describe('Account create and basic data path', () => { }); it('should activate the account using the descriptor menu', async() => { + await page.waitForTimeout(1000); // initialization of functionality takes about 100ms to work await page.waitToClick(selectors.accountDescriptor.menuButton); await page.waitToClick(selectors.accountDescriptor.activateAccount); await page.waitToClick(selectors.accountDescriptor.acceptButton); From 85b4730c6c739a5c454bb6235da03a6959a8b8d2 Mon Sep 17 00:00:00 2001 From: joan Date: Fri, 15 Oct 2021 10:49:23 +0200 Subject: [PATCH 31/47] feat(monitor): show client risk to future on tickets Refs: 2624 --- .../back/methods/sales-monitor/salesFilter.js | 144 ++++++++++++------ .../front/index/search-panel/index.html | 2 +- .../monitor/front/index/search-panel/index.js | 2 +- .../front/index/search-panel/index.spec.js | 4 +- .../monitor/front/index/tickets/index.html | 2 +- modules/ticket/front/search-panel/index.html | 2 +- modules/ticket/front/search-panel/index.js | 2 +- .../ticket/front/search-panel/index.spec.js | 4 +- 8 files changed, 110 insertions(+), 52 deletions(-) diff --git a/modules/monitor/back/methods/sales-monitor/salesFilter.js b/modules/monitor/back/methods/sales-monitor/salesFilter.js index 5d49f07df..af7ce02de 100644 --- a/modules/monitor/back/methods/sales-monitor/salesFilter.js +++ b/modules/monitor/back/methods/sales-monitor/salesFilter.js @@ -130,54 +130,20 @@ module.exports = Self => { const where = buildFilter(ctx.args, (param, value) => { switch (param) { - case 'search': - return /^\d+$/.test(value) - ? {'t.id': {inq: value}} - : {'t.nickname': {like: `%${value}%`}}; case 'from': return {'t.shipped': {gte: value}}; case 'to': return {'t.shipped': {lte: value}}; - case 'nickname': - return {'t.nickname': {like: `%${value}%`}}; - case 'refFk': - return {'t.refFk': value}; case 'salesPersonFk': return {'c.salesPersonFk': value}; - case 'provinceFk': - return {'a.provinceFk': value}; - case 'stateFk': - return {'ts.stateFk': value}; case 'mine': case 'myTeam': if (value) return {'c.salesPersonFk': {inq: teamMembersId}}; else return {'c.salesPersonFk': {nin: teamMembersId}}; - - case 'alertLevel': - return {'ts.alertLevel': value}; - case 'pending': - if (value) { - return {and: [ - {'st.alertLevel': 0}, - {'st.code': {nin: [ - 'OK', - 'BOARDING', - 'PRINTED', - 'PRINTED_AUTO', - 'PICKER_DESIGNED' - ]}} - ]}; - } else { - return {and: [ - {'st.alertLevel': {gt: 0}} - ]}; - } case 'id': case 'clientFk': - case 'agencyModeFk': - case 'warehouseFk': param = `t.${param}`; return {[param]: value}; } @@ -217,6 +183,7 @@ module.exports = Self => { ts.code AS alertLevelCode, u.name AS userName, c.salesPersonFk, + c.credit, z.hour AS zoneLanding, z.name AS zoneName, z.id AS zoneFk, @@ -247,6 +214,47 @@ module.exports = Self => { stmt.merge(conn.makeWhere(filter.where)); stmts.push(stmt); + // Get client debt balance + stmts.push('DROP TEMPORARY TABLE IF EXISTS tmp.clientGetDebt'); + stmts.push(` + CREATE TEMPORARY TABLE tmp.clientGetDebt + (INDEX (clientFk)) + ENGINE = MEMORY + SELECT DISTINCT clientFk FROM tmp.filter`); + + stmt = new ParameterizedSQL('CALL clientGetDebt(?)', [args.to]); + stmts.push(stmt); + stmts.push('DROP TEMPORARY TABLE tmp.clientGetDebt'); + + stmts.push('DROP TEMPORARY TABLE IF EXISTS tmp.tickets'); + stmt = new ParameterizedSQL(` + CREATE TEMPORARY TABLE tmp.tickets + (INDEX (id)) + ENGINE = MEMORY + SELECT f.*, r.risk AS debt + FROM tmp.filter f + LEFT JOIN tmp.risk r ON f.clientFk = r.clientFk`); + stmts.push(stmt); + + // Sum risk to future + stmts.push(`SET @client:= 0`); + stmts.push('SET @risk := 0'); + stmts.push(` + UPDATE tmp.tickets + SET debt = IF(@client <> @client:= clientFk, + -totalWithVat + @risk:= - debt + totalWithVat, + -totalWithVat + @risk:= @risk + totalWithVat + ) + ORDER BY clientFk, shipped DESC + `); + + // Remove positive risks + stmts.push(` + UPDATE tmp.tickets t + SET debt = NULL + WHERE t.debt + t.credit >= 0 + `); + stmts.push('DROP TEMPORARY TABLE IF EXISTS tmp.sale_getProblems'); stmts.push(` CREATE TEMPORARY TABLE tmp.sale_getProblems @@ -260,17 +268,20 @@ module.exports = Self => { stmts.push('CALL ticket_getProblems(FALSE)'); stmt = new ParameterizedSQL(` - SELECT f.*, tp.* - FROM tmp.filter f - LEFT JOIN tmp.ticket_problems tp ON tp.ticketFk = f.id`); + SELECT t.*, tp.*, t.debt + t.credit AS risk, + ((t.debt + t.credit) + cc.riskTolerance < 0) AS hasHighRisk + FROM tmp.tickets t + LEFT JOIN tmp.ticket_problems tp ON tp.ticketFk = t.id + JOIN clientConfig cc`); const hasProblems = args.problems; if (hasProblems != undefined && (!args.from && !args.to)) throw new UserError('Choose a date range or days forward'); - let problemsFilter; + let finalFilter = {}; + let whereProblems; if (hasProblems === true) { - problemsFilter = {or: [ + whereProblems = {or: [ {'tp.isFreezed': true}, {'tp.risk': {gt: 0}}, {'tp.hasTicketRequest': true}, @@ -279,7 +290,7 @@ module.exports = Self => { {'tp.isAvailable': false} ]}; } else if (hasProblems === false) { - problemsFilter = {and: [ + whereProblems = {and: [ {'tp.isFreezed': false}, {'tp.risk': 0}, {'tp.hasTicketRequest': false}, @@ -289,8 +300,53 @@ module.exports = Self => { ]}; } - if (problemsFilter) - stmt.merge(conn.makeWhere(problemsFilter)); + if (whereProblems) finalFilter.where = whereProblems; + + const myWhere = buildFilter(ctx.args, (param, value) => { + switch (param) { + case 'search': + return /^\d+$/.test(value) + ? {'t.id': {inq: value}} + : {'t.nickname': {like: `%${value}%`}}; + + case 'nickname': + return {'t.nickname': {like: `%${value}%`}}; + case 'refFk': + return {'t.refFk': value}; + + case 'provinceFk': + return {'t.provinceFk': value}; + case 'stateFk': + return {'t.stateFk': value}; + case 'alertLevel': + return {'t.alertLevel': value}; + case 'pending': + if (value) { + return {and: [ + {'t.alertLevel': 0}, + {'t.alertLevelCode': {nin: [ + 'OK', + 'BOARDING', + 'PRINTED', + 'PRINTED_AUTO', + 'PICKER_DESIGNED' + ]}} + ]}; + } else { + return {and: [ + {'t.alertLevel': {gt: 0}} + ]}; + } + case 'agencyModeFk': + case 'warehouseFk': + param = `t.${param}`; + return {[param]: value}; + } + }); + + finalFilter = mergeFilters(finalFilter, {where: myWhere}); + if (finalFilter.where) + stmt.merge(conn.makeWhere(finalFilter.where)); stmt.merge(conn.makeOrderBy(filter.order)); stmt.merge(conn.makeLimit(filter)); @@ -299,7 +355,9 @@ module.exports = Self => { stmts.push( `DROP TEMPORARY TABLE tmp.filter, - tmp.ticket_problems`); + tmp.ticket_problems, + tmp.sale_getProblems, + tmp.risk`); let sql = ParameterizedSQL.join(stmts, ';'); let result = await conn.executeStmt(sql); diff --git a/modules/monitor/front/index/search-panel/index.html b/modules/monitor/front/index/search-panel/index.html index dc24c778b..5458202d2 100644 --- a/modules/monitor/front/index/search-panel/index.html +++ b/modules/monitor/front/index/search-panel/index.html @@ -70,7 +70,7 @@ diff --git a/modules/monitor/front/index/search-panel/index.js b/modules/monitor/front/index/search-panel/index.js index 057d555e4..ef6625e8a 100644 --- a/modules/monitor/front/index/search-panel/index.js +++ b/modules/monitor/front/index/search-panel/index.js @@ -14,7 +14,7 @@ class Controller extends SearchPanel { this.$http.get('AlertLevels').then(res => { for (let state of res.data) { groupedStates.push({ - alertLevel: state.alertLevel, + id: state.id, code: state.code, name: this.$t(state.code) }); diff --git a/modules/monitor/front/index/search-panel/index.spec.js b/modules/monitor/front/index/search-panel/index.spec.js index 0d19fd35f..f862e8d77 100644 --- a/modules/monitor/front/index/search-panel/index.spec.js +++ b/modules/monitor/front/index/search-panel/index.spec.js @@ -18,7 +18,7 @@ describe('Monitor Component vnMonitorSalesSearchPanel', () => { jest.spyOn(controller, '$t').mockReturnValue('miCodigo'); const data = [ { - alertLevel: 9999, + id: 9999, code: 'myCode' } ]; @@ -27,7 +27,7 @@ describe('Monitor Component vnMonitorSalesSearchPanel', () => { $httpBackend.flush(); expect(controller.groupedStates).toEqual([{ - alertLevel: 9999, + id: 9999, code: 'myCode', name: 'miCodigo' }]); diff --git a/modules/monitor/front/index/tickets/index.html b/modules/monitor/front/index/tickets/index.html index 45db04ca0..ff378adda 100644 --- a/modules/monitor/front/index/tickets/index.html +++ b/modules/monitor/front/index/tickets/index.html @@ -51,7 +51,7 @@ - + diff --git a/modules/ticket/front/search-panel/index.js b/modules/ticket/front/search-panel/index.js index 6ef47757a..ed86921e0 100644 --- a/modules/ticket/front/search-panel/index.js +++ b/modules/ticket/front/search-panel/index.js @@ -14,7 +14,7 @@ class Controller extends SearchPanel { this.$http.get('AlertLevels').then(res => { for (let state of res.data) { groupedStates.push({ - alertLevel: state.alertLevel, + id: state.id, code: state.code, name: this.$t(state.code) }); diff --git a/modules/ticket/front/search-panel/index.spec.js b/modules/ticket/front/search-panel/index.spec.js index f3a2f39ed..41c32c047 100644 --- a/modules/ticket/front/search-panel/index.spec.js +++ b/modules/ticket/front/search-panel/index.spec.js @@ -18,7 +18,7 @@ describe('Ticket Component vnTicketSearchPanel', () => { jest.spyOn(controller, '$t').mockReturnValue('miCodigo'); const data = [ { - alertLevel: 9999, + id: 9999, code: 'myCode' } ]; @@ -27,7 +27,7 @@ describe('Ticket Component vnTicketSearchPanel', () => { $httpBackend.flush(); expect(controller.groupedStates).toEqual([{ - alertLevel: 9999, + id: 9999, code: 'myCode', name: 'miCodigo' }]); From b6a9896cba900754305b50bf349afa0a9437cc9d Mon Sep 17 00:00:00 2001 From: joan Date: Fri, 15 Oct 2021 12:10:28 +0200 Subject: [PATCH 32/47] Fixed monitor problems filter --- .../back/methods/sales-monitor/salesFilter.js | 17 +++++++++++++---- .../sales-monitor/specs/salesFilter.spec.js | 2 +- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/modules/monitor/back/methods/sales-monitor/salesFilter.js b/modules/monitor/back/methods/sales-monitor/salesFilter.js index af7ce02de..e5f992e2f 100644 --- a/modules/monitor/back/methods/sales-monitor/salesFilter.js +++ b/modules/monitor/back/methods/sales-monitor/salesFilter.js @@ -251,7 +251,7 @@ module.exports = Self => { // Remove positive risks stmts.push(` UPDATE tmp.tickets t - SET debt = NULL + SET debt = 0 WHERE t.debt + t.credit >= 0 `); @@ -267,9 +267,18 @@ module.exports = Self => { AND f.shipped >= CURDATE()`); stmts.push('CALL ticket_getProblems(FALSE)'); + stmts.push(` + INSERT INTO tmp.ticket_problems (ticketFk, risk, totalProblems) + SELECT t.id, t.debt + t.credit AS risk, 1 + FROM tmp.tickets t + WHERE (t.debt + t.credit) < 0 + ON DUPLICATE KEY UPDATE + risk = t.debt + t.credit, totalProblems = totalProblems + 1 + `); + stmt = new ParameterizedSQL(` - SELECT t.*, tp.*, t.debt + t.credit AS risk, - ((t.debt + t.credit) + cc.riskTolerance < 0) AS hasHighRisk + SELECT t.*, tp.*, + ((tp.risk) + cc.riskTolerance < 0) AS hasHighRisk FROM tmp.tickets t LEFT JOIN tmp.ticket_problems tp ON tp.ticketFk = t.id JOIN clientConfig cc`); @@ -283,7 +292,7 @@ module.exports = Self => { if (hasProblems === true) { whereProblems = {or: [ {'tp.isFreezed': true}, - {'tp.risk': {gt: 0}}, + {'tp.risk': {lt: 0}}, {'tp.hasTicketRequest': true}, {'tp.hasComponentLack': true}, {'tp.isTaxDataChecked': false}, 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 53cd9941e..8a5136c80 100644 --- a/modules/monitor/back/methods/sales-monitor/specs/salesFilter.spec.js +++ b/modules/monitor/back/methods/sales-monitor/specs/salesFilter.spec.js @@ -23,7 +23,7 @@ describe('SalesMonitor salesFilter()', () => { const filter = {}; const result = await app.models.SalesMonitor.salesFilter(ctx, filter); - expect(result.length).toEqual(9); + expect(result.length).toEqual(13); }); it('should return the tickets matching the problems on false', async() => { From 629a8d25b7226841d5f57ae90a73bc657f1e0f52 Mon Sep 17 00:00:00 2001 From: joan Date: Fri, 15 Oct 2021 13:49:41 +0200 Subject: [PATCH 33/47] Updated pagination styles --- .../10370-pickles/00-ticket_getProblems.sql | 48 +++++++++++++++++++ .../components/pagination/pagination.html | 9 ++-- front/core/components/pagination/style.scss | 6 +++ 3 files changed, 59 insertions(+), 4 deletions(-) create mode 100644 db/changes/10370-pickles/00-ticket_getProblems.sql diff --git a/db/changes/10370-pickles/00-ticket_getProblems.sql b/db/changes/10370-pickles/00-ticket_getProblems.sql new file mode 100644 index 000000000..b58676a71 --- /dev/null +++ b/db/changes/10370-pickles/00-ticket_getProblems.sql @@ -0,0 +1,48 @@ +drop procedure `vn`.`ticket_getProblems`; + +DELIMITER $$ +$$ +create + definer = root@`%` procedure `vn`.`ticket_getProblems`(IN vIsTodayRelative tinyint(1)) +BEGIN +/** + * Calcula los problemas para un conjunto de tickets. + * Agrupados por ticket + * + * @table tmp.sale_getProblems(ticketFk, clientFk, warehouseFk, shipped) Identificadores de los tickets a calcular + * @return tmp.ticket_problems + */ + CALL sale_getProblems(vIsTodayRelative); + + DROP TEMPORARY TABLE IF EXISTS tmp.ticket_problems; + CREATE TEMPORARY TABLE tmp.ticket_problems + (PRIMARY KEY (ticketFk)) + ENGINE = MEMORY + SELECT + ticketFk, + MAX(p.isFreezed) AS isFreezed, + MAX(p.risk) AS risk, + MAX(p.hasHighRisk) AS hasHighRisk, + MAX(p.hasTicketRequest) AS hasTicketRequest, + MIN(p.isAvailable) AS isAvailable, + MAX(p.itemShortage) AS itemShortage, + MIN(p.isTaxDataChecked) AS isTaxDataChecked, + MAX(p.hasComponentLack) AS hasComponentLack, + 0 AS totalProblems + FROM tmp.sale_problems p + GROUP BY ticketFk; + + UPDATE tmp.ticket_problems tp + SET tp.totalProblems = ( + (tp.isFreezed) + + IF(tp.risk, TRUE, FALSE) + + (tp.hasTicketRequest) + + (tp.isAvailable = 0) + + (tp.isTaxDataChecked = 0) + + (tp.hasComponentLack) + ); + + DROP TEMPORARY TABLE + tmp.sale_problems; +END;;$$ +DELIMITER ; diff --git a/front/core/components/pagination/pagination.html b/front/core/components/pagination/pagination.html index 6809018dd..72d7c31ff 100644 --- a/front/core/components/pagination/pagination.html +++ b/front/core/components/pagination/pagination.html @@ -1,9 +1,10 @@ -
- +
- + + +
diff --git a/front/core/components/pagination/style.scss b/front/core/components/pagination/style.scss index 413a6fb5f..02dcb43e4 100644 --- a/front/core/components/pagination/style.scss +++ b/front/core/components/pagination/style.scss @@ -1,7 +1,13 @@ +@import "variables"; vn-pagination { display: block; text-align: center; + color: $color-primary; + + vn-button, vn-icon { + display: block + } & > div > vn-icon-button { font-size: 2rem; From 8fabd378e75fac5bb22f3a019bd049a3c70a1a50 Mon Sep 17 00:00:00 2001 From: joan Date: Fri, 15 Oct 2021 14:00:15 +0200 Subject: [PATCH 34/47] Removed version folder --- db/changes/10370-pickles/00-ACL.sql | 1 - .../10370-pickles/00-ticket_getProblems.sql | 48 ------------------- 2 files changed, 49 deletions(-) delete mode 100644 db/changes/10370-pickles/00-ACL.sql delete mode 100644 db/changes/10370-pickles/00-ticket_getProblems.sql diff --git a/db/changes/10370-pickles/00-ACL.sql b/db/changes/10370-pickles/00-ACL.sql deleted file mode 100644 index c5e10dec5..000000000 --- a/db/changes/10370-pickles/00-ACL.sql +++ /dev/null @@ -1 +0,0 @@ -UPDATE salix.ACL t SET t.principalId = 'employee' WHERE t.id = 269; diff --git a/db/changes/10370-pickles/00-ticket_getProblems.sql b/db/changes/10370-pickles/00-ticket_getProblems.sql deleted file mode 100644 index b58676a71..000000000 --- a/db/changes/10370-pickles/00-ticket_getProblems.sql +++ /dev/null @@ -1,48 +0,0 @@ -drop procedure `vn`.`ticket_getProblems`; - -DELIMITER $$ -$$ -create - definer = root@`%` procedure `vn`.`ticket_getProblems`(IN vIsTodayRelative tinyint(1)) -BEGIN -/** - * Calcula los problemas para un conjunto de tickets. - * Agrupados por ticket - * - * @table tmp.sale_getProblems(ticketFk, clientFk, warehouseFk, shipped) Identificadores de los tickets a calcular - * @return tmp.ticket_problems - */ - CALL sale_getProblems(vIsTodayRelative); - - DROP TEMPORARY TABLE IF EXISTS tmp.ticket_problems; - CREATE TEMPORARY TABLE tmp.ticket_problems - (PRIMARY KEY (ticketFk)) - ENGINE = MEMORY - SELECT - ticketFk, - MAX(p.isFreezed) AS isFreezed, - MAX(p.risk) AS risk, - MAX(p.hasHighRisk) AS hasHighRisk, - MAX(p.hasTicketRequest) AS hasTicketRequest, - MIN(p.isAvailable) AS isAvailable, - MAX(p.itemShortage) AS itemShortage, - MIN(p.isTaxDataChecked) AS isTaxDataChecked, - MAX(p.hasComponentLack) AS hasComponentLack, - 0 AS totalProblems - FROM tmp.sale_problems p - GROUP BY ticketFk; - - UPDATE tmp.ticket_problems tp - SET tp.totalProblems = ( - (tp.isFreezed) + - IF(tp.risk, TRUE, FALSE) + - (tp.hasTicketRequest) + - (tp.isAvailable = 0) + - (tp.isTaxDataChecked = 0) + - (tp.hasComponentLack) - ); - - DROP TEMPORARY TABLE - tmp.sale_problems; -END;;$$ -DELIMITER ; From e9539c76752c181ce21c42afa26e9d8e046e4dc0 Mon Sep 17 00:00:00 2001 From: joan Date: Fri, 15 Oct 2021 14:09:07 +0200 Subject: [PATCH 35/47] Restored SQL version --- db/changes/10370-pickles/00-ACL.sql | 1 + .../10370-pickles/00-ticket_getProblems.sql | 48 +++++++++++++++++++ db/changes/10370-pickles/delete.keep | 0 3 files changed, 49 insertions(+) create mode 100644 db/changes/10370-pickles/00-ACL.sql create mode 100644 db/changes/10370-pickles/00-ticket_getProblems.sql delete mode 100644 db/changes/10370-pickles/delete.keep diff --git a/db/changes/10370-pickles/00-ACL.sql b/db/changes/10370-pickles/00-ACL.sql new file mode 100644 index 000000000..c5e10dec5 --- /dev/null +++ b/db/changes/10370-pickles/00-ACL.sql @@ -0,0 +1 @@ +UPDATE salix.ACL t SET t.principalId = 'employee' WHERE t.id = 269; diff --git a/db/changes/10370-pickles/00-ticket_getProblems.sql b/db/changes/10370-pickles/00-ticket_getProblems.sql new file mode 100644 index 000000000..2ee057cd2 --- /dev/null +++ b/db/changes/10370-pickles/00-ticket_getProblems.sql @@ -0,0 +1,48 @@ +drop procedure `vn`.`ticket_getProblems`; + +DELIMITER $$ +$$ +create + definer = root@`%` procedure `vn`.`ticket_getProblems`(IN vIsTodayRelative tinyint(1)) +BEGIN +/** + * Calcula los problemas para un conjunto de tickets. + * Agrupados por ticket + * + * @table tmp.sale_getProblems(ticketFk, clientFk, warehouseFk, shipped) Identificadores de los tickets a calcular + * @return tmp.ticket_problems + */ + CALL sale_getProblems(vIsTodayRelative); + + DROP TEMPORARY TABLE IF EXISTS tmp.ticket_problems; + CREATE TEMPORARY TABLE tmp.ticket_problems + (PRIMARY KEY (ticketFk)) + ENGINE = MEMORY + SELECT + ticketFk, + MAX(p.isFreezed) AS isFreezed, + MAX(p.risk) AS risk, + MAX(p.hasHighRisk) AS hasHighRisk, + MAX(p.hasTicketRequest) AS hasTicketRequest, + MIN(p.isAvailable) AS isAvailable, + MAX(p.itemShortage) AS itemShortage, + MIN(p.isTaxDataChecked) AS isTaxDataChecked, + MAX(p.hasComponentLack) AS hasComponentLack, + 0 AS totalProblems + FROM tmp.sale_problems p + GROUP BY ticketFk; + + UPDATE tmp.ticket_problems tp + SET tp.totalProblems = ( + (tp.isFreezed) + + IF(tp.risk, TRUE, FALSE) + + (tp.hasTicketRequest) + + (tp.isAvailable = 0) + + (tp.isTaxDataChecked = 0) + + (tp.hasComponentLack) + ); + + DROP TEMPORARY TABLE + tmp.sale_problems; +END;;$$ +DELIMITER ; \ No newline at end of file diff --git a/db/changes/10370-pickles/delete.keep b/db/changes/10370-pickles/delete.keep deleted file mode 100644 index e69de29bb..000000000 From 5e8c216cd2356a48b1c1748ce16d4fd055883778 Mon Sep 17 00:00:00 2001 From: carlosjr Date: Fri, 15 Oct 2021 14:39:45 +0200 Subject: [PATCH 36/47] fix(dependencies): jasmine and it's reporters upgraded --- loopback/locale/en.json | 3 ++- package-lock.json | 38 ++++++++++++++++++++++---------------- package.json | 4 ++-- 3 files changed, 26 insertions(+), 19 deletions(-) diff --git a/loopback/locale/en.json b/loopback/locale/en.json index bc97eae19..8890e911f 100644 --- a/loopback/locale/en.json +++ b/loopback/locale/en.json @@ -116,5 +116,6 @@ "This client is not invoiceable": "This client is not invoiceable", "INACTIVE_PROVIDER": "Inactive provider", "reference duplicated": "reference duplicated", - "The PDF document does not exists": "The PDF document does not exists. Try regenerating it from 'Regenerate invoice PDF' option" + "The PDF document does not exists": "The PDF document does not exists. Try regenerating it from 'Regenerate invoice PDF' option", + "This item is not available": "This item is not available" } \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 645c55238..610514f47 100644 --- a/package-lock.json +++ b/package-lock.json @@ -72,9 +72,9 @@ "html-loader-jest": "^0.2.1", "html-webpack-plugin": "^4.0.0-beta.11", "identity-obj-proxy": "^3.0.0", - "jasmine": "^3.6.3", + "jasmine": "^3.10.0", "jasmine-reporters": "^2.4.0", - "jasmine-spec-reporter": "^6.0.0", + "jasmine-spec-reporter": "^7.0.0", "jest": "^26.0.1", "jest-junit": "^8.0.0", "json-loader": "^0.5.7", @@ -10877,20 +10877,22 @@ "integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=" }, "node_modules/jasmine": { - "version": "3.6.4", - "integrity": "sha512-hIeOou6y0BgCOKYgXYveQvlY+PTHgDPajFf+vLCYbMTQ+VjAP9+EQv0nuC9+gyCAAWISRFauB1XUb9kFuOKtcQ==", + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-3.10.0.tgz", + "integrity": "sha512-2Y42VsC+3CQCTzTwJezOvji4qLORmKIE0kwowWC+934Krn6ZXNQYljiwK5st9V3PVx96BSiDYXSB60VVah3IlQ==", "dev": true, "dependencies": { "glob": "^7.1.6", - "jasmine-core": "~3.6.0" + "jasmine-core": "~3.10.0" }, "bin": { "jasmine": "bin/jasmine.js" } }, "node_modules/jasmine-core": { - "version": "3.6.0", - "integrity": "sha512-8uQYa7zJN8hq9z+g8z1bqCfdC8eoDAeVnM5sfqs7KHv9/ifoJ500m018fpFc7RDaO6SWCLCXwo/wPSNcdYTgcw==", + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-3.10.0.tgz", + "integrity": "sha512-XWGaJ25RUdOQnjGiLoQa9QG/R4u1e9Bk4uhLdn9F4JCBco84L4SKM52bxci4vWTSUzhmhuHNAkAHFN/6Cox9wQ==", "dev": true }, "node_modules/jasmine-reporters": { @@ -10903,8 +10905,9 @@ } }, "node_modules/jasmine-spec-reporter": { - "version": "6.0.0", - "integrity": "sha512-MvTOVoMxDZAftQYBApIlSfKnGMzi9cj351nXeqtnZTuXffPlbONN31+Es7F+Ke4okUeQ2xISukt4U1npfzLVrQ==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/jasmine-spec-reporter/-/jasmine-spec-reporter-7.0.0.tgz", + "integrity": "sha512-OtC7JRasiTcjsaCBPtMO0Tl8glCejM4J4/dNuOJdA8lBjz4PmWjYQ6pzb0uzpBNAWJMDudYuj9OdXJWqM2QTJg==", "dev": true, "dependencies": { "colors": "1.4.0" @@ -31972,17 +31975,19 @@ } }, "jasmine": { - "version": "3.6.4", - "integrity": "sha512-hIeOou6y0BgCOKYgXYveQvlY+PTHgDPajFf+vLCYbMTQ+VjAP9+EQv0nuC9+gyCAAWISRFauB1XUb9kFuOKtcQ==", + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-3.10.0.tgz", + "integrity": "sha512-2Y42VsC+3CQCTzTwJezOvji4qLORmKIE0kwowWC+934Krn6ZXNQYljiwK5st9V3PVx96BSiDYXSB60VVah3IlQ==", "dev": true, "requires": { "glob": "^7.1.6", - "jasmine-core": "~3.6.0" + "jasmine-core": "~3.10.0" } }, "jasmine-core": { - "version": "3.6.0", - "integrity": "sha512-8uQYa7zJN8hq9z+g8z1bqCfdC8eoDAeVnM5sfqs7KHv9/ifoJ500m018fpFc7RDaO6SWCLCXwo/wPSNcdYTgcw==", + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-3.10.0.tgz", + "integrity": "sha512-XWGaJ25RUdOQnjGiLoQa9QG/R4u1e9Bk4uhLdn9F4JCBco84L4SKM52bxci4vWTSUzhmhuHNAkAHFN/6Cox9wQ==", "dev": true }, "jasmine-reporters": { @@ -31995,8 +32000,9 @@ } }, "jasmine-spec-reporter": { - "version": "6.0.0", - "integrity": "sha512-MvTOVoMxDZAftQYBApIlSfKnGMzi9cj351nXeqtnZTuXffPlbONN31+Es7F+Ke4okUeQ2xISukt4U1npfzLVrQ==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/jasmine-spec-reporter/-/jasmine-spec-reporter-7.0.0.tgz", + "integrity": "sha512-OtC7JRasiTcjsaCBPtMO0Tl8glCejM4J4/dNuOJdA8lBjz4PmWjYQ6pzb0uzpBNAWJMDudYuj9OdXJWqM2QTJg==", "dev": true, "requires": { "colors": "1.4.0" diff --git a/package.json b/package.json index ff70e2c4e..23a8d5eb8 100644 --- a/package.json +++ b/package.json @@ -75,9 +75,9 @@ "html-loader-jest": "^0.2.1", "html-webpack-plugin": "^4.0.0-beta.11", "identity-obj-proxy": "^3.0.0", - "jasmine": "^3.6.3", + "jasmine": "^3.10.0", "jasmine-reporters": "^2.4.0", - "jasmine-spec-reporter": "^6.0.0", + "jasmine-spec-reporter": "^7.0.0", "jest": "^26.0.1", "jest-junit": "^8.0.0", "json-loader": "^0.5.7", From 2a20a9194aac663c5c39560c99153006ed0be87a Mon Sep 17 00:00:00 2001 From: carlosjr Date: Fri, 15 Oct 2021 14:40:48 +0200 Subject: [PATCH 37/47] fix(puppeteer): chrimium now limited to single process with no child processes to avoid ram overload --- e2e/helpers/puppeteer.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/e2e/helpers/puppeteer.js b/e2e/helpers/puppeteer.js index b8dc8cfe3..97ec49260 100644 --- a/e2e/helpers/puppeteer.js +++ b/e2e/helpers/puppeteer.js @@ -7,6 +7,8 @@ export async function getBrowser() { const args = [ '--no-sandbox', `--window-size=${ 1920 },${ 1080 }`, + '--single-process', + '--no-zygote' // '--disable-dev-shm-usage' // '--full-memory-crash-report', // '--unlimited-storage' From f1611f8fe0b4607204ad98f9d7e1e8a02522a4fe Mon Sep 17 00:00:00 2001 From: carlosjr Date: Fri, 15 Oct 2021 14:42:27 +0200 Subject: [PATCH 38/47] fix(e2e): many e2e using descriptor more menu need a wait before using the options --- e2e/helpers/selectors.js | 2 +- e2e/paths/04-item/08_regularize.spec.js | 2 +- e2e/paths/05-ticket/01-sale/02_edit_sale.spec.js | 6 +++++- e2e/paths/05-ticket/09_weekly.spec.js | 4 ++-- e2e/paths/05-ticket/12_descriptor.spec.js | 12 +++++++----- e2e/paths/05-ticket/14_create_ticket.spec.js | 3 ++- .../05-ticket/15_create_ticket_from_client.spec.js | 2 +- e2e/paths/09-invoice-in/02_descriptor.spec.js | 4 ++-- e2e/paths/09-invoice-out/02_descriptor.spec.js | 1 + e2e/paths/09-invoice-out/03_manualInvoice.spec.js | 4 ++-- e2e/paths/10-travel/03_descriptor.spec.js | 6 +++--- e2e/paths/11-zone/02_descriptor.spec.js | 2 +- .../14-account/01_create_and_basic_data.spec.js | 3 ++- 13 files changed, 30 insertions(+), 21 deletions(-) diff --git a/e2e/helpers/selectors.js b/e2e/helpers/selectors.js index f63d67f8b..52c89743d 100644 --- a/e2e/helpers/selectors.js +++ b/e2e/helpers/selectors.js @@ -544,7 +544,7 @@ export default { }, ticketSales: { setOk: 'vn-ticket-sale vn-tool-bar > vn-button[label="Ok"] > button', - saleLine: 'vn-table div > vn-tbody > vn-tr', + saleLine: 'vn-table div > vn-tbody > vn-tr vn-check', saleDescriptorPopover: '.vn-popover.shown vn-item-descriptor', saleDescriptorPopoverSummaryButton: '.vn-popover.shown vn-item-descriptor a[ui-sref="item.card.summary({id: $ctrl.descriptor.id})"]', newItemButton: 'vn-ticket-sale vn-card vn-icon-button[icon="add_circle"]', diff --git a/e2e/paths/04-item/08_regularize.spec.js b/e2e/paths/04-item/08_regularize.spec.js index 6a4b85d06..d7bab3b7b 100644 --- a/e2e/paths/04-item/08_regularize.spec.js +++ b/e2e/paths/04-item/08_regularize.spec.js @@ -107,7 +107,7 @@ describe('Item regularize path', () => { }); it('should regularize the item once more', async() => { - await page.waitForTimeout(1000); // initialization of functionality takes about 100ms to work + await page.waitForTimeout(1000); // initialization of functionality takes about 1000ms to work await page.waitToClick(selectors.itemDescriptor.moreMenu); await page.waitToClick(selectors.itemDescriptor.moreMenuRegularizeButton); await page.write(selectors.itemDescriptor.regularizeQuantity, '100'); 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 6c82e31a7..0ce803bea 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 @@ -196,6 +196,7 @@ describe('Ticket Edit sale path', () => { }); it('should select the third sale and create a claim of it', async() => { + await page.waitForTimeout(1000); // initialization of functionality takes about 1000ms to work await page.waitToClick(selectors.ticketSales.thirdSaleCheckbox); await page.waitToClick(selectors.ticketSales.moreMenu); await page.waitToClick(selectors.ticketSales.moreMenuCreateClaim); @@ -340,9 +341,10 @@ describe('Ticket Edit sale path', () => { }); it('should confirm the new ticket received the line', async() => { + const expectedLines = 1; const result = await page.countElement(selectors.ticketSales.saleLine); - expect(result).toEqual(1); + expect(result).toEqual(expectedLines); }); it('should check the first sale reserved icon isnt visible', async() => { @@ -353,6 +355,7 @@ describe('Ticket Edit sale path', () => { it('should mark the first sale as reserved', async() => { await page.waitToClick(selectors.ticketSales.firstSaleCheckbox); + await page.waitForTimeout(1000); // initialization of functionality takes about 1000ms to work await page.waitToClick(selectors.ticketSales.moreMenu); await page.waitToClick(selectors.ticketSales.moreMenuReserve); await page.closePopup(); @@ -363,6 +366,7 @@ describe('Ticket Edit sale path', () => { }); it('should unmark the first sale as reserved', async() => { + await page.waitForTimeout(1000); // initialization of functionality takes about 1000ms to work await page.waitToClick(selectors.ticketSales.moreMenu); await page.waitToClick(selectors.ticketSales.moreMenuUnmarkReseved); await page.waitForClassPresent(selectors.ticketSales.firstSaleReservedIcon, 'ng-hide'); diff --git a/e2e/paths/05-ticket/09_weekly.spec.js b/e2e/paths/05-ticket/09_weekly.spec.js index abee26e0a..be5b1e153 100644 --- a/e2e/paths/05-ticket/09_weekly.spec.js +++ b/e2e/paths/05-ticket/09_weekly.spec.js @@ -28,7 +28,7 @@ describe('Ticket descriptor path', () => { }); it('should add the ticket to thursday turn using the descriptor more menu', async() => { - await page.waitForTimeout(1000); // initialization of functionality takes about 100ms to work + await page.waitForTimeout(1000); // initialization of functionality takes about 1000ms to work await page.waitToClick(selectors.ticketDescriptor.moreMenu); await page.waitToClick(selectors.ticketDescriptor.moreMenuAddToTurn); await page.waitToClick(selectors.ticketDescriptor.thursdayButton); @@ -64,7 +64,7 @@ describe('Ticket descriptor path', () => { }); it('should add the ticket to saturday turn using the descriptor more menu', async() => { - await page.waitForTimeout(1000); // initialization of functionality takes about 100ms to work + await page.waitForTimeout(1000); // initialization of functionality takes about 1000ms to work await page.waitToClick(selectors.ticketDescriptor.moreMenu); await page.waitToClick(selectors.ticketDescriptor.moreMenuAddToTurn); await page.waitToClick(selectors.ticketDescriptor.saturdayButton); diff --git a/e2e/paths/05-ticket/12_descriptor.spec.js b/e2e/paths/05-ticket/12_descriptor.spec.js index 247f91699..dcca61eab 100644 --- a/e2e/paths/05-ticket/12_descriptor.spec.js +++ b/e2e/paths/05-ticket/12_descriptor.spec.js @@ -22,7 +22,7 @@ describe('Ticket descriptor path', () => { }); it(`should update the shipped hour using the descriptor menu`, async() => { - await page.waitForTimeout(1000); // initialization of functionality takes about 100ms to work + await page.waitForTimeout(1000); // initialization of functionality takes about 1000ms to work await page.waitToClick(selectors.ticketDescriptor.moreMenu); await page.waitToClick(selectors.ticketDescriptor.moreMenuChangeShippedHour); await page.pickTime(selectors.ticketDescriptor.changeShippedHour, '08:15'); @@ -66,7 +66,7 @@ describe('Ticket descriptor path', () => { describe('Restore ticket', () => { it('should restore the ticket using the descriptor menu', async() => { - await page.waitForTimeout(1000); // initialization of functionality takes about 100ms to work + await page.waitForTimeout(1000); // initialization of functionality takes about 1000ms to work await page.waitToClick(selectors.ticketDescriptor.moreMenu); await page.waitToClick(selectors.ticketDescriptor.moreMenuRestoreTicket); await page.waitToClick(selectors.ticketDescriptor.acceptDialog); @@ -84,7 +84,7 @@ describe('Ticket descriptor path', () => { }); it('should open the add stowaway dialog', async() => { - await page.waitForTimeout(1000); // initialization of functionality takes about 100ms to work + await page.waitForTimeout(1000); // initialization of functionality takes about 1000ms to work await page.waitForFunction(() => { let element = document.querySelector('vn-ticket-descriptor-menu'); return element.$ctrl.canShowStowaway === true; @@ -117,7 +117,7 @@ describe('Ticket descriptor path', () => { }); it('should delete the stowaway', async() => { - await page.waitForTimeout(1000); // initialization of functionality takes about 100ms to work + await page.waitForTimeout(1000); // initialization of functionality takes about 1000ms to work await page.waitToClick(selectors.ticketDescriptor.moreMenu); await page.waitForContentLoaded(); await page.waitToClick(selectors.ticketDescriptor.moreMenuDeleteStowawayButton); @@ -149,6 +149,7 @@ describe('Ticket descriptor path', () => { }); it('should invoice the ticket using the descriptor menu', async() => { + await page.waitForTimeout(1000); // initialization of functionality takes about 1000ms to work await page.waitToClick(selectors.ticketDescriptor.moreMenu); await page.waitForContentLoaded(); await page.waitToClick(selectors.ticketDescriptor.moreMenuMakeInvoice); @@ -180,7 +181,7 @@ describe('Ticket descriptor path', () => { describe('SMS', () => { it('should send the payment SMS using the descriptor menu', async() => { - await page.waitForTimeout(1000); // initialization of functionality takes about 100ms to work + await page.waitForTimeout(2000); // initialization of functionality takes about 1000ms to work await page.waitToClick(selectors.ticketDescriptor.moreMenu); await page.waitForContentLoaded(); await page.waitToClick(selectors.ticketDescriptor.moreMenuPaymentSMS); @@ -193,6 +194,7 @@ describe('Ticket descriptor path', () => { }); it('should send the import SMS using the descriptor menu', async() => { + await page.waitForTimeout(1000); // initialization of functionality takes about 1000ms to work await page.waitToClick(selectors.ticketDescriptor.moreMenu); await page.waitForContentLoaded(); await page.waitToClick(selectors.ticketDescriptor.moreMenuSendImportSms); diff --git a/e2e/paths/05-ticket/14_create_ticket.spec.js b/e2e/paths/05-ticket/14_create_ticket.spec.js index bd5d86489..1c0e10e6d 100644 --- a/e2e/paths/05-ticket/14_create_ticket.spec.js +++ b/e2e/paths/05-ticket/14_create_ticket.spec.js @@ -62,7 +62,7 @@ describe('Ticket create path', () => { }); it('should make the previously created ticket the stowaway of the current ticket', async() => { - await page.waitForTimeout(1000); // initialization of functionality takes about 100ms to work + await page.waitForTimeout(1000); // initialization of functionality takes about 1000ms to work await page.waitToClick(selectors.ticketDescriptor.moreMenu); await page.waitToClick(selectors.ticketDescriptor.moreMenuAddStowaway); await page.waitToClick(selectors.ticketDescriptor.addStowawayDialogFirstTicket); @@ -72,6 +72,7 @@ describe('Ticket create path', () => { }); it('should delete the current ticket', async() => { + await page.waitForTimeout(1000); // initialization of functionality takes about 1000ms to work await page.waitToClick(selectors.ticketDescriptor.moreMenu); await page.waitToClick(selectors.ticketDescriptor.moreMenuDeleteTicket); await page.waitToClick(selectors.ticketDescriptor.acceptDialog); diff --git a/e2e/paths/05-ticket/15_create_ticket_from_client.spec.js b/e2e/paths/05-ticket/15_create_ticket_from_client.spec.js index 914e6ea20..a27050daa 100644 --- a/e2e/paths/05-ticket/15_create_ticket_from_client.spec.js +++ b/e2e/paths/05-ticket/15_create_ticket_from_client.spec.js @@ -17,7 +17,7 @@ describe('Ticket create from client path', () => { }); it('should click the create simple ticket on the descriptor menu', async() => { - await page.waitForTimeout(1000); // initialization of functionality takes about 100ms to work + await page.waitForTimeout(1000); // initialization of functionality takes about 1000ms to work await page.waitToClick(selectors.clientDescriptor.moreMenu); await page.waitToClick(selectors.clientDescriptor.simpleTicketButton); await page.waitForState('ticket.create'); diff --git a/e2e/paths/09-invoice-in/02_descriptor.spec.js b/e2e/paths/09-invoice-in/02_descriptor.spec.js index 20102b210..28b8e7ae3 100644 --- a/e2e/paths/09-invoice-in/02_descriptor.spec.js +++ b/e2e/paths/09-invoice-in/02_descriptor.spec.js @@ -18,7 +18,7 @@ describe('InvoiceIn descriptor path', () => { }); it('should clone the invoiceIn using the descriptor more menu', async() => { - await page.waitForTimeout(1000); // initialization of functionality takes about 100ms to work + await page.waitForTimeout(1000); // initialization of functionality takes about 1000ms to work await page.waitToClick(selectors.invoiceInDescriptor.moreMenu); await page.waitToClick(selectors.invoiceInDescriptor.moreMenuCloneInvoiceIn); await page.waitToClick(selectors.invoiceInDescriptor.acceptButton); @@ -32,7 +32,7 @@ describe('InvoiceIn descriptor path', () => { }); it('should delete the cloned invoiceIn using the descriptor more menu', async() => { - await page.waitForTimeout(1000); // initialization of functionality takes about 100ms to work + await page.waitForTimeout(1000); // initialization of functionality takes about 1000ms to work await page.waitToClick(selectors.invoiceInDescriptor.moreMenu); await page.waitToClick(selectors.invoiceInDescriptor.moreMenuDeleteInvoiceIn); await page.waitToClick(selectors.invoiceInDescriptor.acceptButton); diff --git a/e2e/paths/09-invoice-out/02_descriptor.spec.js b/e2e/paths/09-invoice-out/02_descriptor.spec.js index 8d403e083..222237b4f 100644 --- a/e2e/paths/09-invoice-out/02_descriptor.spec.js +++ b/e2e/paths/09-invoice-out/02_descriptor.spec.js @@ -38,6 +38,7 @@ describe('InvoiceOut descriptor path', () => { }); it('should delete the invoiceOut using the descriptor more menu', async() => { + await page.waitForTimeout(1000); // initialization of functionality takes about 1000ms to work await page.waitToClick(selectors.invoiceOutDescriptor.moreMenu); await page.waitToClick(selectors.invoiceOutDescriptor.moreMenuDeleteInvoiceOut); await page.waitToClick(selectors.invoiceOutDescriptor.acceptDeleteButton); diff --git a/e2e/paths/09-invoice-out/03_manualInvoice.spec.js b/e2e/paths/09-invoice-out/03_manualInvoice.spec.js index cbf9f8935..d32ab3f3c 100644 --- a/e2e/paths/09-invoice-out/03_manualInvoice.spec.js +++ b/e2e/paths/09-invoice-out/03_manualInvoice.spec.js @@ -16,7 +16,7 @@ describe('InvoiceOut manual invoice path', () => { }); it('should open the manual invoice form', async() => { - await page.waitForTimeout(1000); // initialization of functionality takes about 100ms to work + await page.waitForTimeout(1000); // initialization of functionality takes about 1000ms to work await page.waitToClick(selectors.invoiceOutIndex.createInvoice); await page.waitToClick(selectors.invoiceOutIndex.createManualInvoice); await page.waitForSelector(selectors.invoiceOutIndex.manualInvoiceForm); @@ -45,7 +45,7 @@ describe('InvoiceOut manual invoice path', () => { }); it('should now open the manual invoice form', async() => { - await page.waitForTimeout(1000); // initialization of functionality takes about 100ms to work + await page.waitForTimeout(1000); // initialization of functionality takes about 1000ms to work await page.waitToClick(selectors.invoiceOutIndex.createInvoice); await page.waitToClick(selectors.invoiceOutIndex.createManualInvoice); await page.waitForSelector(selectors.invoiceOutIndex.manualInvoiceForm); diff --git a/e2e/paths/10-travel/03_descriptor.spec.js b/e2e/paths/10-travel/03_descriptor.spec.js index 19f62b80a..d61818866 100644 --- a/e2e/paths/10-travel/03_descriptor.spec.js +++ b/e2e/paths/10-travel/03_descriptor.spec.js @@ -34,7 +34,7 @@ describe('Travel descriptor path', () => { }); it('should be redirected to the create entry view', async() => { - await page.waitForTimeout(1000); // initialization of functionality takes about 100ms to work + await page.waitForTimeout(1000); // initialization of functionality takes about 1000ms to work await page.waitToClick(selectors.travelDescriptor.dotMenu); await page.waitToClick(selectors.travelDescriptor.dotMenuAddEntry); await page.waitForState('entry.create'); @@ -90,7 +90,7 @@ describe('Travel descriptor path', () => { }); it('should be redirected to the create travel when using the clone option of the dot menu', async() => { - await page.waitForTimeout(1000); // initialization of functionality takes about 100ms to work + await page.waitForTimeout(1000); // initialization of functionality takes about 1000ms to work await page.waitToClick(selectors.travelDescriptor.dotMenu); await page.waitToClick(selectors.travelDescriptor.dotMenuClone); await page.respondToDialog('accept'); @@ -116,7 +116,7 @@ describe('Travel descriptor path', () => { }); it('should atempt to clone the travel and its entries using the descriptor menu but receive an error', async() => { - await page.waitForTimeout(1000); // initialization of functionality takes about 100ms to work + await page.waitForTimeout(1000); // initialization of functionality takes about 1000ms to work await page.waitToClick(selectors.travelDescriptor.dotMenu); await page.waitToClick(selectors.travelDescriptor.dotMenuCloneWithEntries); await page.waitToClick(selectors.travelDescriptor.acceptClonation); diff --git a/e2e/paths/11-zone/02_descriptor.spec.js b/e2e/paths/11-zone/02_descriptor.spec.js index fdf33c898..d88829907 100644 --- a/e2e/paths/11-zone/02_descriptor.spec.js +++ b/e2e/paths/11-zone/02_descriptor.spec.js @@ -17,7 +17,7 @@ describe('Zone descriptor path', () => { }); it('should eliminate the zone using the descriptor option', async() => { - await page.waitForTimeout(1000); // initialization of functionality takes about 100ms to work + await page.waitForTimeout(1000); // initialization of functionality takes about 1000ms to work await page.waitToClick(selectors.zoneDescriptor.menu); await page.waitToClick(selectors.zoneDescriptor.deleteZone); await page.respondToDialog('accept'); diff --git a/e2e/paths/14-account/01_create_and_basic_data.spec.js b/e2e/paths/14-account/01_create_and_basic_data.spec.js index 37b785558..204da363c 100644 --- a/e2e/paths/14-account/01_create_and_basic_data.spec.js +++ b/e2e/paths/14-account/01_create_and_basic_data.spec.js @@ -91,7 +91,7 @@ describe('Account create and basic data path', () => { }); it('should activate the account using the descriptor menu', async() => { - await page.waitForTimeout(1000); // initialization of functionality takes about 100ms to work + await page.waitForTimeout(1000); // initialization of functionality takes about 1000ms to work await page.waitToClick(selectors.accountDescriptor.menuButton); await page.waitToClick(selectors.accountDescriptor.activateAccount); await page.waitToClick(selectors.accountDescriptor.acceptButton); @@ -139,6 +139,7 @@ describe('Account create and basic data path', () => { describe('Set password', () => { it('should set the password using the descriptor menu', async() => { + await page.waitForTimeout(1000); // initialization of functionality takes about 1000ms to work await page.waitToClick(selectors.accountDescriptor.menuButton); await page.waitToClick(selectors.accountDescriptor.setPassword); await page.write(selectors.accountDescriptor.newPassword, 'quantum.crypt0graphy'); From 580ba363572779c40433c2692753e61d3c2d52fb Mon Sep 17 00:00:00 2001 From: carlosjr Date: Fri, 15 Oct 2021 14:45:41 +0200 Subject: [PATCH 39/47] refactor(jasmine): usage of done on async functions is deprecated --- .../back/methods/client/specs/canBeInvoiced.spec.js | 4 +--- modules/client/back/models/specs/address.spec.js | 4 +--- modules/entry/back/methods/entry/specs/importBuys.spec.js | 4 +--- .../back/methods/entry/specs/importBuysPreview.spec.js | 4 +--- .../order/back/methods/order-row/specs/addToOrder.spec.js | 4 +--- .../order/back/methods/order-row/specs/removes.spec.js | 4 +--- modules/order/back/methods/order/specs/new.spec.js | 4 +--- .../back/methods/order/specs/updateBasicData.spec.js | 4 +--- .../route/back/methods/route/specs/guessPriority.spec.js | 4 +--- .../route/back/methods/route/specs/insertTicket.spec.js | 4 +--- modules/supplier/back/models/specs/supplier.spec.js | 8 ++------ .../methods/ticket-tracking/specs/changeState.spec.js | 4 +--- .../methods/ticket-tracking/specs/setDelivered.spec.js | 3 +-- .../back/methods/ticket/specs/canBeInvoiced.spec.js | 4 +--- .../ticket/back/methods/ticket/specs/makeInvoice.spec.js | 4 +--- modules/ticket/back/models/specs/ticket-packaging.spec.js | 4 +--- .../back/methods/travel/specs/cloneWithEntries.spec.js | 4 +--- .../back/methods/travel/specs/deleteThermograph.spec.js | 4 +--- .../back/methods/department/specs/createChild.spec.js | 3 +-- .../back/methods/department/specs/moveChild.spec.js | 3 +-- .../back/methods/department/specs/removeChild.spec.js | 3 +-- modules/zone/back/methods/zone/specs/deleteZone.spec.js | 4 +--- 22 files changed, 23 insertions(+), 65 deletions(-) diff --git a/modules/client/back/methods/client/specs/canBeInvoiced.spec.js b/modules/client/back/methods/client/specs/canBeInvoiced.spec.js index 7b0640d2a..2f11d8013 100644 --- a/modules/client/back/methods/client/specs/canBeInvoiced.spec.js +++ b/modules/client/back/methods/client/specs/canBeInvoiced.spec.js @@ -8,12 +8,10 @@ describe('client canBeInvoiced()', () => { accessToken: {userId: userId} }; - beforeAll(async done => { + beforeAll(async() => { spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ active: activeCtx }); - - done(); }); it('should return falsy for a client without the data checked', async() => { diff --git a/modules/client/back/models/specs/address.spec.js b/modules/client/back/models/specs/address.spec.js index 3271c7d8f..cae18258f 100644 --- a/modules/client/back/models/specs/address.spec.js +++ b/modules/client/back/models/specs/address.spec.js @@ -4,13 +4,11 @@ describe('loopback model address', () => { let createdAddressId; const clientId = 1101; - afterAll(async done => { + afterAll(async() => { let client = await app.models.Client.findById(clientId); await app.models.Address.destroyById(createdAddressId); await client.updateAttribute('isEqualizated', false); - - done(); }); describe('observe()', () => { diff --git a/modules/entry/back/methods/entry/specs/importBuys.spec.js b/modules/entry/back/methods/entry/specs/importBuys.spec.js index 942ce0a0b..467c21e90 100644 --- a/modules/entry/back/methods/entry/specs/importBuys.spec.js +++ b/modules/entry/back/methods/entry/specs/importBuys.spec.js @@ -10,12 +10,10 @@ describe('entry import()', () => { accessToken: {userId: buyerId}, }; - beforeAll(async done => { + beforeAll(async() => { spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ active: activeCtx }); - - done(); }); it('should import the buy rows', async() => { diff --git a/modules/entry/back/methods/entry/specs/importBuysPreview.spec.js b/modules/entry/back/methods/entry/specs/importBuysPreview.spec.js index d286993ad..e62272c15 100644 --- a/modules/entry/back/methods/entry/specs/importBuysPreview.spec.js +++ b/modules/entry/back/methods/entry/specs/importBuysPreview.spec.js @@ -3,12 +3,10 @@ const LoopBackContext = require('loopback-context'); describe('entry importBuysPreview()', () => { const entryId = 1; - beforeAll(async done => { + beforeAll(async() => { spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ active: activeCtx }); - - done(); }); it('should return the buys with the calculated packageFk', async() => { diff --git a/modules/order/back/methods/order-row/specs/addToOrder.spec.js b/modules/order/back/methods/order-row/specs/addToOrder.spec.js index 3b832dee2..6e937176d 100644 --- a/modules/order/back/methods/order-row/specs/addToOrder.spec.js +++ b/modules/order/back/methods/order-row/specs/addToOrder.spec.js @@ -3,10 +3,8 @@ const app = require('vn-loopback/server/server'); describe('order addToOrder()', () => { const orderId = 8; let rowToDelete; - afterAll(async done => { + afterAll(async() => { await app.models.OrderRow.removes({rows: [rowToDelete], actualOrderId: orderId}); - - done(); }); it('should add a row to a given order', async() => { diff --git a/modules/order/back/methods/order-row/specs/removes.spec.js b/modules/order/back/methods/order-row/specs/removes.spec.js index 1c68c6052..510676aa0 100644 --- a/modules/order/back/methods/order-row/specs/removes.spec.js +++ b/modules/order/back/methods/order-row/specs/removes.spec.js @@ -4,12 +4,10 @@ describe('order removes()', () => { let row; let newRow; - beforeAll(async done => { + beforeAll(async() => { row = await app.models.OrderRow.findOne({where: {id: 12}}); row.id = null; newRow = await app.models.OrderRow.create(row); - - done(); }); it('should throw an error if rows property is empty', async() => { diff --git a/modules/order/back/methods/order/specs/new.spec.js b/modules/order/back/methods/order/specs/new.spec.js index 84e33b779..8caed2452 100644 --- a/modules/order/back/methods/order/specs/new.spec.js +++ b/modules/order/back/methods/order/specs/new.spec.js @@ -4,10 +4,8 @@ let UserError = require('vn-loopback/util/user-error'); describe('order new()', () => { let orderId; - afterAll(async done => { + afterAll(async() => { await app.models.Order.destroyById(orderId); - - done(); }); it('should throw an error if the client isnt active', async() => { diff --git a/modules/order/back/methods/order/specs/updateBasicData.spec.js b/modules/order/back/methods/order/specs/updateBasicData.spec.js index 5e83d69a0..adf009bc1 100644 --- a/modules/order/back/methods/order/specs/updateBasicData.spec.js +++ b/modules/order/back/methods/order/specs/updateBasicData.spec.js @@ -2,12 +2,10 @@ const app = require('vn-loopback/server/server'); describe('Order updateBasicData', () => { const orderId = 21; - afterAll(async done => { + afterAll(async() => { let validparams = {note: null}; await app.models.Order.updateBasicData(orderId, validparams); - - done(); }); it('should return an error if the order is confirmed', async() => { diff --git a/modules/route/back/methods/route/specs/guessPriority.spec.js b/modules/route/back/methods/route/specs/guessPriority.spec.js index 4e70d727e..892324acf 100644 --- a/modules/route/back/methods/route/specs/guessPriority.spec.js +++ b/modules/route/back/methods/route/specs/guessPriority.spec.js @@ -4,14 +4,12 @@ describe('route guessPriority()', () => { const targetRouteId = 7; let routeTicketsToRestore; - afterAll(async done => { + afterAll(async() => { let restoreFixtures = []; routeTicketsToRestore.forEach(ticket => { restoreFixtures.push(ticket.updateAttribute('priority', null)); }); await Promise.all(restoreFixtures); - - done(); }); it('should call guessPriority() and then check the tickets in the target route now have their priorities defined', async() => { diff --git a/modules/route/back/methods/route/specs/insertTicket.spec.js b/modules/route/back/methods/route/specs/insertTicket.spec.js index 9e7806496..7c60e755f 100644 --- a/modules/route/back/methods/route/specs/insertTicket.spec.js +++ b/modules/route/back/methods/route/specs/insertTicket.spec.js @@ -8,12 +8,10 @@ describe('route insertTicket()', () => { accessToken: {userId: deliveryId}, }; - beforeAll(async done => { + beforeAll(async() => { spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ active: activeCtx }); - - done(); }); it('should add the ticket to a route', async() => { diff --git a/modules/supplier/back/models/specs/supplier.spec.js b/modules/supplier/back/models/specs/supplier.spec.js index f7dd15139..c3c99e676 100644 --- a/modules/supplier/back/models/specs/supplier.spec.js +++ b/modules/supplier/back/models/specs/supplier.spec.js @@ -4,18 +4,14 @@ describe('loopback model Supplier', () => { let supplierOne; let supplierTwo; - beforeAll(async done => { + beforeAll(async() => { supplierOne = await app.models.Supplier.findById(1); supplierTwo = await app.models.Supplier.findById(442); - - done(); }); - afterAll(async done => { + afterAll(async() => { await supplierOne.updateAttribute('payMethodFk', supplierOne.payMethodFk); await supplierTwo.updateAttribute('payMethodFk', supplierTwo.payMethodFk); - - done(); }); describe('payMethodFk', () => { diff --git a/modules/ticket/back/methods/ticket-tracking/specs/changeState.spec.js b/modules/ticket/back/methods/ticket-tracking/specs/changeState.spec.js index 6bee334e4..746e1b7fc 100644 --- a/modules/ticket/back/methods/ticket-tracking/specs/changeState.spec.js +++ b/modules/ticket/back/methods/ticket-tracking/specs/changeState.spec.js @@ -30,12 +30,10 @@ describe('ticket changeState()', () => { agencyModeFk: 7 }; - beforeAll(async done => { + beforeAll(async() => { spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ active: activeCtx }); - - done(); }); it('should throw if the ticket is not editable and the user isnt production', async() => { 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 80c6055e5..3d37221c4 100644 --- a/modules/ticket/back/methods/ticket-tracking/specs/setDelivered.spec.js +++ b/modules/ticket/back/methods/ticket-tracking/specs/setDelivered.spec.js @@ -7,11 +7,10 @@ describe('ticket setDelivered()', () => { accessToken: {userId: userId}, }; - beforeAll(async done => { + beforeAll(async() => { spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ active: activeCtx }); - done(); }); it('should return the state which has been applied to the given tickets', async() => { diff --git a/modules/ticket/back/methods/ticket/specs/canBeInvoiced.spec.js b/modules/ticket/back/methods/ticket/specs/canBeInvoiced.spec.js index 05853acba..43f5b93df 100644 --- a/modules/ticket/back/methods/ticket/specs/canBeInvoiced.spec.js +++ b/modules/ticket/back/methods/ticket/specs/canBeInvoiced.spec.js @@ -8,12 +8,10 @@ describe('ticket canBeInvoiced()', () => { accessToken: {userId: userId} }; - beforeAll(async done => { + beforeAll(async() => { spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ active: activeCtx }); - - done(); }); it('should return falsy for an already invoiced ticket', async() => { diff --git a/modules/ticket/back/methods/ticket/specs/makeInvoice.spec.js b/modules/ticket/back/methods/ticket/specs/makeInvoice.spec.js index 36fc6732b..24d4a48ba 100644 --- a/modules/ticket/back/methods/ticket/specs/makeInvoice.spec.js +++ b/modules/ticket/back/methods/ticket/specs/makeInvoice.spec.js @@ -11,12 +11,10 @@ describe('ticket makeInvoice()', () => { }; const ctx = {req: activeCtx}; - beforeAll(async done => { + beforeAll(async() => { spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ active: activeCtx }); - - done(); }); it('should throw an error when invoicing tickets from multiple clients', async() => { diff --git a/modules/ticket/back/models/specs/ticket-packaging.spec.js b/modules/ticket/back/models/specs/ticket-packaging.spec.js index 893e0fb96..f2834643d 100644 --- a/modules/ticket/back/models/specs/ticket-packaging.spec.js +++ b/modules/ticket/back/models/specs/ticket-packaging.spec.js @@ -3,10 +3,8 @@ const app = require('vn-loopback/server/server'); describe('ticket model TicketTracking', () => { let ticketTrackingId; - afterAll(async done => { + afterAll(async() => { await app.models.TicketPackaging.destroyById(ticketTrackingId); - - done(); }); it('should save a ticketTraing as the quantity is greater than 0', async() => { diff --git a/modules/travel/back/methods/travel/specs/cloneWithEntries.spec.js b/modules/travel/back/methods/travel/specs/cloneWithEntries.spec.js index 1990072f6..b4bfecbfb 100644 --- a/modules/travel/back/methods/travel/specs/cloneWithEntries.spec.js +++ b/modules/travel/back/methods/travel/specs/cloneWithEntries.spec.js @@ -9,7 +9,7 @@ xdescribe('Travel cloneWithEntries()', () => { let travelBefore; let newTravelId; - afterAll(async done => { + afterAll(async() => { try { const entries = await models.Entry.find({ where: { @@ -44,8 +44,6 @@ xdescribe('Travel cloneWithEntries()', () => { } catch (error) { console.error(error); } - - done(); }); it(`should clone the travel and the containing entries`, async() => { diff --git a/modules/travel/back/methods/travel/specs/deleteThermograph.spec.js b/modules/travel/back/methods/travel/specs/deleteThermograph.spec.js index 215dd9a35..7dc7555d9 100644 --- a/modules/travel/back/methods/travel/specs/deleteThermograph.spec.js +++ b/modules/travel/back/methods/travel/specs/deleteThermograph.spec.js @@ -10,7 +10,7 @@ describe('Travel deleteThermograph()', () => { const ctx = {req: {accessToken: {userId: currentUserId}}}; let travelThermographBefore; - afterAll(async done => { + afterAll(async() => { await app.models.TravelThermograph.rawSql(` UPDATE travelThermograph SET travelFk = ?, dmsFk = ? @@ -19,8 +19,6 @@ describe('Travel deleteThermograph()', () => { travelThermographBefore.dmsFk, travelThermographBefore.id ]); - - done(); }); it(`should set the travelFk and dmsFk properties to null for travel thermograph removal`, async() => { diff --git a/modules/worker/back/methods/department/specs/createChild.spec.js b/modules/worker/back/methods/department/specs/createChild.spec.js index 305732f58..51891a6bf 100644 --- a/modules/worker/back/methods/department/specs/createChild.spec.js +++ b/modules/worker/back/methods/department/specs/createChild.spec.js @@ -3,9 +3,8 @@ const app = require('vn-loopback/server/server'); describe('department createChild()', () => { let createdChild; - afterAll(async done => { + afterAll(async() => { await createdChild.destroy(); - done(); }); it('should create a new child', async() => { diff --git a/modules/worker/back/methods/department/specs/moveChild.spec.js b/modules/worker/back/methods/department/specs/moveChild.spec.js index 3358ebf77..ca31784e8 100644 --- a/modules/worker/back/methods/department/specs/moveChild.spec.js +++ b/modules/worker/back/methods/department/specs/moveChild.spec.js @@ -3,10 +3,9 @@ const app = require('vn-loopback/server/server'); describe('department moveChild()', () => { let updatedChild; - afterAll(async done => { + afterAll(async() => { const child = await app.models.Department.findById(updatedChild.id); await child.updateAttribute('parentFk', null); - done(); }); it('should move a child department to a new parent', async() => { diff --git a/modules/worker/back/methods/department/specs/removeChild.spec.js b/modules/worker/back/methods/department/specs/removeChild.spec.js index 1fe3d10ef..d83e1b819 100644 --- a/modules/worker/back/methods/department/specs/removeChild.spec.js +++ b/modules/worker/back/methods/department/specs/removeChild.spec.js @@ -3,9 +3,8 @@ const app = require('vn-loopback/server/server'); describe('department removeChild()', () => { let removedChild; - afterAll(async done => { + afterAll(async() => { await app.models.Department.create(removedChild); - done(); }); it('should remove a child department', async() => { diff --git a/modules/zone/back/methods/zone/specs/deleteZone.spec.js b/modules/zone/back/methods/zone/specs/deleteZone.spec.js index 5dbfe0401..d8abe1da8 100644 --- a/modules/zone/back/methods/zone/specs/deleteZone.spec.js +++ b/modules/zone/back/methods/zone/specs/deleteZone.spec.js @@ -11,7 +11,7 @@ describe('zone deletezone()', () => { let ticketIDs; let originalTicketStates; - beforeAll(async done => { + beforeAll(async() => { spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ active: activeCtx }); @@ -28,8 +28,6 @@ describe('zone deletezone()', () => { } catch (error) { console.error(error); } - - done(); }); it('should delete a zone and update their tickets', async() => { From 270b2802c8fd85614f6707cb638636a3392be5ba Mon Sep 17 00:00:00 2001 From: carlosjr Date: Fri, 15 Oct 2021 15:31:13 +0200 Subject: [PATCH 40/47] refactor(transactions): added transaction to sendChechingPresence and corrected a typo --- modules/account/back/models/ldap-config.js | 4 ++-- modules/ticket/back/methods/ticket/updateDiscount.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/account/back/models/ldap-config.js b/modules/account/back/models/ldap-config.js index f61aa2db5..819659066 100644 --- a/modules/account/back/models/ldap-config.js +++ b/modules/account/back/models/ldap-config.js @@ -77,8 +77,8 @@ module.exports = Self => { .toString('base64'); let hash = crypto.createHash('sha1'); - hash.updateAll(password); - hash.updateAll(salt, 'binary'); + hash.update(password); + hash.update(salt, 'binary'); let digest = hash.digest('binary'); let ssha = Buffer diff --git a/modules/ticket/back/methods/ticket/updateDiscount.js b/modules/ticket/back/methods/ticket/updateDiscount.js index 8d5c4a32d..cd6a5fabc 100644 --- a/modules/ticket/back/methods/ticket/updateDiscount.js +++ b/modules/ticket/back/methods/ticket/updateDiscount.js @@ -148,7 +148,7 @@ module.exports = Self => { ticketUrl: `${origin}/#!/ticket/${id}/sale`, changes: changesMade }); - await models.Chat.sendCheckingPresence(ctx, salesPerson.id, message); + await models.Chat.sendCheckingPresence(ctx, salesPerson.id, message, myOptions); } if (tx) await tx.commit(); From de7af0fee2eeca7cadf5b3d5710148bd8f4e46ca Mon Sep 17 00:00:00 2001 From: carlosjr Date: Fri, 15 Oct 2021 15:59:59 +0200 Subject: [PATCH 41/47] fix(transaction): priceDifference now commits its created transaction --- .../back/methods/ticket/priceDifference.js | 125 +++++++++--------- 1 file changed, 66 insertions(+), 59 deletions(-) diff --git a/modules/ticket/back/methods/ticket/priceDifference.js b/modules/ticket/back/methods/ticket/priceDifference.js index 202a619a5..2456d3de0 100644 --- a/modules/ticket/back/methods/ticket/priceDifference.js +++ b/modules/ticket/back/methods/ticket/priceDifference.js @@ -66,70 +66,77 @@ module.exports = Self => { myOptions.transaction = tx; } - const isEditable = await Self.isEditable(ctx, args.id, myOptions); + try { + const isEditable = await Self.isEditable(ctx, args.id, myOptions); - if (!isEditable) - throw new UserError(`The sales of this ticket can't be modified`); + if (!isEditable) + throw new UserError(`The sales of this ticket can't be modified`); - const isProductionBoss = await models.Account.hasRole(userId, 'productionBoss', myOptions); - if (!isProductionBoss) { - const zoneShipped = await models.Agency.getShipped( - args.landed, - args.addressId, - args.agencyModeId, - args.warehouseId, - myOptions); + const isProductionBoss = await models.Account.hasRole(userId, 'productionBoss', myOptions); + if (!isProductionBoss) { + const zoneShipped = await models.Agency.getShipped( + args.landed, + args.addressId, + args.agencyModeId, + args.warehouseId, + myOptions); - if (!zoneShipped || zoneShipped.zoneFk != args.zoneId) - throw new UserError(`You don't have privileges to change the zone`); - } - - const items = await models.Sale.find({ - where: { - ticketFk: args.id - }, - order: 'concept ASC', - include: 'item' - }, myOptions); - - const salesObj = { - items: items, - totalUnitPrice: 0.00, - totalNewPrice: 0.00, - totalDifference: 0.00, - }; - - const query = `CALL vn.ticket_priceDifference(?, ?, ?, ?, ?)`; - const params = [args.id, args.landed, args.addressId, args.zoneId, args.warehouseId]; - const [difComponents] = await Self.rawSql(query, params, myOptions); - - const map = new Map(); - - // Sale price component, one per sale - for (difComponent of difComponents) - map.set(difComponent.saleFk, difComponent); - - function round(value) { - return Math.round(value * 100) / 100; - } - - for (sale of salesObj.items) { - const difComponent = map.get(sale.id); - - if (difComponent) { - sale.component = difComponent; - - salesObj.totalDifference += difComponent.difference; - salesObj.totalDifference = round(salesObj.totalDifference); - - salesObj.totalNewPrice += difComponent.newPrice; - salesObj.totalNewPrice = round(salesObj.totalNewPrice); + if (!zoneShipped || zoneShipped.zoneFk != args.zoneId) + throw new UserError(`You don't have privileges to change the zone`); } - salesObj.totalUnitPrice += sale.price; - salesObj.totalUnitPrice = round(salesObj.totalUnitPrice); - } + const items = await models.Sale.find({ + where: { + ticketFk: args.id + }, + order: 'concept ASC', + include: 'item' + }, myOptions); - return salesObj; + const salesObj = { + items: items, + totalUnitPrice: 0.00, + totalNewPrice: 0.00, + totalDifference: 0.00, + }; + + const query = `CALL vn.ticket_priceDifference(?, ?, ?, ?, ?)`; + const params = [args.id, args.landed, args.addressId, args.zoneId, args.warehouseId]; + const [difComponents] = await Self.rawSql(query, params, myOptions); + + const map = new Map(); + + // Sale price component, one per sale + for (difComponent of difComponents) + map.set(difComponent.saleFk, difComponent); + + for (sale of salesObj.items) { + const difComponent = map.get(sale.id); + + if (difComponent) { + sale.component = difComponent; + + salesObj.totalDifference += difComponent.difference; + salesObj.totalDifference = round(salesObj.totalDifference); + + salesObj.totalNewPrice += difComponent.newPrice; + salesObj.totalNewPrice = round(salesObj.totalNewPrice); + } + + salesObj.totalUnitPrice += sale.price; + salesObj.totalUnitPrice = round(salesObj.totalUnitPrice); + } + + if (tx) await tx.commit(); + + return salesObj; + } catch (e) { + if (tx) await tx.rollback(); + throw e; + } }; + + function round(value) { + return Math.round(value * 100) / 100; + } }; From c4c1aa929a858809932227b6939c2bbc64e099f5 Mon Sep 17 00:00:00 2001 From: carlosjr Date: Fri, 15 Oct 2021 16:00:50 +0200 Subject: [PATCH 42/47] refactor(endpoints): corrected indentation and removed unused code --- back/methods/dms/updateFile.js | 1 + back/methods/dms/uploadFile.js | 1 + back/models/image.js | 1 + modules/entry/back/methods/entry/deleteBuys.js | 1 + modules/entry/back/methods/entry/importBuys.js | 1 + modules/ticket/back/methods/ticket/componentUpdate.js | 3 --- modules/zone/back/methods/zone/clone.js | 1 + 7 files changed, 6 insertions(+), 3 deletions(-) diff --git a/back/methods/dms/updateFile.js b/back/methods/dms/updateFile.js index 314761932..161f4728c 100644 --- a/back/methods/dms/updateFile.js +++ b/back/methods/dms/updateFile.js @@ -89,6 +89,7 @@ module.exports = Self => { await uploadNewFile(ctx, dms, myOptions); if (tx) await tx.commit(); + return dms; } catch (e) { if (tx) await tx.rollback(); diff --git a/back/methods/dms/uploadFile.js b/back/methods/dms/uploadFile.js index d6540cbc5..6bda1e6db 100644 --- a/back/methods/dms/uploadFile.js +++ b/back/methods/dms/uploadFile.js @@ -96,6 +96,7 @@ module.exports = Self => { } if (tx) await tx.commit(); + return addedDms; } catch (e) { if (tx) await tx.rollback(); diff --git a/back/models/image.js b/back/models/image.js index a35018814..d736e924f 100644 --- a/back/models/image.js +++ b/back/models/image.js @@ -151,6 +151,7 @@ module.exports = Self => { await fs.unlink(srcFilePath); await tx.commit(); + return newImage; } catch (e) { await tx.rollback(); diff --git a/modules/entry/back/methods/entry/deleteBuys.js b/modules/entry/back/methods/entry/deleteBuys.js index 951abfd4c..ce5ff6a7d 100644 --- a/modules/entry/back/methods/entry/deleteBuys.js +++ b/modules/entry/back/methods/entry/deleteBuys.js @@ -41,6 +41,7 @@ module.exports = Self => { const deleted = await Promise.all(promises); if (tx) await tx.commit(); + return deleted; } catch (e) { if (tx) await tx.rollback(); diff --git a/modules/entry/back/methods/entry/importBuys.js b/modules/entry/back/methods/entry/importBuys.js index 3ed8ac1c7..f3bf37dde 100644 --- a/modules/entry/back/methods/entry/importBuys.js +++ b/modules/entry/back/methods/entry/importBuys.js @@ -97,6 +97,7 @@ module.exports = Self => { const sql = ParameterizedSQL.join(stmts, ';'); await conn.executeStmt(sql, myOptions); + if (tx) await tx.commit(); } catch (e) { if (tx) await tx.rollback(); diff --git a/modules/ticket/back/methods/ticket/componentUpdate.js b/modules/ticket/back/methods/ticket/componentUpdate.js index 133cdeb03..515689649 100644 --- a/modules/ticket/back/methods/ticket/componentUpdate.js +++ b/modules/ticket/back/methods/ticket/componentUpdate.js @@ -117,9 +117,6 @@ module.exports = Self => { if (!zoneShipped || zoneShipped.zoneFk != args.zoneFk) throw new UserError(`You don't have privileges to change the zone`); } - const observationTypeDelivery = await models.ObservationType.findOne({ - where: {code: 'delivery'} - }, myOptions); const originalTicket = await models.Ticket.findOne({ where: {id: args.id}, diff --git a/modules/zone/back/methods/zone/clone.js b/modules/zone/back/methods/zone/clone.js index a6f94a727..64dc5aa55 100644 --- a/modules/zone/back/methods/zone/clone.js +++ b/modules/zone/back/methods/zone/clone.js @@ -70,6 +70,7 @@ module.exports = Self => { await models.ZoneIncluded.create(newIncludedGeo, myOptions); await models.ZoneEvent.create(newCalendarDays, myOptions); + if (tx) await tx.commit(); return newZone; From ace1c9c84bbfacc4ef9bba9a8717833fb2bb0466 Mon Sep 17 00:00:00 2001 From: carlosjr Date: Fri, 15 Oct 2021 15:59:59 +0200 Subject: [PATCH 43/47] fix(transaction): priceDifference now commits its created transaction --- .../back/methods/ticket/priceDifference.js | 125 +++++++++--------- 1 file changed, 66 insertions(+), 59 deletions(-) diff --git a/modules/ticket/back/methods/ticket/priceDifference.js b/modules/ticket/back/methods/ticket/priceDifference.js index 202a619a5..2456d3de0 100644 --- a/modules/ticket/back/methods/ticket/priceDifference.js +++ b/modules/ticket/back/methods/ticket/priceDifference.js @@ -66,70 +66,77 @@ module.exports = Self => { myOptions.transaction = tx; } - const isEditable = await Self.isEditable(ctx, args.id, myOptions); + try { + const isEditable = await Self.isEditable(ctx, args.id, myOptions); - if (!isEditable) - throw new UserError(`The sales of this ticket can't be modified`); + if (!isEditable) + throw new UserError(`The sales of this ticket can't be modified`); - const isProductionBoss = await models.Account.hasRole(userId, 'productionBoss', myOptions); - if (!isProductionBoss) { - const zoneShipped = await models.Agency.getShipped( - args.landed, - args.addressId, - args.agencyModeId, - args.warehouseId, - myOptions); + const isProductionBoss = await models.Account.hasRole(userId, 'productionBoss', myOptions); + if (!isProductionBoss) { + const zoneShipped = await models.Agency.getShipped( + args.landed, + args.addressId, + args.agencyModeId, + args.warehouseId, + myOptions); - if (!zoneShipped || zoneShipped.zoneFk != args.zoneId) - throw new UserError(`You don't have privileges to change the zone`); - } - - const items = await models.Sale.find({ - where: { - ticketFk: args.id - }, - order: 'concept ASC', - include: 'item' - }, myOptions); - - const salesObj = { - items: items, - totalUnitPrice: 0.00, - totalNewPrice: 0.00, - totalDifference: 0.00, - }; - - const query = `CALL vn.ticket_priceDifference(?, ?, ?, ?, ?)`; - const params = [args.id, args.landed, args.addressId, args.zoneId, args.warehouseId]; - const [difComponents] = await Self.rawSql(query, params, myOptions); - - const map = new Map(); - - // Sale price component, one per sale - for (difComponent of difComponents) - map.set(difComponent.saleFk, difComponent); - - function round(value) { - return Math.round(value * 100) / 100; - } - - for (sale of salesObj.items) { - const difComponent = map.get(sale.id); - - if (difComponent) { - sale.component = difComponent; - - salesObj.totalDifference += difComponent.difference; - salesObj.totalDifference = round(salesObj.totalDifference); - - salesObj.totalNewPrice += difComponent.newPrice; - salesObj.totalNewPrice = round(salesObj.totalNewPrice); + if (!zoneShipped || zoneShipped.zoneFk != args.zoneId) + throw new UserError(`You don't have privileges to change the zone`); } - salesObj.totalUnitPrice += sale.price; - salesObj.totalUnitPrice = round(salesObj.totalUnitPrice); - } + const items = await models.Sale.find({ + where: { + ticketFk: args.id + }, + order: 'concept ASC', + include: 'item' + }, myOptions); - return salesObj; + const salesObj = { + items: items, + totalUnitPrice: 0.00, + totalNewPrice: 0.00, + totalDifference: 0.00, + }; + + const query = `CALL vn.ticket_priceDifference(?, ?, ?, ?, ?)`; + const params = [args.id, args.landed, args.addressId, args.zoneId, args.warehouseId]; + const [difComponents] = await Self.rawSql(query, params, myOptions); + + const map = new Map(); + + // Sale price component, one per sale + for (difComponent of difComponents) + map.set(difComponent.saleFk, difComponent); + + for (sale of salesObj.items) { + const difComponent = map.get(sale.id); + + if (difComponent) { + sale.component = difComponent; + + salesObj.totalDifference += difComponent.difference; + salesObj.totalDifference = round(salesObj.totalDifference); + + salesObj.totalNewPrice += difComponent.newPrice; + salesObj.totalNewPrice = round(salesObj.totalNewPrice); + } + + salesObj.totalUnitPrice += sale.price; + salesObj.totalUnitPrice = round(salesObj.totalUnitPrice); + } + + if (tx) await tx.commit(); + + return salesObj; + } catch (e) { + if (tx) await tx.rollback(); + throw e; + } }; + + function round(value) { + return Math.round(value * 100) / 100; + } }; From 1ba2a924e63ed102d6b28127797f1b0f1b6b6736 Mon Sep 17 00:00:00 2001 From: carlosjr Date: Fri, 15 Oct 2021 16:15:00 +0200 Subject: [PATCH 44/47] refactor(print): chrimoum is now a single process on each instance with no child processes --- print/boot.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/print/boot.js b/print/boot.js index 5e84bb5dd..8cd0eaad7 100644 --- a/print/boot.js +++ b/print/boot.js @@ -58,7 +58,12 @@ module.exports = async app => { async function launchBrowser() { config.browser = await puppeteer.launch({ headless: true, - args: ['--no-sandbox', '--disable-setuid-sandbox'] + args: [ + '--no-sandbox', + '--disable-setuid-sandbox', + '--single-process', + '--no-zygote' + ] }); config.browser.on('disconnected', launchBrowser); From da5be333d9539c6b441ecabef9767eb102412baf Mon Sep 17 00:00:00 2001 From: joan Date: Mon, 18 Oct 2021 08:22:14 +0200 Subject: [PATCH 45/47] fix(osticket): don't show resolved tickets by other deparments --- print/templates/email/osticket-report/sql/tickets.sql | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/print/templates/email/osticket-report/sql/tickets.sql b/print/templates/email/osticket-report/sql/tickets.sql index 7cb35aaab..50b15473d 100644 --- a/print/templates/email/osticket-report/sql/tickets.sql +++ b/print/templates/email/osticket-report/sql/tickets.sql @@ -9,6 +9,7 @@ SELECT * FROM ( ote.body AS description, oter.body AS resolution FROM ost_ticket ot + JOIN ost_department od ON od.id = ot.dept_id JOIN ost_ticket__cdata otc ON ot.ticket_id = otc.ticket_id JOIN ost_ticket_status ots ON ot.status_id = ots.id JOIN ost_user otu ON ot.user_id = otu.id @@ -20,8 +21,9 @@ SELECT * FROM ( LEFT JOIN ost_thread_entry oter ON oth.id = oter.thread_id AND oter.type = 'R' WHERE ot.ticket_pid IS NULL - AND ots.state = 'closed' AND ot.closed BETWEEN ? AND ? + AND ots.state = 'closed' + AND od.code = 'IT' ORDER BY oter.created DESC ) ot GROUP BY ot.ticket_id ORDER BY ot.assigned \ No newline at end of file From ff2a1e761738d53e1f4a9ffc1f2945a8e39610b0 Mon Sep 17 00:00:00 2001 From: joan Date: Mon, 18 Oct 2021 10:14:04 +0200 Subject: [PATCH 46/47] Removed comments --- front/core/components/popover/index.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/front/core/components/popover/index.js b/front/core/components/popover/index.js index 9567102db..8dbae629c 100644 --- a/front/core/components/popover/index.js +++ b/front/core/components/popover/index.js @@ -99,8 +99,6 @@ export default class Popover extends Popup { left = parentRect.left + parentRect.width / 2 - width / 2; left = clamp(left, margin, maxRight - width); } - /* let left = parentRect.left + parentRect.width / 2 - width / 2; - left = clamp(left, margin, maxRight - width); */ let top; if (this.direction == 'left') @@ -122,7 +120,6 @@ export default class Popover extends Popup { if (this.direction == 'left') { arrowLeft = 0; let arrowTop = arrowOffset; - // arrowLeft = clamp(arrowLeft, arrowHeight, width - arrowHeight); arrowStyle.top = `${arrowTop}px`; } else { arrowLeft = (parentRect.left - left) + parentRect.width / 2; From ec011cbc4ebd26ab439232a40eee9ee1798b1761 Mon Sep 17 00:00:00 2001 From: joan Date: Mon, 18 Oct 2021 10:51:20 +0200 Subject: [PATCH 47/47] Updated JSDOC param --- front/core/components/popover/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/front/core/components/popover/index.js b/front/core/components/popover/index.js index 8dbae629c..446c0697b 100644 --- a/front/core/components/popover/index.js +++ b/front/core/components/popover/index.js @@ -23,6 +23,7 @@ export default class Popover extends Popup { * it is shown in a visible relative position to it. * * @param {HTMLElement|Event} parent Overrides the parent property + * @param {String} direction - Direction [left] */ show(parent, direction) { if (parent instanceof Event)