From 0c517800e055ba5db521e2a8cc99b1164162122b Mon Sep 17 00:00:00 2001 From: JurTI-BR Date: Thu, 13 Mar 2025 22:27:19 -0300 Subject: [PATCH 1/5] setup da configuracao do redis --- package-lock.json | 507 +++++++++++++++++- package.json | 6 +- src/app.module.ts | 7 + src/configs/typeorm.config.ts | 3 +- src/main.ts | 3 +- src/redis/redis.module.ts | 8 + src/redis/redis.providers.ts | 12 + src/sales/customer/customer.service.ts | 6 +- .../sales/placesinterior.service.spec.ts | 49 ++ src/sales/sales/sales.controller.ts | 232 ++++---- src/sales/sales/sales.module.ts | 3 +- src/sales/sales/sales.service.ts | 436 +++++---------- tsconfig.json | 4 + 13 files changed, 844 insertions(+), 432 deletions(-) create mode 100644 src/redis/redis.module.ts create mode 100644 src/redis/redis.providers.ts create mode 100644 src/sales/sales/placesinterior.service.spec.ts diff --git a/package-lock.json b/package-lock.json index 074b46d..859be27 100644 --- a/package-lock.json +++ b/package-lock.json @@ -580,6 +580,11 @@ "minimist": "^1.2.0" } }, + "@ioredis/commands": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.2.0.tgz", + "integrity": "sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==" + }, "@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -1527,6 +1532,41 @@ "pako": "^1.0.10" } }, + "@redis/bloom": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-1.2.0.tgz", + "integrity": "sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==" + }, + "@redis/client": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@redis/client/-/client-1.6.0.tgz", + "integrity": "sha512-aR0uffYI700OEEH4gYnitAnv3vzVGXCFvYfdpu/CJKvk4pHfLPEy/JSZyrpQ+15WhXe1yJRXLtfQ84s4mEXnPg==", + "requires": { + "cluster-key-slot": "1.1.2", + "generic-pool": "3.9.0", + "yallist": "4.0.0" + } + }, + "@redis/graph": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@redis/graph/-/graph-1.1.1.tgz", + "integrity": "sha512-FEMTcTHZozZciLRl6GiiIB4zGm5z5F3F6a6FZCyrfxdKOhFlGkiAqlexWMBzCi4DcRoyiOsuLfW+cjlGWyExOw==" + }, + "@redis/json": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@redis/json/-/json-1.0.7.tgz", + "integrity": "sha512-6UyXfjVaTBTJtKNG4/9Z8PSpKE6XgSyEb8iwaqDcy+uKrd/DGYHTWkUdnQDyzm727V7p21WUMhsqz5oy65kPcQ==" + }, + "@redis/search": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@redis/search/-/search-1.2.0.tgz", + "integrity": "sha512-tYoDBbtqOVigEDMAcTGsRlMycIIjwMCgD8eR2t0NANeQmgK/lvxNAvYyb6bZDD4frHRhIHkJu2TBRvB0ERkOmw==" + }, + "@redis/time-series": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-1.1.0.tgz", + "integrity": "sha512-c1Q99M5ljsIuc4YdaCwfUEXsofakb9c8+Zse2qxTadu8TalLXuAESzLvFAvNVbkmSlvlzIQOLpBCmWI9wTOt+g==" + }, "@schematics/schematics": { "version": "0.1100.3", "resolved": "https://registry.npmjs.org/@schematics/schematics/-/schematics-0.1100.3.tgz", @@ -1613,6 +1653,11 @@ "@types/node": "*" } }, + "@types/cache-manager": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/@types/cache-manager/-/cache-manager-3.4.3.tgz", + "integrity": "sha512-71aBXoFYXZW4TnDHHH8gExw2lS28BZaWeKefgsiJI7QYZeJfUEbMKw6CQtzGjlYQcGIWwB76hcCrkVA3YHSvsw==" + }, "@types/connect": { "version": "3.4.34", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.34.tgz", @@ -1692,6 +1737,14 @@ "@types/node": "*" } }, + "@types/ioredis": { + "version": "4.28.10", + "resolved": "https://registry.npmjs.org/@types/ioredis/-/ioredis-4.28.10.tgz", + "integrity": "sha512-69LyhUgrXdgcNDv7ogs1qXZomnfOEnSmrmMFqKgt1XMJxmoOSG/u3wYy13yACIfKuMJ8IhKgHafDO3sx19zVQQ==", + "requires": { + "@types/node": "*" + } + }, "@types/istanbul-lib-coverage": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", @@ -1772,8 +1825,7 @@ "@types/node": { "version": "13.13.41", "resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.41.tgz", - "integrity": "sha512-qLT9IvHiXJfdrje9VmsLzun7cQ65obsBTmtU3EOnCSLFOoSHx1hpiRHoBnpdbyFqnzqdUUIv81JcEJQCB8un9g==", - "dev": true + "integrity": "sha512-qLT9IvHiXJfdrje9VmsLzun7cQ65obsBTmtU3EOnCSLFOoSHx1hpiRHoBnpdbyFqnzqdUUIv81JcEJQCB8un9g==" }, "@types/normalize-package-data": { "version": "2.4.0", @@ -1885,6 +1937,11 @@ } } }, + "@types/uuid": { + "version": "3.4.13", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-3.4.13.tgz", + "integrity": "sha512-pAeZeUbLE4Z9Vi9wsWV2bYPTweEHeJJy0G4pEjOA/FSvy1Ad5U5Km8iDV6TKre1mjBiVNfAdVHKruP8bAh4Q5A==" + }, "@types/webpack": { "version": "4.41.25", "resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-4.41.25.tgz", @@ -2493,6 +2550,43 @@ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" }, + "axios": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.0.tgz", + "integrity": "sha512-1uvKqKQta3KBxIz14F2v06AEHZ/dIoeKfbTRkK1E5oqjDnuEerLmYTgJB5AiQZHJcljpg1TuRzdjDR06qNk0DQ==", + "requires": { + "follow-redirects": "1.5.10", + "is-buffer": "^2.0.2" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "follow-redirects": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", + "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", + "requires": { + "debug": "=3.1.0" + } + }, + "is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==" + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + } + } + }, "babel-jest": { "version": "25.5.1", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-25.5.1.tgz", @@ -2852,13 +2946,28 @@ } }, "cache-manager": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/cache-manager/-/cache-manager-3.4.0.tgz", - "integrity": "sha512-+WtL5sKHGngtnzTHNFA6+gC0wjpAAUmwmprXOSeaCBOkohM8Nh7GvV8fC90NFrDh7m3i87AshGd39/yYbWNtWA==", + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/cache-manager/-/cache-manager-3.6.3.tgz", + "integrity": "sha512-dS4DnV6c6cQcVH5OxzIU1XZaACXwvVIiUPkFytnRmLOACuBGv3GQgRQ1RJGRRw4/9DF14ZK2RFlZu1TUgDniMg==", "requires": { - "async": "^3.2.0", - "lodash": "^4.17.20", + "async": "3.2.3", + "lodash.clonedeep": "^4.5.0", "lru-cache": "6.0.0" + }, + "dependencies": { + "async": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", + "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==" + } + } + }, + "cache-manager-redis-store": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/cache-manager-redis-store/-/cache-manager-redis-store-3.0.1.tgz", + "integrity": "sha512-o560kw+dFqusC9lQJhcm6L2F2fMKobJ5af+FoR2PdnMVdpQ3f3Bz6qzvObTGyvoazQJxjQNWgMQeChP4vRTuXQ==", + "requires": { + "redis": "^4.3.1" } }, "call-bind": { @@ -2985,6 +3094,26 @@ } } }, + "cli-color": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/cli-color/-/cli-color-1.4.0.tgz", + "integrity": "sha512-xu6RvQqqrWEo6MPR1eixqGPywhYBHRs653F9jfXB2Hx4jdM/3WxiNE1vppRmxtMIfl16SFYTpYlrnqH/HsK/2w==", + "requires": { + "ansi-regex": "^2.1.1", + "d": "1", + "es5-ext": "^0.10.46", + "es6-iterator": "^2.0.3", + "memoizee": "^0.4.14", + "timers-ext": "^0.1.5" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==" + } + } + }, "cli-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", @@ -3079,6 +3208,11 @@ "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", "dev": true }, + "cluster-key-slot": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz", + "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==" + }, "co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -3372,6 +3506,15 @@ } } }, + "d": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.2.tgz", + "integrity": "sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==", + "requires": { + "es5-ext": "^0.10.64", + "type": "^2.7.2" + } + }, "dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", @@ -3499,6 +3642,11 @@ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" }, + "denque": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz", + "integrity": "sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw==" + }, "depd": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", @@ -3684,6 +3832,47 @@ "is-symbol": "^1.0.2" } }, + "es5-ext": { + "version": "0.10.64", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz", + "integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==", + "requires": { + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "esniff": "^2.0.1", + "next-tick": "^1.1.0" + } + }, + "es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", + "requires": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "es6-symbol": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.4.tgz", + "integrity": "sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==", + "requires": { + "d": "^1.0.2", + "ext": "^1.7.0" + } + }, + "es6-weak-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", + "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", + "requires": { + "d": "1", + "es5-ext": "^0.10.46", + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.1" + } + }, "escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -4073,6 +4262,17 @@ "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", "dev": true }, + "esniff": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz", + "integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==", + "requires": { + "d": "^1.0.1", + "es5-ext": "^0.10.62", + "event-emitter": "^0.3.5", + "type": "^2.7.2" + } + }, "espree": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz", @@ -4148,6 +4348,15 @@ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" }, + "event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", + "requires": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, "events": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/events/-/events-3.2.0.tgz", @@ -4286,6 +4495,14 @@ } } }, + "ext": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", + "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", + "requires": { + "type": "^2.7.2" + } + }, "extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -4641,6 +4858,11 @@ "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", "dev": true }, + "generic-pool": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.9.0.tgz", + "integrity": "sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==" + }, "gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -5064,6 +5286,34 @@ "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", "dev": true }, + "ioredis": { + "version": "4.29.1", + "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-4.29.1.tgz", + "integrity": "sha512-iq4u3AC9h9/P/gBXH1cUR7Ln0exKexqMaYDwUaoZJzkvvgJs9W5+CLQFS0APyG8uyvJJjn6q6Vx7LwmZQu3h5A==", + "requires": { + "@ioredis/commands": "^1.0.2", + "cluster-key-slot": "^1.1.0", + "debug": "^4.3.1", + "denque": "^1.1.0", + "lodash.defaults": "^4.2.0", + "lodash.flatten": "^4.4.0", + "lodash.isarguments": "^3.1.0", + "p-map": "^2.1.0", + "redis-errors": "^1.2.0", + "redis-parser": "^3.0.0", + "standard-as-callback": "^2.1.0" + }, + "dependencies": { + "debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "requires": { + "ms": "^2.1.3" + } + } + } + }, "ip-regex": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", @@ -5255,6 +5505,11 @@ "isobject": "^3.0.1" } }, + "is-promise": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", + "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==" + }, "is-regex": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.2.tgz", @@ -6526,7 +6781,23 @@ "lodash": { "version": "4.17.20", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", - "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", + "dev": true + }, + "lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==" + }, + "lodash.defaults": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==" + }, + "lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==" }, "lodash.get": { "version": "4.4.2", @@ -6538,6 +6809,11 @@ "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=" }, + "lodash.isarguments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", + "integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==" + }, "lodash.isboolean": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", @@ -6622,6 +6898,14 @@ "yallist": "^4.0.0" } }, + "lru-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz", + "integrity": "sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==", + "requires": { + "es5-ext": "~0.10.2" + } + }, "macos-release": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/macos-release/-/macos-release-2.4.1.tgz", @@ -6713,6 +6997,21 @@ "fs-monkey": "1.0.1" } }, + "memoizee": { + "version": "0.4.17", + "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.17.tgz", + "integrity": "sha512-DGqD7Hjpi/1or4F/aYAspXKNm5Yili0QDAFAY4QYvpqpgiY6+1jOfqpmByzjxbWd/T9mChbCArXAbDAsTm5oXA==", + "requires": { + "d": "^1.0.2", + "es5-ext": "^0.10.64", + "es6-weak-map": "^2.0.3", + "event-emitter": "^0.3.5", + "is-promise": "^2.2.2", + "lru-queue": "^0.1.0", + "next-tick": "^1.1.0", + "timers-ext": "^0.1.7" + } + }, "memory-fs": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz", @@ -7052,6 +7351,148 @@ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "dev": true }, + "nestjs-redis": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/nestjs-redis/-/nestjs-redis-1.2.8.tgz", + "integrity": "sha512-h3lDq/F4xbA++1OY63Lh2LjJgdJ3RvCPFbM+oRbs5M4Ep/9zgWwtfaVlcx31al/wBXUeaJ4HTNv5IAQZLkdIBA==", + "requires": { + "@nestjs/common": "6.3.1", + "@nestjs/core": "^6.6.7", + "@types/ioredis": "^4.0.4", + "@types/uuid": "^3.4.4", + "ioredis": "^4.2.0", + "reflect-metadata": "^0.1.12", + "rxjs": "^6.2.2", + "uuid": "^3.3.2" + }, + "dependencies": { + "@nestjs/common": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-6.3.1.tgz", + "integrity": "sha512-uuI/CCe6MFISMX+fSpkRvvQ6CBlXW89+5wfiveQ22AzAxgqGLAyWvNVHUE8F+zev7QDbxbY9vfPtm8CE5kiJVQ==", + "requires": { + "axios": "0.19.0", + "cli-color": "1.4.0", + "uuid": "3.3.2" + }, + "dependencies": { + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" + } + } + }, + "@nestjs/core": { + "version": "6.11.11", + "resolved": "https://registry.npmjs.org/@nestjs/core/-/core-6.11.11.tgz", + "integrity": "sha512-ewUy2rjiRWi6SziI5gXZnlat7PfnVklL3tusnU1qqtUm74cPY1Zre+zDCJ27P/+B7sFJHbkFfpi0qQP2pQv9jQ==", + "requires": { + "@nuxtjs/opencollective": "0.2.2", + "fast-safe-stringify": "2.0.7", + "iterare": "1.2.0", + "object-hash": "2.0.3", + "path-to-regexp": "3.2.0", + "tslib": "1.11.1", + "uuid": "7.0.1" + }, + "dependencies": { + "uuid": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-7.0.1.tgz", + "integrity": "sha512-yqjRXZzSJm9Dbl84H2VDHpM3zMjzSJQ+hn6C4zqd5ilW+7P4ZmLEEqwho9LjP+tGuZlF4xrHQXT0h9QZUS/pWA==" + } + } + }, + "@nuxtjs/opencollective": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@nuxtjs/opencollective/-/opencollective-0.2.2.tgz", + "integrity": "sha512-69gFVDs7mJfNjv9Zs5DFVD+pvBW+k1TaHSOqUWqAyTTfLcKI/EMYQgvEvziRd+zAFtUOoye6MfWh0qvinGISPw==", + "requires": { + "chalk": "^2.4.1", + "consola": "^2.3.0", + "node-fetch": "^2.3.0" + } + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" + }, + "iterare": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/iterare/-/iterare-1.2.0.tgz", + "integrity": "sha512-RxMV9p/UzdK0Iplnd8mVgRvNdXlsTOiuDrqMRnDi3wIhbT+JP4xDquAX9ay13R3CH72NBzQ91KWe0+C168QAyQ==" + }, + "object-hash": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.0.3.tgz", + "integrity": "sha512-JPKn0GMu+Fa3zt3Bmr66JhokJU5BaNBIh4ZeTlaCBzrBsOeXzwcKKAK1tbLiPKgvwmPXsDvvLHoWh5Bm7ofIYg==" + }, + "rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "requires": { + "tslib": "^1.9.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + }, + "tslib": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.1.tgz", + "integrity": "sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA==" + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + } + } + }, + "next-tick": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==" + }, "nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", @@ -7435,6 +7876,11 @@ "p-limit": "^2.2.0" } }, + "p-map": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==" + }, "p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", @@ -8048,6 +8494,32 @@ "resolve": "^1.1.6" } }, + "redis": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/redis/-/redis-4.7.0.tgz", + "integrity": "sha512-zvmkHEAdGMn+hMRXuMBtu4Vo5P6rHQjLoHftu+lBqq8ZTA3RCVC/WzD790bkKKiNFp7d5/9PcSD19fJyyRvOdQ==", + "requires": { + "@redis/bloom": "1.2.0", + "@redis/client": "1.6.0", + "@redis/graph": "1.1.1", + "@redis/json": "1.0.7", + "@redis/search": "1.2.0", + "@redis/time-series": "1.1.0" + } + }, + "redis-errors": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", + "integrity": "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==" + }, + "redis-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz", + "integrity": "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==", + "requires": { + "redis-errors": "^1.0.0" + } + }, "reflect-metadata": { "version": "0.1.13", "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", @@ -8991,6 +9463,11 @@ } } }, + "standard-as-callback": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz", + "integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==" + }, "static-extend": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", @@ -9529,6 +10006,15 @@ "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", "dev": true }, + "timers-ext": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.8.tgz", + "integrity": "sha512-wFH7+SEAcKfJpfLPkrgMPvvwnEtj8W4IurvEyrKsDleXnKLCDw71w8jltvfLa8Rm4qQxxT4jmDBYbJG/z7qoww==", + "requires": { + "es5-ext": "^0.10.64", + "next-tick": "^1.1.0" + } + }, "timm": { "version": "1.7.1", "resolved": "https://registry.npmjs.org/timm/-/timm-1.7.1.tgz", @@ -9877,6 +10363,11 @@ "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" }, + "type": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.3.tgz", + "integrity": "sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==" + }, "type-check": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", diff --git a/package.json b/package.json index 8068068..0833e5a 100644 --- a/package.json +++ b/package.json @@ -29,14 +29,18 @@ "@nestjs/platform-express": "^7.0.0", "@nestjs/swagger": "^4.8.2", "@nestjs/typeorm": "^7.1.0", - "cache-manager": "^3.4.0", + "@types/cache-manager": "^3.4.3", + "cache-manager": "^3.6.3", + "cache-manager-redis-store": "^3.0.1", "compression": "^1.7.4", "crc": "^4.3.2", "fs": "0.0.1-security", "guid-typescript": "^1.0.9", + "ioredis": "^4.29.1", "md5": "^2.3.0", "md5-typescript": "^1.0.5", "mindee": "^3.7.3", + "nestjs-redis": "^1.2.8", "node-geocoder": "^4.2.0", "odata-v4-typeorm": "^0.1.1", "oracledb": "^4.2.0", diff --git a/src/app.module.ts b/src/app.module.ts index 458bfb9..7ebebcf 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -1,4 +1,5 @@ import { DashboardModule } from './sales/dashboard/dashboard.module'; +import { redisProvider } from './redis/redis.providers'; import { MindeeModule } from './payment/mindee.module'; import { GoogleModule } from './google/google.module'; import { CepModule } from './sales/cep/cep.module'; @@ -38,10 +39,13 @@ import { typeOrmConfig } from './configs/typeorm.config'; import { Connection } from 'typeorm'; import { DictionaryModule } from './backoffice/dictionary/dictionary.module'; import { ConfigModule } from '@nestjs/config/dist/config.module'; +import { RedisModule } from './redis/redis.module'; + @Module({ imports: [ DashboardModule, + RedisModule, MindeeModule, GoogleModule, CepModule, @@ -88,8 +92,11 @@ import { ConfigModule } from '@nestjs/config/dist/config.module'; ReportsController, AppController], providers: [ + redisProvider, ProductService, ReportService, AppService], + + exports: [redisProvider], }) export class AppModule implements NestModule { diff --git a/src/configs/typeorm.config.ts b/src/configs/typeorm.config.ts index 5a45e5d..3b30a6b 100644 --- a/src/configs/typeorm.config.ts +++ b/src/configs/typeorm.config.ts @@ -29,4 +29,5 @@ export const connectionOptions: ConnectionOptions = { synchronize: false, logging: false, entities: [__dirname + '/../**/*.entity.{js,ts}'], -} \ No newline at end of file +} + diff --git a/src/main.ts b/src/main.ts index 261f0bd..169cb70 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,7 +1,8 @@ import { NestFactory } from '@nestjs/core'; import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'; -import * as compression from 'compression'; +const compression = require('compression'); import { AppModule } from './app.module'; +import 'reflect-metadata'; import { CustomLoggerService } from './services/custom-logger.service'; async function bootstrap() { diff --git a/src/redis/redis.module.ts b/src/redis/redis.module.ts new file mode 100644 index 0000000..a174185 --- /dev/null +++ b/src/redis/redis.module.ts @@ -0,0 +1,8 @@ +import { Module } from '@nestjs/common'; +import { redisProvider } from './redis.providers'; + +@Module({ + providers: [redisProvider], + exports: [redisProvider], +}) +export class RedisModule {} diff --git a/src/redis/redis.providers.ts b/src/redis/redis.providers.ts new file mode 100644 index 0000000..11ba7a9 --- /dev/null +++ b/src/redis/redis.providers.ts @@ -0,0 +1,12 @@ +import { Provider } from '@nestjs/common'; +import Redis = require('ioredis'); + +export const redisProvider: Provider = { + provide: 'REDIS_CLIENT', + useFactory: () => { + return new Redis({ + host: 'localhost', + port: 6379, + }); + }, +}; diff --git a/src/sales/customer/customer.service.ts b/src/sales/customer/customer.service.ts index 60afd24..f855837 100644 --- a/src/sales/customer/customer.service.ts +++ b/src/sales/customer/customer.service.ts @@ -1,11 +1,11 @@ import { HttpStatus } from '@nestjs/common'; import { Injectable, HttpException } from '@nestjs/common'; -import { connectionOptions } from 'src/configs/typeorm.config'; -import { Customer } from 'src/domain/models/customer.model'; +import { connectionOptions } from '../../configs/typeorm.config'; +import { Customer } from '../../domain/models/customer.model'; import { Connection } from 'typeorm'; import { Pcclient } from '../../domain/entity/tables/pcclient.entity'; import { Estcategoriacliente } from '../../domain/entity/tables/estcategoriacliente.entity'; -import { Estsubcategoriacliente } from 'src/domain/entity/tables/estsubcategoriacliente.entity'; +import { Estsubcategoriacliente } from '../../domain/entity/tables/estsubcategoriacliente.entity'; @Injectable() export class CustomerService { diff --git a/src/sales/sales/placesinterior.service.spec.ts b/src/sales/sales/placesinterior.service.spec.ts new file mode 100644 index 0000000..4fe9b82 --- /dev/null +++ b/src/sales/sales/placesinterior.service.spec.ts @@ -0,0 +1,49 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { SalesController } from './sales.controller'; +import { SalesService } from './sales.service'; +import { HttpException, HttpStatus } from '@nestjs/common'; + + +describe('SalesController', () => { + let salesController: SalesController; + let salesService: SalesService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + controllers: [SalesController], + providers: [ + { + provide: SalesService, + useValue: { + getPlacesInterior: jest.fn(), + }, + }, + ], + }).compile(); + + salesController = module.get(SalesController); + salesService = module.get(SalesService); + }); + + describe('getPlacesInterior', () => { + it('deve retornar a lista de cidades do interior', async () => { + const mockData = [{ name: 'Cidade1' }, { name: 'Cidade2' }]; + jest.spyOn(salesService, 'getPlacesInterior').mockResolvedValue(mockData); + + const result = await salesController.getPlacesInterior(); + expect(result).toEqual(mockData); + }); + + it('deve lançar um HttpException em caso de erro', async () => { + jest + .spyOn(salesService, 'getPlacesInterior') + .mockRejectedValue(new Error('Erro ao buscar cidades')); + + await expect(salesController.getPlacesInterior()).rejects.toThrow( + new HttpException('Erro ao buscar cidades', HttpStatus.BAD_REQUEST), + ); + }); + + + }); +}); diff --git a/src/sales/sales/sales.controller.ts b/src/sales/sales/sales.controller.ts index df52ce3..0e01487 100644 --- a/src/sales/sales/sales.controller.ts +++ b/src/sales/sales/sales.controller.ts @@ -1,37 +1,48 @@ -import { Body, Controller, Get, HttpException, HttpStatus, Param, Post, Query, Req } from '@nestjs/common'; -import { FilterProduct } from 'src/domain/models/filter-product.model'; -import { Notify } from 'src/domain/models/notify.model'; -import { Rupture } from 'src/domain/models/rupture.model'; +import { Body, Controller, Get, HttpException, HttpStatus, Param, Post, Query, Req, Headers } from '@nestjs/common'; +import { FilterProduct } from '../../domain/models/filter-product.model'; +import { Notify } from '../../domain/models/notify.model'; +import { Rupture } from '../../domain/models/rupture.model'; import { SalesService } from './sales.service'; -import { ApiTags } from '@nestjs/swagger'; +import { ApiTags, ApiHeader, ApiOperation, ApiParam, ApiQuery, ApiResponse } from '@nestjs/swagger'; + +interface PaginationParams { + pageNumber: number; + sizeCount: number; + store: string; +} @ApiTags('Sales') @Controller('api/v1/sales') +@ApiHeader({ name: 'x-page', description: 'Page number for pagination', required: false }) +@ApiHeader({ name: 'x-size-count', description: 'Number of items per page', required: false }) +@ApiHeader({ name: 'x-store', description: 'Store identifier', required: false }) export class SalesController { - constructor(private salesService: SalesService) { } + constructor(private readonly salesService: SalesService) { } + + private extractPaginationParams(headers): PaginationParams { + return { + pageNumber: headers['x-page'] ? parseInt(headers['x-page'], 10) : 1, + sizeCount: headers['x-size-count'] ? parseInt(headers['x-size-count'], 10) : 500, + store: headers['x-store'] || '99' + }; + } @Get('products') - async get(@Req() request: any) { - let pageNumber = 1; - let sizeCount = 500; - let store = '99'; - console.log(request.headers); - console.log(request.query); + @ApiOperation({ summary: 'Obter produtos com filtro' }) + @ApiResponse({ status: 200, description: 'Retorna lista de produtos' }) + @ApiResponse({ status: 400, description: 'Erro ao obter produtos' }) + async getProducts(@Req() request: any) { try { - if (request.headers['x-page']) - pageNumber = request.headers['x-page']; - if (request.headers['x-size-count']) - sizeCount = request.headers['x-size-count']; - if (request.headers['x-store']) - store = request.headers['x-store']; + const { pageNumber, sizeCount, store } = this.extractPaginationParams(request.headers); return await this.salesService.GetProducts2(store, sizeCount, pageNumber, request.query); } catch (e) { throw new HttpException(e.message, HttpStatus.BAD_REQUEST); } - } @Get('departments') + @ApiOperation({ summary: 'Get all departments' }) + @ApiResponse({ status: 200, description: 'Returns department list' }) async getDepartments() { try { return await this.salesService.getDepartments(); @@ -41,6 +52,8 @@ export class SalesController { } @Get('category') + @ApiOperation({ summary: 'Get all categories' }) + @ApiResponse({ status: 200, description: 'Returns category list' }) async getCategory() { try { return await this.salesService.getCategory(); @@ -49,8 +62,9 @@ export class SalesController { } } - @Get('placesinterior') + @ApiOperation({ summary: 'Lista de cidades do interior' }) + @ApiResponse({ status: 200, description: 'Retorna lista de cidades do interior' }) async getPlacesInterior() { try { return await this.salesService.getPlacesInterior(); @@ -60,18 +74,12 @@ export class SalesController { } @Get('products/:search') - async searchProducts(@Param('search') search: string, @Req() request: any) { - console.log("pesquisando produtos..."); - let pageNumber = 1; - let sizeCount = 500; - let store = '99'; + @ApiOperation({ summary: 'Search products by term' }) + @ApiParam({ name: 'search', description: 'Search term' }) + @ApiResponse({ status: 200, description: 'Returns matching products' }) + async searchProducts(@Param('search') search: string, @Headers() headers) { try { - if (request.headers['x-page']) - pageNumber = request.headers['x-page']; - if (request.headers['x-size-count']) - sizeCount = request.headers['x-size-count']; - if (request.headers['x-store']) - store = request.headers['x-store']; + const { pageNumber, sizeCount, store } = this.extractPaginationParams(headers); return await this.salesService.searchProduct(store, search, sizeCount, pageNumber); } catch (e) { throw new HttpException(e.message, HttpStatus.BAD_REQUEST); @@ -79,18 +87,11 @@ export class SalesController { } @Get('product/category/:url') - async searchByDepartment(@Param('url') urlDepartment: string, @Req() request: any) { - console.log("pesquisando produtos..."); - let pageNumber = 1; - let sizeCount = 500; - let store = '99'; + @ApiOperation({ summary: 'Search products by department' }) + @ApiParam({ name: 'url', description: 'Department URL' }) + async searchByDepartment(@Param('url') urlDepartment: string, @Headers() headers) { try { - if (request.headers['x-page']) - pageNumber = request.headers['x-page']; - if (request.headers['x-size-count']) - sizeCount = request.headers['x-size-count']; - if (request.headers['x-store']) - store = request.headers['x-store']; + const { pageNumber, sizeCount, store } = this.extractPaginationParams(headers); return await this.salesService.searchByDepartment(store, sizeCount, pageNumber, urlDepartment); } catch (e) { throw new HttpException(e.message, HttpStatus.BAD_REQUEST); @@ -98,17 +99,16 @@ export class SalesController { } @Get('product/category/:urlDepartament/:urlSection') - async searchBySection(@Param('urlDepartament') urlDepartment: string, @Param('urlSection') urlSection: string, @Req() request: any) { - let pageNumber = 1; - let sizeCount = 500; - let store = '99'; + @ApiOperation({ summary: 'Search products by department and section' }) + @ApiParam({ name: 'urlDepartament', description: 'Department URL' }) + @ApiParam({ name: 'urlSection', description: 'Section URL' }) + async searchBySection( + @Param('urlDepartament') urlDepartment: string, + @Param('urlSection') urlSection: string, + @Headers() headers + ) { try { - if (request.headers['x-page']) - pageNumber = request.headers['x-page']; - if (request.headers['x-size-count']) - sizeCount = request.headers['x-size-count']; - if (request.headers['x-store']) - store = request.headers['x-store']; + const { pageNumber, sizeCount, store } = this.extractPaginationParams(headers); return await this.salesService.searchBySection(store, sizeCount, pageNumber, urlDepartment, urlSection); } catch (e) { throw new HttpException(e.message, HttpStatus.BAD_REQUEST); @@ -116,39 +116,36 @@ export class SalesController { } @Get('product/category/:urlDepartament/:urlSection/:urlCategory') - async searchByCategory(@Param('urlDepartament') urlDepartment: string, @Param('urlSection') urlSection: string, - @Param('urlCategory') urlCategory: string, @Req() request: any) { - let pageNumber = 1; - let sizeCount = 500; - let store = '99'; + @ApiOperation({ summary: 'Search products by department, section and category' }) + @ApiParam({ name: 'urlDepartament', description: 'Department URL' }) + @ApiParam({ name: 'urlSection', description: 'Section URL' }) + @ApiParam({ name: 'urlCategory', description: 'Category URL' }) + async searchByCategory( + @Param('urlDepartament') urlDepartment: string, + @Param('urlSection') urlSection: string, + @Param('urlCategory') urlCategory: string, + @Headers() headers + ) { try { - if (request.headers['x-page']) - pageNumber = request.headers['x-page']; - if (request.headers['x-size-count']) - sizeCount = request.headers['x-size-count']; - if (request.headers['x-store']) - store = request.headers['x-store']; - return await this.salesService.searchByCategory(store, sizeCount, pageNumber, urlDepartment, urlSection, urlCategory); + const { pageNumber, sizeCount, store } = this.extractPaginationParams(headers); + return await this.salesService.searchByCategory( + store, + sizeCount, + pageNumber, + urlDepartment, + urlSection, + urlCategory + ); } catch (e) { throw new HttpException(e.message, HttpStatus.BAD_REQUEST); } } - @Post('products') - async getProductsByFilter(@Req() request: any, @Body() filter: FilterProduct) { - let pageNumber = 1; - let sizeCount = 500; - console.log(filter); - let store = '99'; + @ApiOperation({ summary: 'Get products by filter criteria' }) + async getProductsByFilter(@Headers() headers, @Body() filter: FilterProduct) { try { - if (request.headers['x-page']) - pageNumber = request.headers['x-page']; - if (request.headers['x-size-count']) - sizeCount = request.headers['x-size-count']; - if (request.headers['x-store']) - store = request.headers['x-store']; - // return await this.salesService.GetProducts2(store, sizeCount, pageNumber, filter); + const { pageNumber, sizeCount, store } = this.extractPaginationParams(headers); return await this.salesService.searchProduct2(store, sizeCount, pageNumber, filter); } catch (e) { throw new HttpException(e.message, HttpStatus.BAD_REQUEST); @@ -156,11 +153,11 @@ export class SalesController { } @Get('product/:id') - async getProduct(@Req() request: any, @Param('id') id: number) { - let store = '99'; + @ApiOperation({ summary: 'Get product by ID' }) + @ApiParam({ name: 'id', description: 'Product ID' }) + async getProduct(@Headers() headers, @Param('id') id: number) { try { - if (request.headers['x-store']) - store = request.headers['x-store']; + const { store } = this.extractPaginationParams(headers); return await this.salesService.GetProduct(store, id); } catch (e) { throw new HttpException(e.message, HttpStatus.BAD_REQUEST); @@ -168,11 +165,11 @@ export class SalesController { } @Get('product/bytogether/:id') - async GetProductsBuyTogether(@Req() request: any, @Param('id') id: number) { - let store = '99'; + @ApiOperation({ summary: 'Get products frequently bought together' }) + @ApiParam({ name: 'id', description: 'Product ID' }) + async getProductsBuyTogether(@Headers() headers, @Param('id') id: number) { try { - if (request.headers['x-store']) - store = request.headers['x-store']; + const { store } = this.extractPaginationParams(headers); return await this.salesService.GetProductsBuyTogether(store, id); } catch (e) { throw new HttpException(e.message, HttpStatus.BAD_REQUEST); @@ -180,6 +177,9 @@ export class SalesController { } @Get('stock/:storeid/:id') + @ApiOperation({ summary: 'Get product stock information' }) + @ApiParam({ name: 'storeid', description: 'Store ID' }) + @ApiParam({ name: 'id', description: 'Product ID' }) async getStock(@Param('storeid') storeId: string, @Param('id') id: number) { try { return await this.salesService.GetStocks(storeId, id); @@ -189,23 +189,26 @@ export class SalesController { } @Get('installment/:id') - async getSaleIntallment(@Req() request: any, @Query() query, @Param('id') id: number) { - let store = '99'; - let quantity = 1; + @ApiOperation({ summary: 'Get installment options for a product' }) + @ApiParam({ name: 'id', description: 'Product ID' }) + @ApiQuery({ name: 'quantity', description: 'Product quantity', required: false }) + async getSaleInstallment( + @Headers() headers, + @Query('quantity') quantityParam: string, + @Param('id') id: number + ) { try { - if (request.headers['x-store']) - store = request.headers['x-store']; - if (query['quantity']) { - quantity = Number.parseFloat(query['quantity']); - } + const { store } = this.extractPaginationParams(headers); + const quantity = quantityParam ? parseFloat(quantityParam) : 1; return await this.salesService.GetSaleInstallment(store, id, quantity); } catch (e) { throw new HttpException(e.message, HttpStatus.BAD_REQUEST); } } - @Get('delivery/:cpf') + @ApiOperation({ summary: 'Get delivery options by CPF' }) + @ApiParam({ name: 'cpf', description: 'Customer CPF' }) async getDelivery(@Param('cpf') cpf: string) { try { return await this.salesService.GetDelivery(cpf); @@ -215,14 +218,26 @@ export class SalesController { } @Get('deliveryDays/:createDate/:invoiceStoreId/:placeId/:cartId') - async deliveryDays(@Param('createDate') createDate: string, - @Param('invoiceStoreId') invoiceStoreId: string, - @Param('placeId') placeId: string, - @Param('cartId') cartId: string) { + @ApiOperation({ summary: 'Get delivery days estimation' }) + @ApiParam({ name: 'createDate', description: 'Order creation date' }) + @ApiParam({ name: 'invoiceStoreId', description: 'Invoice store ID' }) + @ApiParam({ name: 'placeId', description: 'Place ID' }) + @ApiParam({ name: 'cartId', description: 'Cart ID' }) + async deliveryDays( + @Param('createDate') createDate: string, + @Param('invoiceStoreId') invoiceStoreId: string, + @Param('placeId') placeId: string, + @Param('cartId') cartId: string + ) { + try { return this.salesService.getDeliveryTime(createDate, invoiceStoreId, placeId, cartId); + } catch (e) { + throw new HttpException(e.message, HttpStatus.BAD_REQUEST); + } } @Post('notify') + @ApiOperation({ summary: 'Create product notification' }) async createNotification(@Body() data: Notify) { try { return await this.salesService.createNotification(data); @@ -232,6 +247,7 @@ export class SalesController { } @Post('rupture') + @ApiOperation({ summary: 'Create rupture notification' }) async createRupture(@Body() data: Rupture) { try { return await this.salesService.createRuptura(data); @@ -241,8 +257,8 @@ export class SalesController { } @Post('calculatedeliverytaxorder') - async calcDeliveryTaxOrder( - @Body() dataDeliveryOrder: any) { + @ApiOperation({ summary: 'Calculate delivery tax for an order' }) + async calcDeliveryTaxOrder(@Body() dataDeliveryOrder: any) { try { return await this.salesService.calculateDeliveryTaxOrder(dataDeliveryOrder); } catch (e) { @@ -251,6 +267,8 @@ export class SalesController { } @Get('analisevenda/:id') + @ApiOperation({ summary: 'Get sale analysis' }) + @ApiParam({ name: 'id', description: 'Sale ID' }) async analiseVendaRca(@Param('id') id: number) { try { return await this.salesService.GetAnaliseVenda(id); @@ -260,6 +278,8 @@ export class SalesController { } @Get('historicovenda/:id') + @ApiOperation({ summary: 'Get sales history' }) + @ApiParam({ name: 'id', description: 'Customer ID' }) async historicoVendaRca(@Param('id') id: number) { try { return await this.salesService.GetHistoricoVendas(id); @@ -269,15 +289,17 @@ export class SalesController { } @Get('calculatedeliverytax/:cartid/:ibgeCode') + @ApiOperation({ summary: 'Calculate delivery tax by cart and location' }) + @ApiParam({ name: 'cartid', description: 'Cart ID' }) + @ApiParam({ name: 'ibgeCode', description: 'IBGE location code' }) async calculatedeliverytax( - @Param('cartid') cartId: string, - @Param('ibgeCode') ibgeCode: string) { + @Param('cartid') cartId: string, + @Param('ibgeCode') ibgeCode: string + ) { try { return await this.salesService.calculateDeliveryTax(cartId, ibgeCode); } catch (e) { throw new HttpException(e.message, HttpStatus.BAD_REQUEST); } } - - -} +} \ No newline at end of file diff --git a/src/sales/sales/sales.module.ts b/src/sales/sales/sales.module.ts index d82b703..823b013 100644 --- a/src/sales/sales/sales.module.ts +++ b/src/sales/sales/sales.module.ts @@ -2,9 +2,10 @@ import { Module } from '@nestjs/common'; import { SalesController } from './sales.controller'; import { SalesService } from './sales.service'; import { CustomerService } from '../customer/customer.service'; +import { RedisModule } from '../../redis/redis.module'; @Module({ - imports: [], + imports: [RedisModule], controllers: [SalesController], providers: [SalesService, CustomerService], }) diff --git a/src/sales/sales/sales.service.ts b/src/sales/sales/sales.service.ts index 1b6c1a4..1563bec 100644 --- a/src/sales/sales/sales.service.ts +++ b/src/sales/sales/sales.service.ts @@ -1,287 +1,29 @@ -import { Injectable, HttpException, HttpStatus } from '@nestjs/common'; -import { Pcclient } from 'src/domain/entity/tables/pcclient.entity'; -import { SalesProduct } from 'src/domain/entity/views/esvprodutosvenda.entity'; +import { Injectable, HttpException, HttpStatus, Inject, CACHE_MANAGER } from '@nestjs/common'; +import { Pcclient } from '../../domain/entity/tables/pcclient.entity'; +import { SalesProduct } from '../../domain/entity/views/esvprodutosvenda.entity'; import { Connection, getConnection } from 'typeorm'; import { Esvsituacaopedido } from '../../domain/entity/views/esvsituacaopedido.entity'; import { Stock } from '../../domain/entity/views/esvestoquevenda.entity'; -import { FilterProduct } from 'src/domain/models/filter-product.model'; -import { Notify } from 'src/domain/models/notify.model'; -import { Estavisoestoque } from 'src/domain/entity/tables/estavisoestoque.entity'; +import { FilterProduct } from '../../domain/models/filter-product.model'; +import { Notify } from '../../domain/models/notify.model'; +import { Estavisoestoque } from '../../domain/entity/tables/estavisoestoque.entity'; import { Esvparcelamentovenda } from '../../domain/entity/views/esvparcelamentovenda.entity'; -import { Rupture } from 'src/domain/models/rupture.model'; -import { Estruptura } from 'src/domain/entity/tables/estruptura.entity'; +import { Rupture } from '../../domain/models/rupture.model'; +import { Estruptura } from '../../domain/entity/tables/estruptura.entity'; import { Esvsecao } from '../../domain/entity/views/esvsecao.entity'; -import { Esvdepartamento } from 'src/domain/entity/views/esvdepartamento.entity'; -import { Esvanalisevendarca } from 'src/domain/entity/views/esvanalisevendarca.entity'; -import { connectionOptions } from 'src/configs/typeorm.config'; +import { Esvdepartamento } from '../../domain/entity/views/esvdepartamento.entity'; +import { Esvanalisevendarca } from '../../domain/entity/views/esvanalisevendarca.entity'; +import { connectionOptions } from '../../configs/typeorm.config'; import { CustomerService } from '../customer/customer.service'; +import Redis = require('ioredis'); @Injectable() export class SalesService { - constructor( - private readonly customerService: CustomerService - ) { } - - - async GetProducts(store: string, pageSize: number, pageNumber: number, filter: FilterProduct = null): Promise { - const connection = getConnection(); - const queryRunner = connection.createQueryRunner(); - await queryRunner.connect(); - try { - if (pageSize == 0) - pageSize = 500; - if (pageNumber == 0) - pageNumber = 1; - const offSet = (pageNumber - 1) * pageSize; - - if (filter && filter.text != null) { - const description = filter.text.toUpperCase(); - console.log('consultando por codigo de fabrica'); - let products = await queryRunner.manager - .getRepository(SalesProduct) - .createQueryBuilder('esvlistaprodutos') - .select("\"esvlistaprodutos\".CODPROD", "idProduct") - .addSelect("\"esvlistaprodutos\".SEQ", "seq") - .addSelect("\"esvlistaprodutos\".DESCRICAO", "smallDescription") - .addSelect("\"esvlistaprodutos\".NOMEECOMMERCE", "title") - .addSelect("\"esvlistaprodutos\".CODFAB", "idProvider") - .addSelect("\"esvlistaprodutos\".CODAUXILIAR", "ean") - .addSelect("\"esvlistaprodutos\".TIPOPRODUTO", "productType") - .addSelect("\"esvlistaprodutos\".DADOSTECNICOS", "technicalData") - .addSelect("\"esvlistaprodutos\".INFORMACOESTECNICAS", "description") - .addSelect("\"esvlistaprodutos\".URLIMAGEM", "urlImage") - .addSelect("\"esvlistaprodutos\".NOMEMARCA", "brand") - .addSelect("\"esvlistaprodutos\".NOMEDEPARTAMENTO", "department") - .addSelect("\"esvlistaprodutos\".NOMESECAO", "section") - .addSelect("\"esvlistaprodutos\".NOMECATEGORIA", "category") - .addSelect("\"esvlistaprodutos\".NOMEFORNECEDOR", "supplier") - .addSelect("\"esvlistaprodutos\".CODIGOFILIAL", "store") - .addSelect("\"esvlistaprodutos\".CLASSEVENDA", "saleAbc") - .addSelect("\"esvlistaprodutos\".CLASSEESTOQUE", "stockAbc") - .addSelect("\"esvlistaprodutos\".FORALINHA", "outLine") - .addSelect("\"esvlistaprodutos\".PRECOVENDA", "listPrice") - .addSelect("\"esvlistaprodutos\".PRECOPROMOCIONAL", "salePrice") - .addSelect("\"esvlistaprodutos\".PRECOPROMOCIONAL", "salePromotion") - .addSelect("\"esvlistaprodutos\".PERCENTUALDESCONTO", "offPercent") - .addSelect("\"esvlistaprodutos\".QTESTOQUE_DISPONIVEL", "stock") - .addSelect("\"esvlistaprodutos\".QTCAIXAS", "boxStock") - .addSelect("\"esvlistaprodutos\".ESTOQUE_DISP_LOJA", "store_stock") - .addSelect("\"esvlistaprodutos\".ESTOQUE_DISP_CAIXA_LOJA", "store_boxStock") - .addSelect("\"esvlistaprodutos\".MULTIPLO", "mutiple") - .addSelect("\"esvlistaprodutos\".UNIDADE", "unity") - .addSelect("\"esvlistaprodutos\".URLDEPARTAMENTO", "urlDepartment") - .addSelect("\"esvlistaprodutos\".URLSECAO", "urlSection") - .addSelect("\"esvlistaprodutos\".BASETINTOMETRICO", "base") - .addSelect("\"esvlistaprodutos\".QUANTIDADE_ESTOQUE_GERAL", "full_stock") - .orderBy("\"esvlistaprodutos\".DESCRICAO") - .where("UPPER(\"esvlistaprodutos\".CODFAB) LIKE '%'||REPLACE(:description, '@', '%')||'%'", { description }) - .andWhere("(\"esvlistaprodutos\".codfilial = :codfilial OR :codfilial = '99')", { codfilial: store }) - .andWhere("(\"esvlistaprodutos\".produto_com_reducao_preco = :produtoComReducaoPreco OR :produtoComReducaoPreco = 'N')", - { produtoComReducaoPreco: (filter.markdown) ? 'S' : 'N' }) - .andWhere("(\"esvlistaprodutos\".produto_em_campanha = :campaign OR :campaign = 'N')", - { campaign: (filter.campaign) ? 'S' : 'N' }) - .andWhere("(\"esvlistaprodutos\".produto_oportunidade = :oportunity OR :oportunity = 'N')", - { oportunity: (filter.oportunity) ? 'S' : 'N' }) - .andWhere("(\"esvlistaprodutos\".produto_em_promocao = :produtoEmPromocao OR :produtoEmPromocao = 'N')", - { produtoEmPromocao: (filter.promotion) ? 'S' : 'N' }) - .orderBy("\"esvlistaprodutos\".CLASSEVENDA") - .limit(pageSize) - .offset(offSet) - .orderBy("\"esvlistaprodutos\".DESCRICAO", "ASC") - .getRawMany(); - if (products.length == 0) { - products = await queryRunner.manager - .getRepository(SalesProduct) - .createQueryBuilder('esvlistaprodutos') - .select("\"esvlistaprodutos\".CODPROD", "idProduct") - .addSelect("\"esvlistaprodutos\".SEQ", "seq") - .addSelect("\"esvlistaprodutos\".DESCRICAO", "smallDescription") - .addSelect("\"esvlistaprodutos\".NOMEECOMMERCE", "title") - .addSelect("\"esvlistaprodutos\".CODFAB", "idProvider") - .addSelect("\"esvlistaprodutos\".CODAUXILIAR", "ean") - .addSelect("\"esvlistaprodutos\".TIPOPRODUTO", "productType") - .addSelect("\"esvlistaprodutos\".DADOSTECNICOS", "technicalData") - .addSelect("\"esvlistaprodutos\".INFORMACOESTECNICAS", "description") - .addSelect("\"esvlistaprodutos\".URLIMAGEM", "urlImage") - .addSelect("\"esvlistaprodutos\".NOMEMARCA", "brand") - .addSelect("\"esvlistaprodutos\".NOMEDEPARTAMENTO", "department") - .addSelect("\"esvlistaprodutos\".NOMESECAO", "section") - .addSelect("\"esvlistaprodutos\".NOMECATEGORIA", "category") - .addSelect("\"esvlistaprodutos\".NOMEFORNECEDOR", "supplier") - .addSelect("\"esvlistaprodutos\".CODIGOFILIAL", "store") - .addSelect("\"esvlistaprodutos\".CLASSEVENDA", "saleAbc") - .addSelect("\"esvlistaprodutos\".CLASSEESTOQUE", "stockAbc") - .addSelect("\"esvlistaprodutos\".FORALINHA", "outLine") - .addSelect("\"esvlistaprodutos\".PRECOVENDA", "listPrice") - .addSelect("\"esvlistaprodutos\".PRECOPROMOCIONAL", "salePrice") - .addSelect("\"esvlistaprodutos\".PRECOPROMOCIONAL", "salePromotion") - .addSelect("\"esvlistaprodutos\".PERCENTUALDESCONTO", "offPercent") - .addSelect("\"esvlistaprodutos\".QTESTOQUE_DISPONIVEL", "stock") - .addSelect("\"esvlistaprodutos\".QTCAIXAS", "boxStock") - .addSelect("\"esvlistaprodutos\".ESTOQUE_DISP_LOJA", "store_stock") - .addSelect("\"esvlistaprodutos\".ESTOQUE_DISP_CAIXA_LOJA", "store_boxStock") - .addSelect("\"esvlistaprodutos\".MULTIPLO", "mutiple") - .addSelect("\"esvlistaprodutos\".UNIDADE", "unity") - .addSelect("\"esvlistaprodutos\".URLDEPARTAMENTO", "urlDepartment") - .addSelect("\"esvlistaprodutos\".URLSECAO", "urlSection") - .addSelect("\"esvlistaprodutos\".BASETINTOMETRICO", "base") - .addSelect("\"esvlistaprodutos\".QUANTIDADE_ESTOQUE_GERAL", "full_stock") - .orderBy("\"esvlistaprodutos\".DESCRICAO") - .where("UPPER(\"esvlistaprodutos\".descricao) LIKE '%'||REPLACE(:description, '@', '%')||'%'", { description }) - .andWhere("(\"esvlistaprodutos\".codfilial = :codfilial OR :codfilial = '99')", { codfilial: store }) - .andWhere("(\"esvlistaprodutos\".produto_com_reducao_preco = :produtoComReducaoPreco OR :produtoComReducaoPreco = 'N')", - { produtoComReducaoPreco: (filter.markdown) ? 'S' : 'N' }) - .andWhere("(\"esvlistaprodutos\".produto_em_campanha = :campaign OR :campaign = 'N')", - { campaign: (filter.campaign) ? 'S' : 'N' }) - .andWhere("(\"esvlistaprodutos\".produto_oportunidade = :oportunity OR :oportunity = 'N')", - { oportunity: (filter.oportunity) ? 'S' : 'N' }) - .andWhere("(\"esvlistaprodutos\".produto_em_promocao = :produtoEmPromocao OR :produtoEmPromocao = 'N')", - { produtoEmPromocao: (filter.promotion) ? 'S' : 'N' }) - .orderBy("\"esvlistaprodutos\".CLASSEVENDA") - .limit(pageSize) - .offset(offSet) - .orderBy("\"esvlistaprodutos\".DESCRICAO", "ASC") - .getRawMany(); - } - products = this.createListImages(products); - console.log(products.length + ' produtos'); - return products; - } - - if (filter && filter.brands && filter.brands.length > 0) { - const brands = filter.brands; - let xbrands = ''; - brands.forEach(b => { - if (xbrands.length > 0) { - xbrands += ', ' + '\'' + b + '\'' - } - else { - xbrands = '\'' + b + '\''; - } - }); - console.log("String: " + xbrands); - console.log("String: " + filter.urlCategory); - let products = await queryRunner.manager - .getRepository(SalesProduct) - .createQueryBuilder('esvlistaprodutos') - .select("\"esvlistaprodutos\".CODPROD", "idProduct") - .addSelect("\"esvlistaprodutos\".SEQ", "seq") - .addSelect("\"esvlistaprodutos\".DESCRICAO", "smallDescription") - .addSelect("\"esvlistaprodutos\".NOMEECOMMERCE", "title") - .addSelect("\"esvlistaprodutos\".CODFAB", "idProvider") - .addSelect("\"esvlistaprodutos\".CODAUXILIAR", "ean") - .addSelect("\"esvlistaprodutos\".TIPOPRODUTO", "productType") - .addSelect("\"esvlistaprodutos\".DADOSTECNICOS", "technicalData") - .addSelect("\"esvlistaprodutos\".INFORMACOESTECNICAS", "description") - .addSelect("\"esvlistaprodutos\".URLIMAGEM", "urlImage") - .addSelect("\"esvlistaprodutos\".NOMEMARCA", "brand") - .addSelect("\"esvlistaprodutos\".NOMEDEPARTAMENTO", "department") - .addSelect("\"esvlistaprodutos\".NOMESECAO", "section") - .addSelect("\"esvlistaprodutos\".NOMECATEGORIA", "category") - .addSelect("\"esvlistaprodutos\".NOMEFORNECEDOR", "supplier") - .addSelect("\"esvlistaprodutos\".CODIGOFILIAL", "store") - .addSelect("\"esvlistaprodutos\".CLASSEVENDA", "saleAbc") - .addSelect("\"esvlistaprodutos\".CLASSEESTOQUE", "stockAbc") - .addSelect("\"esvlistaprodutos\".FORALINHA", "outLine") - .addSelect("\"esvlistaprodutos\".PRECOVENDA", "listPrice") - .addSelect("\"esvlistaprodutos\".PRECOPROMOCIONAL", "salePrice") - .addSelect("\"esvlistaprodutos\".PRECOPROMOCIONAL", "salePromotion") - .addSelect("\"esvlistaprodutos\".PERCENTUALDESCONTO", "offPercent") - .addSelect("\"esvlistaprodutos\".QTESTOQUE_DISPONIVEL", "stock") - .addSelect("\"esvlistaprodutos\".QTCAIXAS", "boxStock") - .addSelect("\"esvlistaprodutos\".ESTOQUE_DISP_LOJA", "store_stock") - .addSelect("\"esvlistaprodutos\".ESTOQUE_DISP_CAIXA_LOJA", "store_boxStock") - .addSelect("\"esvlistaprodutos\".MULTIPLO", "mutiple") - .addSelect("\"esvlistaprodutos\".UNIDADE", "unity") - .addSelect("\"esvlistaprodutos\".URLDEPARTAMENTO", "urlDepartment") - .addSelect("\"esvlistaprodutos\".URLSECAO", "urlSection") - .addSelect("\"esvlistaprodutos\".BASETINTOMETRICO", "base") - .addSelect("\"esvlistaprodutos\".QUANTIDADE_ESTOQUE_GERAL", "full_stock") - .orderBy("\"esvlistaprodutos\".DESCRICAO") - .where("esvlistaprodutos.brand in (" + xbrands + ")") - .andWhere("\"esvlistaprodutos\".URLCATEGORIA LIKE :urlCategoria||'%'", { urlCategoria: filter.urlCategory }) - .andWhere("(\"esvlistaprodutos\".codfilial = :codfilial OR :codfilial = '99')", { codfilial: store }) - .andWhere("(\"esvlistaprodutos\".produto_com_reducao_preco = :produtoComReducaoPreco OR :produtoComReducaoPreco = 'N')", - { produtoComReducaoPreco: (filter.markdown) ? 'S' : 'N' }) - .andWhere("(\"esvlistaprodutos\".produto_em_campanha = :campaign OR :campaign = 'N')", - { campaign: (filter.campaign) ? 'S' : 'N' }) - .andWhere("(\"esvlistaprodutos\".produto_oportunidade = :oportunity OR :oportunity = 'N')", - { oportunity: (filter.oportunity) ? 'S' : 'N' }) - .andWhere("(\"esvlistaprodutos\".produto_em_promocao = :produtoEmPromocao OR :produtoEmPromocao = 'N')", - { produtoEmPromocao: (filter.promotion) ? 'S' : 'N' }) - .limit(pageSize) - .offset(offSet) - .orderBy("\"esvlistaprodutos\".DESCRICAO", "ASC") - .getRawMany(); - products = this.createListImages(products); - console.log(products.length + ' produtos'); - return products; - - } else { - if (filter && filter.markdown) - console.log('Produto em redução de preço - 1'); - let products = await queryRunner.manager - .getRepository(SalesProduct) - .createQueryBuilder("esvlistaprodutos") - .select("\"esvlistaprodutos\".CODPROD", "idProduct") - .addSelect("\"esvlistaprodutos\".SEQ", "seq") - .addSelect("\"esvlistaprodutos\".DESCRICAO", "smallDescription") - .addSelect("\"esvlistaprodutos\".NOMEECOMMERCE", "title") - .addSelect("\"esvlistaprodutos\".CODFAB", "idProvider") - .addSelect("\"esvlistaprodutos\".CODAUXILIAR", "ean") - .addSelect("\"esvlistaprodutos\".TIPOPRODUTO", "productType") - .addSelect("\"esvlistaprodutos\".DADOSTECNICOS", "technicalData") - .addSelect("\"esvlistaprodutos\".INFORMACOESTECNICAS", "description") - .addSelect("\"esvlistaprodutos\".URLIMAGEM", "urlImage") - .addSelect("\"esvlistaprodutos\".NOMEMARCA", "brand") - .addSelect("\"esvlistaprodutos\".NOMEDEPARTAMENTO", "department") - .addSelect("\"esvlistaprodutos\".NOMESECAO", "section") - .addSelect("\"esvlistaprodutos\".NOMECATEGORIA", "category") - .addSelect("\"esvlistaprodutos\".NOMEFORNECEDOR", "supplier") - .addSelect("\"esvlistaprodutos\".CODIGOFILIAL", "store") - .addSelect("\"esvlistaprodutos\".CLASSEVENDA", "saleAbc") - .addSelect("\"esvlistaprodutos\".CLASSEESTOQUE", "stockAbc") - .addSelect("\"esvlistaprodutos\".FORALINHA", "outLine") - .addSelect("\"esvlistaprodutos\".PRECOVENDA", "listPrice") - .addSelect("\"esvlistaprodutos\".PRECOPROMOCIONAL", "salePrice") - .addSelect("\"esvlistaprodutos\".PRECOPROMOCIONAL", "salePromotion") - .addSelect("\"esvlistaprodutos\".PERCENTUALDESCONTO", "offPercent") - .addSelect("\"esvlistaprodutos\".QTESTOQUE_DISPONIVEL", "stock") - .addSelect("\"esvlistaprodutos\".QTCAIXAS", "boxStock") - .addSelect("\"esvlistaprodutos\".ESTOQUE_DISP_LOJA", "store_stock") - .addSelect("\"esvlistaprodutos\".ESTOQUE_DISP_CAIXA_LOJA", "store_boxStock") - .addSelect("\"esvlistaprodutos\".MULTIPLO", "mutiple") - .addSelect("\"esvlistaprodutos\".UNIDADE", "unity") - .addSelect("\"esvlistaprodutos\".URLDEPARTAMENTO", "urlDepartment") - .addSelect("\"esvlistaprodutos\".URLSECAO", "urlSection") - .addSelect("\"esvlistaprodutos\".BASETINTOMETRICO", "base") - .addSelect("\"esvlistaprodutos\".QUANTIDADE_ESTOQUE_GERAL", "full_stock") - .where("(\"esvlistaprodutos\".codfilial = :codfilial OR :codfilial = '99')", { codfilial: store }) - .andWhere("(\"esvlistaprodutos\".produto_com_reducao_preco = :produtoComReducaoPreco OR :produtoComReducaoPreco = 'N')", - { produtoComReducaoPreco: (filter && filter.markdown) ? 'S' : 'N' }) - .andWhere("(\"esvlistaprodutos\".produto_em_campanha = :campaign OR :campaign = 'N')", - { campaign: (filter && filter.campaign) ? 'S' : 'N' }) - .andWhere("(\"esvlistaprodutos\".produto_oportunidade = :oportunity OR :oportunity = 'N')", - { oportunity: (filter && filter.oportunity) ? 'S' : 'N' }) - .andWhere("(\"esvlistaprodutos\".produto_em_promocao = :produtoEmPromocao OR :produtoEmPromocao = 'N')", - { produtoEmPromocao: (filter && filter.promotion) ? 'S' : 'N' }) - .orderBy("\"esvlistaprodutos\".DESCRICAO") - .limit(pageSize) - .offset(offSet) - .getRawMany(); - products = this.createListImages(products); - console.log(products.length + ' produtos'); - return products; - - } - } catch (error) { - console.log(error); - throw error; - } finally { - await queryRunner.release(); - } - } + constructor( + @Inject('REDIS_CLIENT') private readonly redisClient: Redis.Redis, + private readonly customerService: CustomerService + ) {} async GetProducts2(store: string, pageSize: number, pageNumber: number, filter: FilterProduct = null,) { @@ -1317,29 +1059,78 @@ export class SalesService { } - async getDepartments() { - const connectionDb = new Connection(connectionOptions); - await connectionDb.connect(); - const queryRunner = connectionDb.createQueryRunner(); - await queryRunner.connect(); + async getDepartments(): Promise { + const cacheKey = 'departments'; + const lockKey = 'departments_lock'; + const lockTimeout = 30; // lock expira em 30 segundos + try { - const departments = await queryRunner.manager - .getRepository(Esvdepartamento) - .createQueryBuilder('Esvdepartamento') - .innerJoinAndSelect('Esvdepartamento.secoes', 'secoes') - .innerJoinAndSelect('secoes.categorias', 'categorias') - .where('\"Esvdepartamento\".tituloecommerce is not null') - .orderBy('\"Esvdepartamento\".tituloecommerce, \"secoes\".tituloecommerce, \"categorias\".tituloecommerce') - .getMany(); - return departments; + // Tenta recuperar os departamentos do cache + const cachedDepartments = await this.redisClient.get(cacheKey); + if (cachedDepartments) { + console.log('Buscando departamentos no Redis'); + return JSON.parse(cachedDepartments); + } } catch (err) { - throw err; - } finally { + console.error('Erro ao acessar o Redis (cache):', err); + // Se o Redis falhar, a execução continua para consultar o banco + } + const lockValue = Date.now() + lockTimeout * 1000 + 1; + const acquiredLock = await this.redisClient.set(lockKey, lockValue, 'NX', 'EX', lockTimeout); + + if (acquiredLock === 'OK') { + const connectionDb = new Connection(connectionOptions); + await connectionDb.connect(); + const queryRunner = connectionDb.createQueryRunner(); + await queryRunner.connect(); + + try { + const departments = await queryRunner.manager + .getRepository(Esvdepartamento) + .createQueryBuilder('Esvdepartamento') + .innerJoinAndSelect('Esvdepartamento.secoes', 'secoes') + .innerJoinAndSelect('secoes.categorias', 'categorias') + .where('"Esvdepartamento".tituloecommerce is not null') + .orderBy('"Esvdepartamento".tituloecommerce, "secoes".tituloecommerce, "categorias".tituloecommerce') + .getMany(); + + try { + await this.redisClient.set(cacheKey, JSON.stringify(departments), 'EX', 3600); + } catch (cacheErr) { + console.error('Erro ao armazenar dados no Redis:', cacheErr); + } + + return departments; + } catch (dbErr) { + console.error('Erro na consulta ao banco de dados:', dbErr); + throw dbErr; + } finally { await queryRunner.release(); await connectionDb.close(); + + // Libera o lock somente se ainda for o proprietário + try { + const currentLockValue = await this.redisClient.get(lockKey); + if (currentLockValue === lockValue.toString()) { + await this.redisClient.del(lockKey); + } + } catch (lockErr) { + console.error('Erro ao liberar o lock do Redis:', lockErr); + } + } + } else { + console.log('Lock não adquirido, aguardando a liberação...'); + await this.sleep(1000); // aguarda 1 segundo + return this.getDepartments(); } + } + private sleep(ms: number): Promise { + return new Promise(resolve => setTimeout(resolve, ms)); + } + + + - } async getCategory() { const connectionDb = new Connection(connectionOptions); @@ -1365,6 +1156,18 @@ export class SalesService { async searchProduct2(store: string, pageSize: number, pageNumber: number, filter: FilterProduct) { console.log('searchProduct2'); + + // Cria uma chave única para o cache utilizando os parâmetros da função + const cacheKey = `searchProduct2:${store}:${pageSize}:${pageNumber}:${JSON.stringify(filter)}`; + + // Tenta recuperar os produtos do cache + const cachedProducts = await this.redisClient.get(cacheKey); + if (cachedProducts) { + console.log('Retornando produtos do cache'); + return JSON.parse(cachedProducts); + } + + // Monta a consulta SQL const sql = 'SELECT esvlistaprodutos.CODPROD "idProduct" ' + ` ,esvlistaprodutos.SEQ "seq" ` + ' ,esvlistaprodutos.DESCRICAO "smallDescription" ' + @@ -1406,6 +1209,8 @@ export class SalesService { ' ,esvlistaprodutos.QUANTIDADE_ESTOQUE_GERAL "full_stock" ' + ' FROM esvlistaprodutos ' + ' WHERE 1 = 1'; + + // Concatena as condições WHERE baseadas nos filtros let where = ""; if (filter.text != null) { where += ` AND ( ESF_REMOVE_ACENTUACAO(UPPER(esvlistaprodutos.descricao)) LIKE ` + @@ -1425,7 +1230,7 @@ export class SalesService { where += ` AND (esvlistaprodutos.produto_em_campanha = '${(filter.offers ? 'D' : 'N')}' OR '${(filter.offers ? 'S' : 'N')}' = 'N') `; where += ` AND (esvlistaprodutos.produto_em_campanha = '${(filter.oportunity ? 'O' : 'N')}' OR '${(filter.oportunity ? 'O' : 'N')}' = 'N') `; where += ` AND (esvlistaprodutos.produto_em_promocao = '${(filter.promotion ? 'S' : 'N')}' OR '${(filter.promotion ? 'S' : 'N')}' = 'N') `; - + if (filter.onlyWithStock) { if (filter.storeStock == '' || filter.storeStock == null) { where += ` AND EXISTS( SELECT P.CODPROD FROM ESVLISTAPRODUTOS P ` + @@ -1437,43 +1242,45 @@ export class SalesService { ` AND P.ESTOQUE_DISP_LOJA > 0 ) `; } } - + if (filter.percentOffMin > 0) { - where += ` AND esvlistaprodutos.PERCENTUALDESCONTO >= ${filter.percentOffMin}` + where += ` AND esvlistaprodutos.PERCENTUALDESCONTO >= ${filter.percentOffMin}`; } - + if (filter.percentOffMax > 0) { - where += ` AND esvlistaprodutos.PERCENTUALDESCONTO <= ${filter.percentOffMax}` + where += ` AND esvlistaprodutos.PERCENTUALDESCONTO <= ${filter.percentOffMax}`; } - + let xbrands = ''; if (filter && filter.brands && filter.brands.length > 0) { const brands = filter.brands; brands.forEach(b => { if (xbrands.length > 0) { - xbrands += ', ' + '\'' + b + '\'' - } - else { + xbrands += ', ' + '\'' + b + '\''; + } else { xbrands = '\'' + b + '\''; } }); where += ` AND esvlistaprodutos.nomemarca in ( ${xbrands} )`; } - - + const orderBy = `ORDER BY esvlistaprodutos.${(filter.orderBy == null) ? 'DESCRICAO' : filter.orderBy}`; - + const skipReg = ((pageNumber - 1) * pageSize); const pagination = ` OFFSET ${skipReg} ROWS FETCH NEXT ${pageSize} ROWS ONLY`; - + const connectionDb = new Connection(connectionOptions); await connectionDb.connect(); const queryRunner = connectionDb.createQueryRunner(); await queryRunner.connect(); + try { let products = await queryRunner.manager.query(sql + where + orderBy + pagination) as SalesProduct[]; products = this.createListImages(products); console.log("Total de produtos: " + products.length); + + await this.redisClient.set(cacheKey, JSON.stringify(products), 'EX', 3600); + return products; } catch (err) { console.log(err); @@ -1482,8 +1289,8 @@ export class SalesService { await queryRunner.release(); await connectionDb.close(); } - } + async calculateDeliveryTax(cartId: string, ibgeCode: string) { @@ -1596,17 +1403,23 @@ export class SalesService { } + async getPlacesInterior() { const connectionDb = new Connection(connectionOptions); await connectionDb.connect(); const queryRunner = connectionDb.createQueryRunner(); await queryRunner.connect(); + try { - const sql = `SELECT DISTINCT ESTPREVENTREGAPRACA.CODPRACA, PCPRACA.PRACA - FROM ESTPREVENTREGAPRACA, PCPRACA - WHERE ESTPREVENTREGAPRACA.CODPRACA = PCPRACA.CODPRACA `; - - const places = await queryRunner.query(sql); + const sql = ` + SELECT DISTINCT ESTPREVENTREGAPRACA.CODPRACA, PCPRACA.PRACA + FROM ESTPREVENTREGAPRACA, PCPRACA + WHERE ESTPREVENTREGAPRACA.CODPRACA = PCPRACA.CODPRACA + `; + + const places = await queryRunner.query(sql); + + return places; } catch (err) { throw err; @@ -1614,9 +1427,8 @@ export class SalesService { await queryRunner.release(); await connectionDb.close(); } - - } + async getDeliveryTime(saleDate: string, invoiceStoreId: string, placeId: string, cartId: string) { const connection = new Connection(connectionOptions); diff --git a/tsconfig.json b/tsconfig.json index 69f185f..47bd92a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,7 @@ { "compilerOptions": { "module": "commonjs", + "esModuleInterop": true, "declaration": true, "removeComments": true, "emitDecoratorMetadata": true, @@ -9,6 +10,9 @@ "sourceMap": true, "outDir": "./dist", "baseUrl": "./", + "paths": { + "src/*": ["./src/*"] + }, "incremental": true }, "exclude": ["node_modules", "dist"] From b43af08d04c2a3994b0f1edb1557aa765cadf217 Mon Sep 17 00:00:00 2001 From: JurTI-BR Date: Fri, 14 Mar 2025 09:26:28 -0300 Subject: [PATCH 2/5] Cache departamento --- .../address-customer.service.ts | 21 +- src/sales/customer/customer.service.ts | 23 -- src/sales/order/order.module.ts | 3 +- src/sales/order/order.service.ts | 205 ++++++++++++------ src/sales/sales/sales.service.ts | 107 ++++++--- 5 files changed, 223 insertions(+), 136 deletions(-) diff --git a/src/sales/address-customer/address-customer.service.ts b/src/sales/address-customer/address-customer.service.ts index 745e49f..2a42580 100644 --- a/src/sales/address-customer/address-customer.service.ts +++ b/src/sales/address-customer/address-customer.service.ts @@ -83,26 +83,7 @@ export class AddressCustomerService { const address = await queryRunner.query( sql, [idCustomer, idAddress] ) ; - // .getRepository(Pcclientendent) - // .createQueryBuilder('pcclientendent') - // .select('\"pcclientendent\".codcli', 'customerId') - // .addSelect('\"pcclientendent\".codendentcli', 'idAddress') - // .addSelect('\"pcclientendent\".bairroent', 'neighbourhood') - // .addSelect('\"pcclientendent\".municent', 'city') - // .addSelect('\"pcclientendent\".estent', 'state') - // .addSelect('\"pcclientendent\".cepent', 'zipCode') - // .addSelect('\"pcclientendent\".enderent', 'street') - // .addSelect('\"pcclientendent\".complementoent', 'complement') - // .addSelect('\"pcclientendent\".numeroent', 'numberAddress') - // .addSelect('\"pcclientendent\".codcidade', 'cityCode') - // .addSelect('\"pcclientendent\".pontorefer', 'referencePoint') - // .addSelect('\"pcclientendent\".observacao', 'note') - // .addSelect('\"pcclientendent\".telent', 'phone') - // .addSelect('\"pcclientendent\".telent', 'cellPhone') - // .addSelect('\"pcclientendent\".codpracaent', 'placeId') - // .where("\"pcclientendent\".codcli = :idCustomer", { idCustomer }) - // .andWhere("\"pcclientendent\".codendentcli = :idAddress", { idAddress }) - // .getOne(); + return address[0]; } catch (error) { console.log(error); diff --git a/src/sales/customer/customer.service.ts b/src/sales/customer/customer.service.ts index f855837..1515fa4 100644 --- a/src/sales/customer/customer.service.ts +++ b/src/sales/customer/customer.service.ts @@ -152,29 +152,6 @@ export class CustomerService { ' WHERE pcclient.codcidade = pccidade.codcidade (+)'; const where = ` AND pcclient.codcli = ${idCustomer}`; const customer = await queryRunner.query(sql + where); - // const customer = await queryRunner.manager - // .getRepository(Pcclient) - // .createQueryBuilder('pcclient') - // .select("\"pcclient\".codcli as \"customerId\"") - // .addSelect("\"pcclient\".cliente as \"name\"") - // .addSelect("\"pcclient\".emailnfe as \"email\"") - // .addSelect("\"pcclient\".cgcent as \"cpfCnpj\"") - // .addSelect("\"pcclient\".ieent as \"numberState\"") - // .addSelect("\"pcclient\".enderent as \"address\"") - // .addSelect("\"pcclient\".numeroent as \"addressNumber\"") - // .addSelect("\"pcclient\".bairroent as \"neighborhood\"") - // .addSelect("\"pcclient\".complementoent as \"complement\"") - // .addSelect("\"pcclient\".municent as \"city\"") - // .addSelect("\"pcclient\".estent as \"state\"") - // .addSelect("\"pcclient\".cepent as \"zipCode\"") - // .addSelect("\"pcclient\".telent as \"phone\"") - // .addSelect("\"pcclient\".telcelent as \"cellPhone\"") - // .addSelect("\"pcclient\".codcategoria as \"categoryId\"") - // .addSelect("\"pcclient\".codsubcategoria as \"subCategoryId\"") - // .addSelect("\"pcclient\".codpraca as \"placeId\"") - // .where("\"pcclient\".codcli = :codcli", { codcli: idCustomer }) - // .andWhere("\"pcclient\".CODCLI NOT IN (2)") - // .getOne(); return customer[0]; } catch (error) { console.log(error); diff --git a/src/sales/order/order.module.ts b/src/sales/order/order.module.ts index 10fc8e9..389d4fc 100644 --- a/src/sales/order/order.module.ts +++ b/src/sales/order/order.module.ts @@ -10,9 +10,10 @@ import { CustomerService } from '../customer/customer.service'; import { AddressCustomerService } from '../address-customer/address-customer.service'; import { ShoppingService } from '../shopping/shopping.service'; import { UserService } from 'src/Auth/services/user.service'; +import { RedisModule } from '../../redis/redis.module'; @Module({ - imports: [HttpModule], + imports: [HttpModule,RedisModule], controllers: [ OrderController, OrderController,], diff --git a/src/sales/order/order.service.ts b/src/sales/order/order.service.ts index f4f43a7..a1b342f 100644 --- a/src/sales/order/order.service.ts +++ b/src/sales/order/order.service.ts @@ -1,5 +1,5 @@ /* eslint-disable @typescript-eslint/camelcase */ -import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; +import { HttpException, HttpStatus, Injectable,Inject } from '@nestjs/common'; import { ShoppingItens } from 'src/domain/entity/tables/estprevendai.entity'; import { Sale } from 'src/domain/entity/tables/estvenda.entity'; import { Pcpedctemp } from 'src/domain/entity/tables/pcpedctemp.entity'; @@ -13,11 +13,14 @@ import { ListsService } from 'src/backoffice/lists/lists.service'; import { CustomerService } from '../customer/customer.service'; import { AddressCustomerService } from '../address-customer/address-customer.service'; import { ShoppingService } from '../shopping/shopping.service'; +import Redis = require('ioredis'); + @Injectable() export class OrderService { constructor( + @Inject('REDIS_CLIENT') private readonly redisClient: Redis.Redis, private readonly listsService: ListsService, private readonly customerService: CustomerService, private readonly addressCustomerService: AddressCustomerService, @@ -669,7 +672,6 @@ export class OrderService { numeroSeq = numeroSeq + 1; } - // execute some operations on this transaction: await queryRunner.manager .createQueryBuilder() .insert() @@ -687,7 +689,7 @@ export class OrderService { await queryRunner.release(); await connection.close(); } - //const idOrder = await this.getIdOrder(cart.idSeller); + } @@ -742,15 +744,10 @@ export class OrderService { let sql = 'SELECT NVL(PROXNUMPEDWEB,0) as "proxnumpedweb" FROM PCUSUARI ' + ' WHERE PCUSUARI.CODUSUR = :1 FOR UPDATE'; const seller = await queryRunner.query(sql, [idSeller]); - /* const seller = await queryRunner.manager - .getRepository(Pcusuari) - .createQueryBuilder('pcusuari') - .where("\"pcusuari\".codusur = :idseller", { idseller: idSeller }) - .getOne(); */ + const idOrder = seller[0].proxnumpedweb; console.log(idOrder); - // lets now open a new transaction: await queryRunner.startTransaction(); try { @@ -759,27 +756,18 @@ export class OrderService { ' WHERE PCUSUARI.CODUSUR = :1'; await queryRunner.query(sql, [idSeller]); - // await queryRunner.manager - // .createQueryBuilder() - // .update(Pcusuari) - // .set({ proxnumpedweb: idOrder + 1 }) - // .where("\"PCUSUARI\".codusur = :idseller", { idseller: idSeller }) - // .execute(); - - // commit transaction now: + await queryRunner.commitTransaction(); return idOrder; } catch (err) { - // since we have errors let's rollback changes we made await queryRunner.rollbackTransaction(); console.log(err); return -1; } finally { - // you need to release query runner which is manually created: await queryRunner.release(); await connection.close(); } @@ -807,77 +795,160 @@ export class OrderService { } } - async getOrders(store: string, initialDate: Date, finalDate: Date, - document: string, name: string, sellerId: number, idOrder: string) { - const connection = new Connection(connectionOptions); - await connection.connect(); - const queryRunner = connection.createQueryRunner(); - await queryRunner.connect(); - let sqlWhere = ''; - let sql = ''; + async getOrders( + store: string, + initialDate: any, + finalDate: any, + document: string, + name: string, + sellerId: number, + idOrder: string + ): Promise { + const initialDateObj = initialDate instanceof Date ? initialDate : new Date(initialDate); + const finalDateObj = finalDate instanceof Date ? finalDate : new Date(finalDate); + + const cacheKey = + 'getOrders:' + + store + + '_' + + initialDateObj.toISOString() + + '_' + + finalDateObj.toISOString() + + '_' + + document + + '_' + + name + + '_' + + sellerId + + '_' + + idOrder; + + const lockKey = 'lock:' + cacheKey; + const lockTimeout = 30; // lock expira em 30 segundos + try { + const cachedResult = await this.redisClient.get(cacheKey); + if (cachedResult) { + console.log('Retornando resultado do cache (getOrders)'); + return JSON.parse(cachedResult); + } + } catch (err) { + console.error('Erro ao acessar o Redis no getOrders:', err?.message || err); + } + + const lockValue = Date.now() + lockTimeout * 1000 + 1; + let acquiredLock: string | null = null; + try { + acquiredLock = await this.redisClient.set(lockKey, lockValue, 'NX', 'EX', lockTimeout); + } catch (err) { + console.error('Erro ao adquirir lock no Redis (getOrders):', err?.message || err); + } + + if (acquiredLock === 'OK') { - sql = ` SELECT TO_CHAR(PCPEDC.DATA, \'DD/MM/YYYY\') as "createDate" ` + - ` ,PCPEDC.NUMPED as "orderId" ` + - ` ,PCPEDC.CODFILIAL as "store" ` + - ` ,CASE WHEN PCPEDC.POSICAO = 'B' THEN 'BLOQUEADO' ` + - ` WHEN PCPEDC.POSICAO = 'P' THEN 'PENDENTE' ` + - ` WHEN PCPEDC.POSICAO = 'L' THEN 'LIBERADO' ` + - ` WHEN PCPEDC.POSICAO = 'M' THEN 'MONTADO' ` + - ` WHEN PCPEDC.POSICAO = 'F' THEN 'FATURADO' END as "status" ` + - ` ,PCPEDC.CODCLI as "customerId" ` + - ` ,PCPEDC.CODUSUR as "sellerId" ` + - ` ,PCCLIENT.CLIENTE as "customerName" ` + - ` ,PCPEDC.VLATEND as "orderValue" ` + - ` ,PCPEDC.NUMITENS as "itens" ` + - ` ,CASE WHEN ( SELECT COUNT(1) FROM ESTPIX WHERE ESTPIX.NUMPED = PCPEDC.NUMPED ) > 0 THEN 'S' ELSE 'N' END as "pixCreate" ` + - ` FROM PCPEDC, PCCLIENT ` + - ` WHERE PCPEDC.CODCLI = PCCLIENT.CODCLI ` + - ` AND PCPEDC.CONDVENDA IN (1,7) ` + - ` AND PCPEDC.DTCANCEL IS NULL AND PCPEDC.POSICAO NOT IN ('C') `; - ` AND PCPEDC.ROTINALANC = 'VENDAWEB' `; - if (store != null && store != '') { - sqlWhere += ` AND PCPEDC.CODFILIAL = '${store}' `; + const connection = new Connection(connectionOptions); + await connection.connect(); + const queryRunner = connection.createQueryRunner(); + await queryRunner.connect(); + let sqlWhere = ''; + let sql = ''; + + try { + sql = ` SELECT TO_CHAR(PCPEDC.DATA, 'DD/MM/YYYY') as "createDate", + PCPEDC.NUMPED as "orderId", + PCPEDC.CODFILIAL as "store", + CASE + WHEN PCPEDC.POSICAO = 'B' THEN 'BLOQUEADO' + WHEN PCPEDC.POSICAO = 'P' THEN 'PENDENTE' + WHEN PCPEDC.POSICAO = 'L' THEN 'LIBERADO' + WHEN PCPEDC.POSICAO = 'M' THEN 'MONTADO' + WHEN PCPEDC.POSICAO = 'F' THEN 'FATURADO' + END as "status", + PCPEDC.CODCLI as "customerId", + PCPEDC.CODUSUR as "sellerId", + PCCLIENT.CLIENTE as "customerName", + PCPEDC.VLATEND as "orderValue", + PCPEDC.NUMITENS as "itens", + CASE WHEN ( SELECT COUNT(1) FROM ESTPIX WHERE ESTPIX.NUMPED = PCPEDC.NUMPED ) > 0 THEN 'S' ELSE 'N' END as "pixCreate" + FROM PCPEDC, PCCLIENT + WHERE PCPEDC.CODCLI = PCCLIENT.CODCLI + AND PCPEDC.CONDVENDA IN (1,7) + AND PCPEDC.DTCANCEL IS NULL + AND PCPEDC.POSICAO NOT IN ('C') + AND PCPEDC.ROTINALANC = 'VENDAWEB' `; + + if (store && store !== '') { + sqlWhere += ` AND PCPEDC.CODFILIAL = '${store}' `; } - if (document != null && document != '') { - sqlWhere += ` AND REGEXP_REPLACE(PCCLIENT.CGCENT, '[^0-9]', '') = REGEXP_REPLACE('${document}', '[^0-9]', '')`; + if (document && document !== '') { + sqlWhere += ` AND REGEXP_REPLACE(PCCLIENT.CGCENT, '[^0-9]', '') = REGEXP_REPLACE('${document}', '[^0-9]', '') `; } - if (name != null && name != '') { - sqlWhere += ` AND PCCLIENT.CLIENTE LIKE '${name.replace('@', '%')}'||'%'`; + if (name && name !== '') { + sqlWhere += ` AND PCCLIENT.CLIENTE LIKE '${name.replace('@', '%')}'||'%' `; } if (sellerId > 0) { - sqlWhere += ` AND PCPEDC.CODUSUR = ${sellerId} `; + sqlWhere += ` AND PCPEDC.CODUSUR = ${sellerId} `; } - if (idOrder.trim() != null && idOrder.trim() != '') { - sqlWhere += ` AND PCPEDC.NUMPED = ${idOrder} `; + if (idOrder && idOrder.trim() !== '') { + sqlWhere += ` AND PCPEDC.NUMPED = ${idOrder} `; } - - //tratamento de data// - const startDate = new Date(initialDate); + + // Formatação das datas para o SQL + const startDate = initialDateObj; let day = startDate.getDate(); let month = ("00" + (startDate.getMonth() + 1)).slice(-2); let year = startDate.getFullYear(); const startFormat = day + "/" + month + "/" + year; - const endDate = new Date(finalDate); + + const endDate = finalDateObj; day = endDate.getDate(); month = ("00" + (endDate.getMonth() + 1)).slice(-2); year = endDate.getFullYear(); const endFormat = day + "/" + month + "/" + year; - - sqlWhere += ` AND PCPEDC.DATA BETWEEN TO_DATE('${startFormat}', 'DD/MM/YYYY') AND TO_DATE('${endFormat}', 'DD/MM/YYYY') `; - + + sqlWhere += ` AND PCPEDC.DATA BETWEEN TO_DATE('${startFormat}', 'DD/MM/YYYY') AND TO_DATE('${endFormat}', 'DD/MM/YYYY') `; + const result = await queryRunner.query(sql + sqlWhere); + + // Armazena o resultado no cache com TTL de 1 hora (3600 segundos) + try { + await this.redisClient.set(cacheKey, JSON.stringify(result), 'EX', 3600); + } catch (cacheSetErr) { + console.error('Erro ao salvar o resultado no cache (getOrders):', cacheSetErr?.message || cacheSetErr); + } + return result; - } catch (error) { - console.log(error); + } catch (error) { + console.error('Erro ao executar a query no getOrders:', error?.message || error); throw error; - } finally { + } finally { await queryRunner.release(); await connection.close(); + + // Libera o lock, somente se o valor armazenado for o mesmo deste processo + try { + const currentLockValue = await this.redisClient.get(lockKey); + if (currentLockValue === lockValue.toString()) { + await this.redisClient.del(lockKey); + } + } catch (lockErr) { + console.error('Erro ao liberar o lock do Redis (getOrders):', lockErr?.message || lockErr); + } + } + } else { + // Se não conseguir adquirir o lock, aguarda 1 segundo e tenta novamente + console.log('Lock não adquirido (getOrders), aguardando e tentando novamente...'); + await this.sleep(1000); + return this.getOrders(store, initialDate, finalDate, document, name, sellerId, idOrder); } - - } + } + + // Função auxiliar para aguardar um período determinado (em milissegundos) + private sleep(ms: number): Promise { + return new Promise(resolve => setTimeout(resolve, ms)); + } + async getItensOrder(idOrder: number) { const connection = new Connection(connectionOptions); diff --git a/src/sales/sales/sales.service.ts b/src/sales/sales/sales.service.ts index 1563bec..f7e1921 100644 --- a/src/sales/sales/sales.service.ts +++ b/src/sales/sales/sales.service.ts @@ -352,36 +352,97 @@ export class SalesService { } - async searchByDepartment(store: string, pageSize: number, pageNumber: number, urlDepartment: string): Promise { - const connectionDb = new Connection(connectionOptions); - await connectionDb.connect(); - const queryRunner = connectionDb.createQueryRunner(); - await queryRunner.connect(); + async searchByDepartment( + store: string, + pageSize: number, + pageNumber: number, + urlDepartment: string + ): Promise { + const cacheKey = + 'searchByDepartment:' + + store + + '_' + + pageSize + + '_' + + pageNumber + + '_' + + urlDepartment; + const lockKey = 'lock:' + cacheKey; + const lockTimeout = 30; // lock expira em 30 segundos + try { - if (pageSize == 0) - pageSize = 50; - if (pageNumber == 0) - pageNumber = 1; + const cachedResult = await this.redisClient.get(cacheKey); + if (cachedResult) { + console.log('Retornando resultado do cache (searchByDepartment)'); + return JSON.parse(cachedResult); + } + } catch (err) { + console.error('Erro ao acessar o Redis no searchByDepartment:', err?.message || err); + } + + const lockValue = Date.now() + lockTimeout * 1000 + 1; + let acquiredLock: string | null = null; + try { + acquiredLock = await this.redisClient.set(lockKey, lockValue, 'NX', 'EX', lockTimeout); + } catch (err) { + console.error('Erro ao adquirir lock no Redis (searchByDepartment):', err?.message || err); + } + + if (acquiredLock === 'OK') { + const connectionDb = new Connection(connectionOptions); + await connectionDb.connect(); + const queryRunner = connectionDb.createQueryRunner(); + await queryRunner.connect(); + try { + if (pageSize === 0) pageSize = 50; + if (pageNumber === 0) pageNumber = 1; const offSet = (pageNumber - 1) * pageSize; + let products = await queryRunner.manager - .getRepository(SalesProduct) - .createQueryBuilder('esvlistaprodutos') - .where('\"esvlistaprodutos\".urldepartamento = :urlDepartment', { urlDepartment }) - .andWhere("(\"esvlistaprodutos\".codfilial = :codfilial OR :codfilial = '99')", { codfilial: store }) - .limit(pageSize) - .offset(offSet) - .orderBy("\"esvlistaprodutos\".DESCRICAO", "ASC") - .getMany(); + .getRepository(SalesProduct) + .createQueryBuilder('esvlistaprodutos') + .where('"esvlistaprodutos".urldepartamento = :urlDepartment', { urlDepartment }) + .andWhere('("esvlistaprodutos".codfilial = :codfilial OR :codfilial = \'99\')', { codfilial: store }) + .limit(pageSize) + .offset(offSet) + .orderBy('"esvlistaprodutos".DESCRICAO', 'ASC') + .getMany(); + products = this.createListImages(products); + + try { + await this.redisClient.set(cacheKey, JSON.stringify(products), 'EX', 3600); + } catch (cacheErr) { + console.error('Erro ao salvar o resultado no cache (searchByDepartment):', cacheErr?.message || cacheErr); + } + return products; - } catch (error) { - console.log(error); + } catch (error) { + console.error('Erro ao executar a query no searchByDepartment:', error?.message || error); throw error; - } finally { + } finally { await queryRunner.release(); await connectionDb.close(); + + try { + const currentLockValue = await this.redisClient.get(lockKey); + if (currentLockValue === lockValue.toString()) { + await this.redisClient.del(lockKey); + } + } catch (lockErr) { + console.error('Erro ao liberar o lock do Redis (searchByDepartment):', lockErr?.message || lockErr); + } + } + } else { + console.log('Lock não adquirido (searchByDepartment), aguardando e tentando novamente...'); + await this.sleep(1000); + return this.searchByDepartment(store, pageSize, pageNumber, urlDepartment); } - } + } + + + + async searchBySection(store: string, pageSize: number, pageNumber: number, urlDepartment: string, urlSection: string): Promise { const connectionDb = new Connection(connectionOptions); @@ -1157,17 +1218,14 @@ export class SalesService { async searchProduct2(store: string, pageSize: number, pageNumber: number, filter: FilterProduct) { console.log('searchProduct2'); - // Cria uma chave única para o cache utilizando os parâmetros da função const cacheKey = `searchProduct2:${store}:${pageSize}:${pageNumber}:${JSON.stringify(filter)}`; - // Tenta recuperar os produtos do cache const cachedProducts = await this.redisClient.get(cacheKey); if (cachedProducts) { console.log('Retornando produtos do cache'); return JSON.parse(cachedProducts); } - // Monta a consulta SQL const sql = 'SELECT esvlistaprodutos.CODPROD "idProduct" ' + ` ,esvlistaprodutos.SEQ "seq" ` + ' ,esvlistaprodutos.DESCRICAO "smallDescription" ' + @@ -1210,7 +1268,6 @@ export class SalesService { ' FROM esvlistaprodutos ' + ' WHERE 1 = 1'; - // Concatena as condições WHERE baseadas nos filtros let where = ""; if (filter.text != null) { where += ` AND ( ESF_REMOVE_ACENTUACAO(UPPER(esvlistaprodutos.descricao)) LIKE ` + From 6c324df9e9d5417e317360f3ff261fde8f88e394 Mon Sep 17 00:00:00 2001 From: JurTI-BR Date: Fri, 14 Mar 2025 11:04:20 -0300 Subject: [PATCH 3/5] Ajuste comentario cache de departamento --- src/sales/order/order.service.ts | 1 + src/sales/sales/sales.service.ts | 4 +--- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/sales/order/order.service.ts b/src/sales/order/order.service.ts index a1b342f..f6b7ed3 100644 --- a/src/sales/order/order.service.ts +++ b/src/sales/order/order.service.ts @@ -672,6 +672,7 @@ export class OrderService { numeroSeq = numeroSeq + 1; } + // execute some operations on this transaction: await queryRunner.manager .createQueryBuilder() .insert() diff --git a/src/sales/sales/sales.service.ts b/src/sales/sales/sales.service.ts index f7e1921..f0684d8 100644 --- a/src/sales/sales/sales.service.ts +++ b/src/sales/sales/sales.service.ts @@ -1123,10 +1123,9 @@ export class SalesService { async getDepartments(): Promise { const cacheKey = 'departments'; const lockKey = 'departments_lock'; - const lockTimeout = 30; // lock expira em 30 segundos + const lockTimeout = 30; try { - // Tenta recuperar os departamentos do cache const cachedDepartments = await this.redisClient.get(cacheKey); if (cachedDepartments) { console.log('Buscando departamentos no Redis'); @@ -1134,7 +1133,6 @@ export class SalesService { } } catch (err) { console.error('Erro ao acessar o Redis (cache):', err); - // Se o Redis falhar, a execução continua para consultar o banco } const lockValue = Date.now() + lockTimeout * 1000 + 1; const acquiredLock = await this.redisClient.set(lockKey, lockValue, 'NX', 'EX', lockTimeout); From 17fd2a5411925605d2329d5dc387648b7fd362ed Mon Sep 17 00:00:00 2001 From: JurTI-BR Date: Fri, 14 Mar 2025 13:01:15 -0300 Subject: [PATCH 4/5] Ajuste comentario cache de departamento --- src/sales/order/order.service.ts | 178 +++++++++---------------------- 1 file changed, 48 insertions(+), 130 deletions(-) diff --git a/src/sales/order/order.service.ts b/src/sales/order/order.service.ts index f6b7ed3..2bb3a10 100644 --- a/src/sales/order/order.service.ts +++ b/src/sales/order/order.service.ts @@ -796,159 +796,77 @@ export class OrderService { } } - async getOrders( - store: string, - initialDate: any, - finalDate: any, - document: string, - name: string, - sellerId: number, - idOrder: string - ): Promise { + async getOrders(store: string, initialDate: Date, finalDate: Date, + document: string, name: string, sellerId: number, idOrder: string) { + const connection = new Connection(connectionOptions); + await connection.connect(); + const queryRunner = connection.createQueryRunner(); + await queryRunner.connect(); + let sqlWhere = ''; + let sql = ''; - const initialDateObj = initialDate instanceof Date ? initialDate : new Date(initialDate); - const finalDateObj = finalDate instanceof Date ? finalDate : new Date(finalDate); - - const cacheKey = - 'getOrders:' + - store + - '_' + - initialDateObj.toISOString() + - '_' + - finalDateObj.toISOString() + - '_' + - document + - '_' + - name + - '_' + - sellerId + - '_' + - idOrder; - - const lockKey = 'lock:' + cacheKey; - const lockTimeout = 30; // lock expira em 30 segundos - try { - const cachedResult = await this.redisClient.get(cacheKey); - if (cachedResult) { - console.log('Retornando resultado do cache (getOrders)'); - return JSON.parse(cachedResult); - } - } catch (err) { - console.error('Erro ao acessar o Redis no getOrders:', err?.message || err); - } - - const lockValue = Date.now() + lockTimeout * 1000 + 1; - let acquiredLock: string | null = null; - try { - acquiredLock = await this.redisClient.set(lockKey, lockValue, 'NX', 'EX', lockTimeout); - } catch (err) { - console.error('Erro ao adquirir lock no Redis (getOrders):', err?.message || err); - } - - if (acquiredLock === 'OK') { - const connection = new Connection(connectionOptions); - await connection.connect(); - const queryRunner = connection.createQueryRunner(); - await queryRunner.connect(); - let sqlWhere = ''; - let sql = ''; - - try { - sql = ` SELECT TO_CHAR(PCPEDC.DATA, 'DD/MM/YYYY') as "createDate", - PCPEDC.NUMPED as "orderId", - PCPEDC.CODFILIAL as "store", - CASE - WHEN PCPEDC.POSICAO = 'B' THEN 'BLOQUEADO' - WHEN PCPEDC.POSICAO = 'P' THEN 'PENDENTE' - WHEN PCPEDC.POSICAO = 'L' THEN 'LIBERADO' - WHEN PCPEDC.POSICAO = 'M' THEN 'MONTADO' - WHEN PCPEDC.POSICAO = 'F' THEN 'FATURADO' - END as "status", - PCPEDC.CODCLI as "customerId", - PCPEDC.CODUSUR as "sellerId", - PCCLIENT.CLIENTE as "customerName", - PCPEDC.VLATEND as "orderValue", - PCPEDC.NUMITENS as "itens", - CASE WHEN ( SELECT COUNT(1) FROM ESTPIX WHERE ESTPIX.NUMPED = PCPEDC.NUMPED ) > 0 THEN 'S' ELSE 'N' END as "pixCreate" - FROM PCPEDC, PCCLIENT - WHERE PCPEDC.CODCLI = PCCLIENT.CODCLI - AND PCPEDC.CONDVENDA IN (1,7) - AND PCPEDC.DTCANCEL IS NULL - AND PCPEDC.POSICAO NOT IN ('C') - AND PCPEDC.ROTINALANC = 'VENDAWEB' `; - - if (store && store !== '') { - sqlWhere += ` AND PCPEDC.CODFILIAL = '${store}' `; + sql = ` SELECT TO_CHAR(PCPEDC.DATA, \'DD/MM/YYYY\') as "createDate" ` + + ` ,PCPEDC.NUMPED as "orderId" ` + + ` ,PCPEDC.CODFILIAL as "store" ` + + ` ,CASE WHEN PCPEDC.POSICAO = 'B' THEN 'BLOQUEADO' ` + + ` WHEN PCPEDC.POSICAO = 'P' THEN 'PENDENTE' ` + + ` WHEN PCPEDC.POSICAO = 'L' THEN 'LIBERADO' ` + + ` WHEN PCPEDC.POSICAO = 'M' THEN 'MONTADO' ` + + ` WHEN PCPEDC.POSICAO = 'F' THEN 'FATURADO' END as "status" ` + + ` ,PCPEDC.CODCLI as "customerId" ` + + ` ,PCPEDC.CODUSUR as "sellerId" ` + + ` ,PCCLIENT.CLIENTE as "customerName" ` + + ` ,PCPEDC.VLATEND as "orderValue" ` + + ` ,PCPEDC.NUMITENS as "itens" ` + + ` ,CASE WHEN ( SELECT COUNT(1) FROM ESTPIX WHERE ESTPIX.NUMPED = PCPEDC.NUMPED ) > 0 THEN 'S' ELSE 'N' END as "pixCreate" ` + + ` FROM PCPEDC, PCCLIENT ` + + ` WHERE PCPEDC.CODCLI = PCCLIENT.CODCLI ` + + ` AND PCPEDC.CONDVENDA IN (1,7) ` + + ` AND PCPEDC.DTCANCEL IS NULL AND PCPEDC.POSICAO NOT IN ('C') `; + ` AND PCPEDC.ROTINALANC = 'VENDAWEB' `; + if (store != null && store != '') { + sqlWhere += ` AND PCPEDC.CODFILIAL = '${store}' `; } - if (document && document !== '') { - sqlWhere += ` AND REGEXP_REPLACE(PCCLIENT.CGCENT, '[^0-9]', '') = REGEXP_REPLACE('${document}', '[^0-9]', '') `; + if (document != null && document != '') { + sqlWhere += ` AND REGEXP_REPLACE(PCCLIENT.CGCENT, '[^0-9]', '') = REGEXP_REPLACE('${document}', '[^0-9]', '')`; } - if (name && name !== '') { - sqlWhere += ` AND PCCLIENT.CLIENTE LIKE '${name.replace('@', '%')}'||'%' `; + if (name != null && name != '') { + sqlWhere += ` AND PCCLIENT.CLIENTE LIKE '${name.replace('@', '%')}'||'%'`; } if (sellerId > 0) { - sqlWhere += ` AND PCPEDC.CODUSUR = ${sellerId} `; + sqlWhere += ` AND PCPEDC.CODUSUR = ${sellerId} `; } - if (idOrder && idOrder.trim() !== '') { - sqlWhere += ` AND PCPEDC.NUMPED = ${idOrder} `; + if (idOrder.trim() != null && idOrder.trim() != '') { + sqlWhere += ` AND PCPEDC.NUMPED = ${idOrder} `; } - - // Formatação das datas para o SQL - const startDate = initialDateObj; + + //tratamento de data// + const startDate = new Date(initialDate); let day = startDate.getDate(); let month = ("00" + (startDate.getMonth() + 1)).slice(-2); let year = startDate.getFullYear(); const startFormat = day + "/" + month + "/" + year; - - const endDate = finalDateObj; + const endDate = new Date(finalDate); day = endDate.getDate(); month = ("00" + (endDate.getMonth() + 1)).slice(-2); year = endDate.getFullYear(); const endFormat = day + "/" + month + "/" + year; - - sqlWhere += ` AND PCPEDC.DATA BETWEEN TO_DATE('${startFormat}', 'DD/MM/YYYY') AND TO_DATE('${endFormat}', 'DD/MM/YYYY') `; - + + sqlWhere += ` AND PCPEDC.DATA BETWEEN TO_DATE('${startFormat}', 'DD/MM/YYYY') AND TO_DATE('${endFormat}', 'DD/MM/YYYY') `; + const result = await queryRunner.query(sql + sqlWhere); - - // Armazena o resultado no cache com TTL de 1 hora (3600 segundos) - try { - await this.redisClient.set(cacheKey, JSON.stringify(result), 'EX', 3600); - } catch (cacheSetErr) { - console.error('Erro ao salvar o resultado no cache (getOrders):', cacheSetErr?.message || cacheSetErr); - } - return result; - } catch (error) { - console.error('Erro ao executar a query no getOrders:', error?.message || error); + } catch (error) { + console.log(error); throw error; - } finally { + } finally { await queryRunner.release(); await connection.close(); - - // Libera o lock, somente se o valor armazenado for o mesmo deste processo - try { - const currentLockValue = await this.redisClient.get(lockKey); - if (currentLockValue === lockValue.toString()) { - await this.redisClient.del(lockKey); - } - } catch (lockErr) { - console.error('Erro ao liberar o lock do Redis (getOrders):', lockErr?.message || lockErr); - } - } - } else { - // Se não conseguir adquirir o lock, aguarda 1 segundo e tenta novamente - console.log('Lock não adquirido (getOrders), aguardando e tentando novamente...'); - await this.sleep(1000); - return this.getOrders(store, initialDate, finalDate, document, name, sellerId, idOrder); } - } - - // Função auxiliar para aguardar um período determinado (em milissegundos) - private sleep(ms: number): Promise { - return new Promise(resolve => setTimeout(resolve, ms)); - } + + } async getItensOrder(idOrder: number) { From bdb0cd926a652e249563d6b0f4f4eba4068a46f1 Mon Sep 17 00:00:00 2001 From: JurTI-BR Date: Fri, 14 Mar 2025 15:22:40 -0300 Subject: [PATCH 5/5] =?UTF-8?q?commit=20antes=20da=20migra=C3=A7=C3=A3o=20?= =?UTF-8?q?da=20versao=20do=20TYPEORM?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 71 +++++++++---------- package.json | 2 +- .../access-control/access-control.service.ts | 3 + src/app.module.ts | 5 +- src/partner-range/partner-range.service.ts | 3 + src/partner/partner.service.ts | 3 + .../address-customer.service.ts | 2 + src/sales/customer/customer.service.ts | 14 +--- src/sales/dashboard/dashboard.service.ts | 3 + src/sales/pre-order/pre-order.service.ts | 3 + src/seller/seller.service.ts | 3 + src/shared/services/shared.service.ts | 3 + 12 files changed, 63 insertions(+), 52 deletions(-) diff --git a/package-lock.json b/package-lock.json index 859be27..4e47102 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2386,7 +2386,7 @@ "any-promise": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=" + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==" }, "anymatch": { "version": "3.1.1", @@ -2399,9 +2399,9 @@ } }, "app-root-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-3.0.0.tgz", - "integrity": "sha512-qMcx+Gy2UZynHjOHOIXPNvpf+9cjvk3cWrBBK7zg4gH9+clobJRb9NGzcT7mQTcV/6Gm/1WelUtqxVXnNlrwcw==" + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-3.1.0.tgz", + "integrity": "sha512-biN3PwB2gUtjaYy/isrU3aNWI5w+fAfvHkSvCKeQGxhmYpwKFUxudR3Yya+KqVRHBmEDYh+/lTozYCFbmzX4nA==" }, "append-field": { "version": "1.0.0", @@ -3124,12 +3124,12 @@ } }, "cli-highlight": { - "version": "2.1.10", - "resolved": "https://registry.npmjs.org/cli-highlight/-/cli-highlight-2.1.10.tgz", - "integrity": "sha512-CcPFD3JwdQ2oSzy+AMG6j3LRTkNjM82kzcSKzoVw6cLanDCJNlsLjeqVTOTfOfucnWv5F0rmBemVf1m9JiIasw==", + "version": "2.1.11", + "resolved": "https://registry.npmjs.org/cli-highlight/-/cli-highlight-2.1.11.tgz", + "integrity": "sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg==", "requires": { "chalk": "^4.0.0", - "highlight.js": "^10.0.0", + "highlight.js": "^10.7.1", "mz": "^2.4.0", "parse5": "^5.1.1", "parse5-htmlparser2-tree-adapter": "^6.0.0", @@ -4641,9 +4641,9 @@ } }, "figlet": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/figlet/-/figlet-1.5.0.tgz", - "integrity": "sha512-ZQJM4aifMpz6H19AW1VqvZ7l4pOE9p7i/3LyxgO2kp+PO/VcDYNqIHEMtkccqIhTXMKci4kjueJr/iCQEaT/Ww==" + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/figlet/-/figlet-1.8.0.tgz", + "integrity": "sha512-chzvGjd+Sp7KUvPHZv6EXV5Ir3Q7kYNpCr4aHrRW79qFtTefmQZNny+W1pW9kf5zeE6dikku2W50W/wAH2xWgw==" }, "figures": { "version": "3.2.0", @@ -5027,7 +5027,7 @@ "has-ansi": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==", "requires": { "ansi-regex": "^2.0.0" }, @@ -5035,7 +5035,7 @@ "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==" } } }, @@ -5103,9 +5103,9 @@ } }, "highlight.js": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.6.0.tgz", - "integrity": "sha512-8mlRcn5vk/r4+QcqerapwBYTe+iPL5ih6xrNylxrnBdHQiijDETfXX7VIxC3UiCRiINBJfANBAsPzAvRQj8RpQ==" + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", + "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==" }, "hosted-git-info": { "version": "2.8.8", @@ -7909,7 +7909,7 @@ "parent-require": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/parent-require/-/parent-require-1.0.0.tgz", - "integrity": "sha1-dGoWdjgIOoYLDu9nMssn7UbDKXc=" + "integrity": "sha512-2MXDNZC4aXdkkap+rBBMv0lUsfJqvX5/2FiYYnfCnorZt3Pk06/IOR5KeaoghgS2w07MLWgjbsnyaq6PdHn2LQ==" }, "parse-bmfont-ascii": { "version": "1.0.6", @@ -9989,7 +9989,7 @@ "thenify-all": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", - "integrity": "sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY=", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", "requires": { "thenify": ">= 3.1.0 < 4" } @@ -10436,11 +10436,11 @@ }, "dependencies": { "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", "requires": { - "ms": "2.1.2" + "ms": "^2.1.3" } }, "mkdirp": { @@ -10448,11 +10448,6 @@ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, "tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", @@ -10928,9 +10923,9 @@ "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" }, "y18n": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.5.tgz", - "integrity": "sha512-hsRUr4FFrvhhRH12wOdfs38Gy7k2FFzB9qgN9v3aLykRq0dRcdcpz5C9FxdS2NuhOrI/628b/KSTJ3rwHysYSg==" + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" }, "yallist": { "version": "4.0.0", @@ -10956,17 +10951,17 @@ "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==" }, "ansi-styles": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==" }, "chalk": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", "requires": { "ansi-styles": "^2.2.1", "escape-string-regexp": "^1.0.2", @@ -10978,7 +10973,7 @@ "strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", "requires": { "ansi-regex": "^2.0.0" } @@ -10986,7 +10981,7 @@ "supports-color": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==" } } }, @@ -11005,9 +11000,9 @@ } }, "yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==" + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==" }, "yn": { "version": "3.1.1", diff --git a/package.json b/package.json index 0833e5a..b3b12d9 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "rxjs": "^7.8.0", "stimulsoft-reports-js": "^2021.1.1", "swagger-ui-express": "^4.6.3", - "typeorm": "^0.2.25", + "typeorm": "^0.2.30", "uuid": "^8.3.2" }, "devDependencies": { diff --git a/src/Auth/access-control/access-control.service.ts b/src/Auth/access-control/access-control.service.ts index 73233bc..458550c 100644 --- a/src/Auth/access-control/access-control.service.ts +++ b/src/Auth/access-control/access-control.service.ts @@ -5,6 +5,9 @@ https://docs.nestjs.com/providers#services import { Injectable } from '@nestjs/common'; import { connectionOptions } from 'src/configs/typeorm.config'; import { Connection } from 'typeorm'; +//import { DataSource } from 'typeorm'; +//import { EntityManager } from 'typeorm'; + import { IndexActions } from '../../domain/models/index-action.model'; @Injectable() diff --git a/src/app.module.ts b/src/app.module.ts index 7ebebcf..36c0614 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -37,6 +37,8 @@ import { AppService } from './app.service'; import { TypeOrmModule } from '@nestjs/typeorm'; import { typeOrmConfig } from './configs/typeorm.config'; import { Connection } from 'typeorm'; +//import { DataSource } from 'typeorm'; +//import { EntityManager } from 'typeorm'; import { DictionaryModule } from './backoffice/dictionary/dictionary.module'; import { ConfigModule } from '@nestjs/config/dist/config.module'; import { RedisModule } from './redis/redis.module'; @@ -99,7 +101,8 @@ import { RedisModule } from './redis/redis.module'; exports: [redisProvider], }) export class AppModule implements NestModule { - + + constructor(private connection: Connection) { } // eslint-disable-next-line @typescript-eslint/no-empty-function, @typescript-eslint/no-unused-vars diff --git a/src/partner-range/partner-range.service.ts b/src/partner-range/partner-range.service.ts index beccd0c..83303f1 100644 --- a/src/partner-range/partner-range.service.ts +++ b/src/partner-range/partner-range.service.ts @@ -7,6 +7,9 @@ import { connectionOptions } from 'src/configs/typeorm.config'; import { Estfaixaparceiro } from 'src/domain/entity/tables/estfaixaparceiro.entity'; import { PartnerRange } from 'src/domain/models/partner-range.model'; import { Connection } from 'typeorm'; +//import { DataSource } from 'typeorm'; +import { EntityManager } from 'typeorm'; + @Injectable() export class PartnerRangeService { diff --git a/src/partner/partner.service.ts b/src/partner/partner.service.ts index 83639e3..b23f72b 100644 --- a/src/partner/partner.service.ts +++ b/src/partner/partner.service.ts @@ -10,6 +10,9 @@ import { Customer } from 'src/domain/models/customer.model'; import { Partner } from 'src/domain/models/partner.model'; import { CustomerService } from 'src/sales/customer/customer.service'; import { Connection } from 'typeorm'; +//import { DataSource } from 'typeorm'; +import { EntityManager } from 'typeorm'; + @Injectable() export class PartnerService { diff --git a/src/sales/address-customer/address-customer.service.ts b/src/sales/address-customer/address-customer.service.ts index 2a42580..850f6b9 100644 --- a/src/sales/address-customer/address-customer.service.ts +++ b/src/sales/address-customer/address-customer.service.ts @@ -1,6 +1,8 @@ import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; import { Address } from 'src/domain/models/address.model'; import { Connection } from 'typeorm'; +//import { DataSource } from 'typeorm'; +import { EntityManager } from 'typeorm'; import { Pcclientendent } from '../../domain/entity/tables/pcclientendent.entity'; import { Pccidade } from '../../domain/entity/tables/pccidade.entity'; import { ResultModel } from 'src/domain/models/result.model'; diff --git a/src/sales/customer/customer.service.ts b/src/sales/customer/customer.service.ts index 1515fa4..9e93355 100644 --- a/src/sales/customer/customer.service.ts +++ b/src/sales/customer/customer.service.ts @@ -3,6 +3,8 @@ import { Injectable, HttpException } from '@nestjs/common'; import { connectionOptions } from '../../configs/typeorm.config'; import { Customer } from '../../domain/models/customer.model'; import { Connection } from 'typeorm'; +//import { DataSource } from 'typeorm'; +import { EntityManager } from 'typeorm'; import { Pcclient } from '../../domain/entity/tables/pcclient.entity'; import { Estcategoriacliente } from '../../domain/entity/tables/estcategoriacliente.entity'; import { Estsubcategoriacliente } from '../../domain/entity/tables/estsubcategoriacliente.entity'; @@ -183,18 +185,6 @@ export class CustomerService { default: throw new HttpException('Não foi informado um campo válido para pesquisa.', HttpStatus.BAD_REQUEST); } - /* - if (document){ - where += "REGEXP_REPLACE(\"pcclient\".cgcent, '[^0-9]', '') = REGEXP_REPLACE('"+document+"', '[^0-9]', '')"; - } - if (name){ - - if(where.length > 0) { - where += " AND \"pcclient\".cliente like '" + name + "%'"; - } else { - where += "\"pcclient\".cliente like '" + name + "%'"; - } - }*/ const connection = new Connection(connectionOptions); await connection.connect(); diff --git a/src/sales/dashboard/dashboard.service.ts b/src/sales/dashboard/dashboard.service.ts index 4b7c9c6..04b19fa 100644 --- a/src/sales/dashboard/dashboard.service.ts +++ b/src/sales/dashboard/dashboard.service.ts @@ -5,6 +5,9 @@ https://docs.nestjs.com/providers#services import { Injectable } from '@nestjs/common'; import { connectionOptions } from 'src/configs/typeorm.config'; import { Connection } from 'typeorm'; +//import { DataSource } from 'typeorm'; +//import { EntityManager } from 'typeorm'; + @Injectable() export class DashboardService { diff --git a/src/sales/pre-order/pre-order.service.ts b/src/sales/pre-order/pre-order.service.ts index 2545882..18a6983 100644 --- a/src/sales/pre-order/pre-order.service.ts +++ b/src/sales/pre-order/pre-order.service.ts @@ -7,6 +7,9 @@ import { Pcorcavendai } from 'src/domain/entity/tables/pcorcavendai.entity'; import { Cart } from 'src/domain/models/cart.model'; import { SharedService } from 'src/shared/services/shared.service'; import { Connection } from 'typeorm'; +//import { DataSource } from 'typeorm'; +import { EntityManager } from 'typeorm'; + import { Pcorcavendac } from '../../domain/entity/tables/pcorcavendac.entity'; import { Shopping } from '../../domain/entity/tables/estprevendac.entity'; import { connectionOptions } from 'src/configs/typeorm.config'; diff --git a/src/seller/seller.service.ts b/src/seller/seller.service.ts index e4a3181..04af24e 100644 --- a/src/seller/seller.service.ts +++ b/src/seller/seller.service.ts @@ -5,6 +5,9 @@ https://docs.nestjs.com/providers#services import { Injectable } from '@nestjs/common'; import { connectionOptions } from 'src/configs/typeorm.config'; import { Connection } from 'typeorm'; +//import { DataSource } from 'typeorm'; +import { EntityManager } from 'typeorm'; + @Injectable() export class SellerService { diff --git a/src/shared/services/shared.service.ts b/src/shared/services/shared.service.ts index d294182..7f566b7 100644 --- a/src/shared/services/shared.service.ts +++ b/src/shared/services/shared.service.ts @@ -8,6 +8,9 @@ import { Pcclient } from 'src/domain/entity/tables/pcclient.entity'; import { Store } from 'src/domain/entity/tables/pcfilial.entity'; import { Pctabtrib } from 'src/domain/entity/tables/pctabtrib.entity'; import { Connection } from 'typeorm'; +//import { DataSource } from 'typeorm'; +import { EntityManager } from 'typeorm'; + @Injectable() export class SharedService {