dcos-core-monalisav2-latam 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +130 -0
- package/index.js +350 -0
- package/package.json +52 -0
- package/src/auth/handler.js +3 -0
- package/src/common/MondelezCastOrder.js +449 -0
- package/src/common/utils/AuthSecurity.js +46 -0
- package/src/common/utils/account-error-handler.js +279 -0
- package/src/common/utils/account-error-helper.js +231 -0
- package/src/common/utils/account-properties-handler.js +355 -0
- package/src/common/utils/api-response.js +62 -0
- package/src/common/utils/aws-services.js +186 -0
- package/src/common/utils/constants/account-error-codes.json +801 -0
- package/src/common/utils/constants.js +37 -0
- package/src/common/utils/convert/MondelezClientsItemsCast.js +52 -0
- package/src/common/utils/convert/MondelezInventoryItemsCast.js +15 -0
- package/src/common/utils/convert/MondelezOrderStatusCast.js +34 -0
- package/src/common/utils/convert/MondelezPricesItemsCast.js +37 -0
- package/src/common/utils/cron-ftp-get.js +143 -0
- package/src/common/utils/data-tables-helper.js +213 -0
- package/src/common/utils/date-range-calculator.js +113 -0
- package/src/common/utils/delay.js +17 -0
- package/src/common/utils/ftp-sftp.js +320 -0
- package/src/common/utils/logger.js +126 -0
- package/src/common/utils/nodemailerLib.js +61 -0
- package/src/common/utils/product-unit-converter.js +168 -0
- package/src/common/utils/schemas-utils.js +101 -0
- package/src/common/utils/seller-email-sharing-service.js +441 -0
- package/src/common/utils/sftp-utils.js +202 -0
- package/src/common/utils/status.js +15 -0
- package/src/common/utils/util.js +236 -0
- package/src/common/utils/validate-state-order.js +35 -0
- package/src/common/utils/validateProviders.js +67 -0
- package/src/common/utils/validation-data.js +45 -0
- package/src/common/utils/vtex/save-hooks.js +65 -0
- package/src/common/utils/vtex/save-schemas.js +65 -0
- package/src/common/utils/vtex-hook-handler.js +71 -0
- package/src/common/validation/AccountCoordinatesValidation.js +350 -0
- package/src/common/validation/GeneralErrorValidation.js +11 -0
- package/src/common/validation/MainErrorValidation.js +8 -0
- package/src/entities/account.js +639 -0
- package/src/entities/clients.js +104 -0
- package/src/entities/controlprice.js +196 -0
- package/src/entities/controlstock.js +206 -0
- package/src/entities/cron.js +77 -0
- package/src/entities/cronjob.js +71 -0
- package/src/entities/orders.js +195 -0
- package/src/entities/sftp-inbound.js +88 -0
- package/src/entities/sku.js +220 -0
- package/src/entities/taxpromotion.js +249 -0
- package/src/functions/account/account-get.js +262 -0
- package/src/functions/account/account-handler.js +299 -0
- package/src/functions/account/clients.js +10 -0
- package/src/functions/account/index.js +208 -0
- package/src/functions/actions/save-promotions-order-history.js +324 -0
- package/src/functions/affiliates/affiliates-hook-consumer.js +87 -0
- package/src/functions/affiliates/affiliates-hook-producer.js +45 -0
- package/src/functions/clients/clients-audience.js +62 -0
- package/src/functions/clients/clients-consumer.js +648 -0
- package/src/functions/clients/clients-producer.js +362 -0
- package/src/functions/clients/clients-suggested-product-consumer.js +166 -0
- package/src/functions/clients/helpers/suggested-product-mdlz.js +233 -0
- package/src/functions/clients_peru/email.html +129 -0
- package/src/functions/clients_peru/splitfile.js +357 -0
- package/src/functions/clients_peru/updateClients.js +1334 -0
- package/src/functions/clients_peru/utils.js +243 -0
- package/src/functions/cronjobs/cron-jobs-manager.js +40 -0
- package/src/functions/cronjobs/cron-jobs.js +171 -0
- package/src/functions/crons/cron.js +39 -0
- package/src/functions/distributors/distributor-handler.js +81 -0
- package/src/functions/distributors/distributor.js +535 -0
- package/src/functions/distributors/index.js +60 -0
- package/src/functions/financialpolicy/assign-financialpolicy.js +111 -0
- package/src/functions/financialpolicy/get-financialpolicy.js +91 -0
- package/src/functions/financialpolicy/index.js +28 -0
- package/src/functions/inventory/catalog-sync-consumer.js +17 -0
- package/src/functions/inventory/catalog-sync-handler.js +311 -0
- package/src/functions/inventory/inventory-consumer.js +119 -0
- package/src/functions/inventory/inventory-producer.js +197 -0
- package/src/functions/multiPresentation/multipre-queue.js +155 -0
- package/src/functions/multiPresentation/multipres.js +459 -0
- package/src/functions/nodeflow/index.js +83 -0
- package/src/functions/nodeflow/nodeflow-cron.js +200 -0
- package/src/functions/nodeflow/nodeflow-pub.js +203 -0
- package/src/functions/nodeflow/nodeflow-pvt.js +266 -0
- package/src/functions/notifications/download-leads-handler.js +67 -0
- package/src/functions/notifications/new-leads-notification-consumer.js +17 -0
- package/src/functions/notifications/new-leads-notification-handler.js +359 -0
- package/src/functions/notifications/order-status-notification-handler.js +482 -0
- package/src/functions/notifications/promotion-notification-handler.js +193 -0
- package/src/functions/orders/index.js +32 -0
- package/src/functions/orders/orders-cancel-handler.js +74 -0
- package/src/functions/orders/orders-handler.js +280 -0
- package/src/functions/orders/orders-hook-consumer.js +137 -0
- package/src/functions/orders/orders-hook-producer.js +170 -0
- package/src/functions/orders/orders-notifications-handler.js +137 -0
- package/src/functions/orders/orders-status-consumer.js +461 -0
- package/src/functions/orders/orders-status-producer.js +443 -0
- package/src/functions/prices/index.js +75 -0
- package/src/functions/prices/prices-consumer.js +236 -0
- package/src/functions/prices/prices-producer.js +323 -0
- package/src/functions/prices/promotion-and-tax.js +1284 -0
- package/src/functions/routesflow/assign-routeflow-queue.js +77 -0
- package/src/functions/schemas/vtex/handle-schemas.js +102 -0
- package/src/functions/security/process_gas.js +221 -0
- package/src/functions/security/security-handler.js +950 -0
- package/src/functions/sftp/sftp-consumer.js +453 -0
- package/src/functions/sftpIntegrations/processes/redirectServices.js +184 -0
- package/src/functions/sftpIntegrations/processes/validateFileSchema.js +226 -0
- package/src/functions/sftpIntegrations/schemas/credential-schema.js +123 -0
- package/src/functions/sftpIntegrations/schemas/record-schema.js +131 -0
- package/src/functions/sftpIntegrations/schemas/sftp_required_fields.json +3 -0
- package/src/functions/sftpIntegrations/sftp-config-producer.js +112 -0
- package/src/functions/sftpIntegrations/sftp-consumer.js +700 -0
- package/src/functions/sftpIntegrations/test/validateFile.test.js +122 -0
- package/src/functions/sftpIntegrations/utils/connect-dynamo.js +29 -0
- package/src/functions/sftpIntegrations/utils/split-data.js +25 -0
- package/src/functions/utils/index.js +130 -0
- package/src/functions/vtex/vtex-helpers.js +694 -0
- package/src/integrations/accountErrors/AccountErrorManager.js +437 -0
- package/src/integrations/audience/Audience.js +70 -0
- package/src/integrations/financialPolicy/FinancialPolicyApi.js +377 -0
- package/src/integrations/index.js +0 -0
- package/src/integrations/mobilvendor/MobilvendorApi.js +405 -0
- package/src/integrations/productmultipresentation/ProductMultiPresentation.js +200 -0
- package/src/mdlz/auth/SecretManagerApi.js +77 -0
- package/src/mdlz/client/MdlzApi.js +70 -0
- package/src/vtex/clients/ProvidersApi.js +51 -0
- package/src/vtex/clients/VtexApi.js +511 -0
- package/src/vtex/models/VtexOrder.js +87 -0
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
const FtpClient = require('ftp')
|
|
2
|
+
let SftpClient = require('ssh2-sftp-client');
|
|
3
|
+
const fs = require('fs')
|
|
4
|
+
|
|
5
|
+
class FileSystem {
|
|
6
|
+
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
class FileInfo {
|
|
10
|
+
constructor(original) {
|
|
11
|
+
this.original = original
|
|
12
|
+
}
|
|
13
|
+
getName() {
|
|
14
|
+
return this.original.name
|
|
15
|
+
}
|
|
16
|
+
getSize() {
|
|
17
|
+
return this.original.size
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// credits going to https://geedew.com/remove-a-directory-that-is-not-empty-in-nodejs/
|
|
22
|
+
var deleteFolderRecursive = function(path) {
|
|
23
|
+
if( fs.existsSync(path) ) {
|
|
24
|
+
fs.readdirSync(path).forEach(function(file,index){
|
|
25
|
+
var curPath = path + "/" + file;
|
|
26
|
+
if(fs.lstatSync(curPath).isDirectory()) { // recurse
|
|
27
|
+
deleteFolderRecursive(curPath);
|
|
28
|
+
} else { // delete file
|
|
29
|
+
fs.unlinkSync(curPath);
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
fs.rmdirSync(path);
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
class LocalFileSystem extends FileSystem {
|
|
37
|
+
constructor() {
|
|
38
|
+
super()
|
|
39
|
+
}
|
|
40
|
+
static create() {
|
|
41
|
+
return new Promise((resolve, reject) => {
|
|
42
|
+
return resolve(new LocalFileSystem())
|
|
43
|
+
})
|
|
44
|
+
}
|
|
45
|
+
async list(path) {
|
|
46
|
+
return new Promise((resolve, reject) => {
|
|
47
|
+
fs.readdir(path, async (err, files) => {
|
|
48
|
+
if (err) {
|
|
49
|
+
return reject(err)
|
|
50
|
+
}
|
|
51
|
+
await Promise.all(
|
|
52
|
+
files.map(fileName => new Promise((res, reject) => {
|
|
53
|
+
fs.stat(path + fileName, (err, stats) => {
|
|
54
|
+
if (err) {
|
|
55
|
+
return reject(err)
|
|
56
|
+
}
|
|
57
|
+
stats.name = fileName
|
|
58
|
+
res(new LocalFileInfo(stats))
|
|
59
|
+
})
|
|
60
|
+
}))
|
|
61
|
+
).then(res => {
|
|
62
|
+
resolve(res)
|
|
63
|
+
}).catch(err => {
|
|
64
|
+
reject(err)
|
|
65
|
+
})
|
|
66
|
+
})
|
|
67
|
+
})
|
|
68
|
+
}
|
|
69
|
+
put(src, toPath) {
|
|
70
|
+
return new Promise((resolve, reject) => {
|
|
71
|
+
try {
|
|
72
|
+
const writeStream = fs.createWriteStream(toPath)
|
|
73
|
+
src.pipe(writeStream)
|
|
74
|
+
resolve(true)
|
|
75
|
+
} catch (e) {
|
|
76
|
+
reject(e)
|
|
77
|
+
}
|
|
78
|
+
})
|
|
79
|
+
}
|
|
80
|
+
get(path) {
|
|
81
|
+
return new Promise((resolve, reject) => {
|
|
82
|
+
try {
|
|
83
|
+
const readStream = fs.createReadStream(path)
|
|
84
|
+
resolve(readStream)
|
|
85
|
+
} catch (e) {
|
|
86
|
+
reject(e)
|
|
87
|
+
}
|
|
88
|
+
})
|
|
89
|
+
}
|
|
90
|
+
mkdir(path, recursive) {
|
|
91
|
+
return fs.mkdir(path, { recursive })
|
|
92
|
+
}
|
|
93
|
+
rmdir(path, recursive) {
|
|
94
|
+
if (!recursive)
|
|
95
|
+
return fs.rmdir(path)
|
|
96
|
+
return new Promise((resolve, reject) => {
|
|
97
|
+
try {
|
|
98
|
+
deleteFolderRecursive(path)
|
|
99
|
+
resolve(true)
|
|
100
|
+
} catch (e) {
|
|
101
|
+
reject(e)
|
|
102
|
+
}
|
|
103
|
+
})
|
|
104
|
+
}
|
|
105
|
+
delete(path) {
|
|
106
|
+
return new Promise((resolve, reject) => {
|
|
107
|
+
fs.unlink(path, err => {
|
|
108
|
+
if (err) {
|
|
109
|
+
return reject(err)
|
|
110
|
+
}
|
|
111
|
+
resolve(true)
|
|
112
|
+
})
|
|
113
|
+
})
|
|
114
|
+
}
|
|
115
|
+
rename(oldPath, newPath) {
|
|
116
|
+
return new Promise((resolve, reject) => {
|
|
117
|
+
fs.rename(oldPath, newPath, err => {
|
|
118
|
+
if (err) {
|
|
119
|
+
return reject(err)
|
|
120
|
+
}
|
|
121
|
+
resolve(true)
|
|
122
|
+
})
|
|
123
|
+
})
|
|
124
|
+
}
|
|
125
|
+
// stats cannot be used with the current FTP library... so this feature will be left out for now
|
|
126
|
+
// stat(path) {
|
|
127
|
+
// return new Promise((resolve, reject) => {
|
|
128
|
+
// fs.stat(path, (err, stats) => {
|
|
129
|
+
// if (err) {
|
|
130
|
+
// return reject(err)
|
|
131
|
+
// }
|
|
132
|
+
// resolve(new LocalFileInfo(stats))
|
|
133
|
+
// })
|
|
134
|
+
// })
|
|
135
|
+
// }
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
class LocalFileInfo extends FileInfo {
|
|
139
|
+
isDirectory() {
|
|
140
|
+
return this.original.isDirectory()
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
class FtpFileSystem extends FileSystem {
|
|
145
|
+
constructor(client) {
|
|
146
|
+
super()
|
|
147
|
+
this.client = client
|
|
148
|
+
}
|
|
149
|
+
static async create(host, port, user, password) {
|
|
150
|
+
const c = new FtpClient()
|
|
151
|
+
return new Promise((resolve, reject) => {
|
|
152
|
+
c.on('ready', () => {
|
|
153
|
+
resolve(new FtpFileSystem(c))
|
|
154
|
+
})
|
|
155
|
+
c.once('error', (err) => {
|
|
156
|
+
reject(err)
|
|
157
|
+
})
|
|
158
|
+
c.connect({
|
|
159
|
+
host,
|
|
160
|
+
port,
|
|
161
|
+
user,
|
|
162
|
+
password
|
|
163
|
+
})
|
|
164
|
+
})
|
|
165
|
+
}
|
|
166
|
+
list(path) {
|
|
167
|
+
return new Promise((resolve, reject) => {
|
|
168
|
+
this.client.list(path, (err, listing) => {
|
|
169
|
+
if (err) {
|
|
170
|
+
return reject(err)
|
|
171
|
+
}
|
|
172
|
+
resolve(listing.map(l => new FtpFileInfo(l)))
|
|
173
|
+
})
|
|
174
|
+
})
|
|
175
|
+
}
|
|
176
|
+
put(src, toPath) {
|
|
177
|
+
return new Promise((resolve, reject) => {
|
|
178
|
+
this.client.put(src, toPath, (err) => {
|
|
179
|
+
if (err) {
|
|
180
|
+
reject(err)
|
|
181
|
+
}
|
|
182
|
+
resolve(true)
|
|
183
|
+
})
|
|
184
|
+
})
|
|
185
|
+
}
|
|
186
|
+
get(path) {
|
|
187
|
+
return new Promise((resolve, reject) => {
|
|
188
|
+
this.client.get(path, (err, stream) => {
|
|
189
|
+
if (err) {
|
|
190
|
+
return reject(err)
|
|
191
|
+
}
|
|
192
|
+
resolve(stream)
|
|
193
|
+
})
|
|
194
|
+
})
|
|
195
|
+
}
|
|
196
|
+
mkdir(path, recursive) {
|
|
197
|
+
return new Promise((resolve, reject) => {
|
|
198
|
+
this.client.mkdir(path, recursive, err => {
|
|
199
|
+
if (err) {
|
|
200
|
+
return reject(err)
|
|
201
|
+
}
|
|
202
|
+
resolve(true)
|
|
203
|
+
})
|
|
204
|
+
})
|
|
205
|
+
}
|
|
206
|
+
rmdir(path, recursive) {
|
|
207
|
+
return new Promise((resolve, reject) => {
|
|
208
|
+
this.client.rmdir(path, recursive, err => {
|
|
209
|
+
if (err) {
|
|
210
|
+
return reject(err)
|
|
211
|
+
}
|
|
212
|
+
resolve(1)
|
|
213
|
+
})
|
|
214
|
+
})
|
|
215
|
+
}
|
|
216
|
+
delete(path) {
|
|
217
|
+
return new Promise((resolve, reject) => {
|
|
218
|
+
this.client.delete(path, err => {
|
|
219
|
+
if (err) {
|
|
220
|
+
return reject(err)
|
|
221
|
+
}
|
|
222
|
+
resolve(path)
|
|
223
|
+
})
|
|
224
|
+
})
|
|
225
|
+
}
|
|
226
|
+
rename(oldPath, newPath) {
|
|
227
|
+
return new Promise((resolve, reject) => {
|
|
228
|
+
this.client.rename(oldPath, newPath, (err) => {
|
|
229
|
+
if (err) {
|
|
230
|
+
return reject(err)
|
|
231
|
+
}
|
|
232
|
+
resolve(true)
|
|
233
|
+
})
|
|
234
|
+
})
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
class FtpFileInfo extends FileInfo {
|
|
239
|
+
constructor(original) {
|
|
240
|
+
super(original)
|
|
241
|
+
}
|
|
242
|
+
isDirectory() {
|
|
243
|
+
return this.original.type === 'd'
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
class SftpFileSystem extends FileSystem {
|
|
248
|
+
constructor(client) {
|
|
249
|
+
super()
|
|
250
|
+
this.client = client
|
|
251
|
+
}
|
|
252
|
+
static async create(host, port, user, password) {
|
|
253
|
+
const c = new SftpClient()
|
|
254
|
+
return new Promise((resolve, reject) => {
|
|
255
|
+
c.connect({
|
|
256
|
+
host,
|
|
257
|
+
port,
|
|
258
|
+
username: user,
|
|
259
|
+
password
|
|
260
|
+
}).then(() => {
|
|
261
|
+
resolve(new SftpFileSystem(c))
|
|
262
|
+
}).catch(err => {
|
|
263
|
+
reject(err)
|
|
264
|
+
})
|
|
265
|
+
})
|
|
266
|
+
}
|
|
267
|
+
async list(path) {
|
|
268
|
+
return new Promise((resolve, reject) => {
|
|
269
|
+
this.client.list(path)
|
|
270
|
+
.then(paths => {
|
|
271
|
+
resolve(paths.map(it => new SftpFileInfo(it)))
|
|
272
|
+
}).catch(err => {
|
|
273
|
+
reject(err)
|
|
274
|
+
})
|
|
275
|
+
})
|
|
276
|
+
}
|
|
277
|
+
put(src, toPath) {
|
|
278
|
+
return this.client.put(src, toPath)
|
|
279
|
+
}
|
|
280
|
+
get(path) {
|
|
281
|
+
return new Promise((resolve, reject) => {
|
|
282
|
+
try {
|
|
283
|
+
resolve(this.client.sftp.createReadStream(path))
|
|
284
|
+
} catch (e) {
|
|
285
|
+
reject(e)
|
|
286
|
+
}
|
|
287
|
+
})
|
|
288
|
+
}
|
|
289
|
+
mkdir(path, recursive) {
|
|
290
|
+
return this.client.mkdir(path, recursive)
|
|
291
|
+
}
|
|
292
|
+
rmdir(path, recursive) {
|
|
293
|
+
return this.client.rmdir(path, recursive)
|
|
294
|
+
}
|
|
295
|
+
delete(path) {
|
|
296
|
+
return this.client.delete(path)
|
|
297
|
+
}
|
|
298
|
+
rename(oldPath, newPath) {
|
|
299
|
+
return this.client.rename(oldPath, newPath)
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
class SftpFileInfo extends FileInfo {
|
|
304
|
+
constructor(original) {
|
|
305
|
+
super(original)
|
|
306
|
+
}
|
|
307
|
+
isDirectory() {
|
|
308
|
+
return this.original.type === 'd'
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
module.exports = {
|
|
314
|
+
FileSystem,
|
|
315
|
+
FileInfo,
|
|
316
|
+
LocalFileSystem,
|
|
317
|
+
FtpFileSystem,
|
|
318
|
+
SftpFileSystem,
|
|
319
|
+
SftpFileInfo
|
|
320
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
class Logger {
|
|
2
|
+
static config = {
|
|
3
|
+
DebuggerOn: false,
|
|
4
|
+
AccountName: 'System',
|
|
5
|
+
showTimestamps: false,
|
|
6
|
+
showAccount: true,
|
|
7
|
+
showType: false
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
static _originalConsole = {
|
|
11
|
+
log: console.log,
|
|
12
|
+
info: console.info,
|
|
13
|
+
warn: console.warn,
|
|
14
|
+
error: console.error,
|
|
15
|
+
debug: console.debug,
|
|
16
|
+
dir: console.dir
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
// Objeto de configuración asociado a la instancia de la clase
|
|
20
|
+
config = { ...Logger.config };
|
|
21
|
+
|
|
22
|
+
constructor(configAccount = null) {
|
|
23
|
+
if (configAccount) {
|
|
24
|
+
this.setAccount(configAccount);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
setAccount(configAccount) {
|
|
29
|
+
const { DebuggerOn = false, ...remain } = configAccount;
|
|
30
|
+
this.config = { ...this.config, DebuggerOn, ...remain };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
log(...args) {
|
|
34
|
+
Logger._handleMessage(this, 'log', ...args);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
info(...args) {
|
|
38
|
+
Logger._handleMessage(this, 'info', ...args);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
warn(...args) {
|
|
42
|
+
Logger._handleMessage(this, 'warn', ...args);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
error(...args) {
|
|
46
|
+
Logger._handleMessage(this, 'error', ...args);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
debug(...args) {
|
|
50
|
+
Logger._handleMessage(this, 'debug', ...args);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Establece las opciones de configuración.
|
|
55
|
+
* @param {object} configAccount Objeto JSON del account en Monalisa V2.
|
|
56
|
+
*/
|
|
57
|
+
static setAccount(configAccount) {
|
|
58
|
+
if (configAccount) {
|
|
59
|
+
const { DebuggerOn = false, ...remain } = configAccount;
|
|
60
|
+
Logger.config = { ...Logger.config, DebuggerOn, ...remain };
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Métodos públicos (sin cambios para mantener compatibilidad)
|
|
65
|
+
static log(...args) {
|
|
66
|
+
Logger._handleMessage(Logger, 'log', ...args);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
static info(...args) {
|
|
70
|
+
Logger._handleMessage(Logger, 'info', ...args);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
static warn(...args) {
|
|
74
|
+
Logger._handleMessage(Logger, 'warn', ...args);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
static error(...args) {
|
|
78
|
+
Logger._handleMessage(Logger, 'error', ...args);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
static debug(...args) {
|
|
82
|
+
Logger._handleMessage(Logger, 'debug', ...args);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
static _handleMessage(thisRef, type, ...args) {
|
|
86
|
+
if (thisRef?.config?.DebuggerOn || ['log', 'error'].includes(type)) {
|
|
87
|
+
Logger._originalConsole[type](...Logger._format(thisRef, type, ...args));
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
static _format(thisRef, type, ...args) {
|
|
92
|
+
const header = [];
|
|
93
|
+
|
|
94
|
+
if (thisRef?.config?.showTimestamps) {
|
|
95
|
+
header.push(`[${new Date().toISOString()}]`);
|
|
96
|
+
}
|
|
97
|
+
if (thisRef?.config?.showAccount) {
|
|
98
|
+
header.push(`[${thisRef.config.AccountName}]`);
|
|
99
|
+
}
|
|
100
|
+
if (thisRef?.config?.showType) {
|
|
101
|
+
header.push(`[${type.toUpperCase()}]`);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const logsData = [];
|
|
105
|
+
if (header.length) {
|
|
106
|
+
logsData.push(header.join(''))
|
|
107
|
+
}
|
|
108
|
+
for (let arg of args) {
|
|
109
|
+
if (arg instanceof Error) {
|
|
110
|
+
logsData.push(arg.stack);
|
|
111
|
+
} else {
|
|
112
|
+
logsData.push(arg);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return logsData;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Overloading de las funciones de console
|
|
120
|
+
console.log = Logger.log
|
|
121
|
+
console.info = Logger.info
|
|
122
|
+
console.warn = Logger.warn
|
|
123
|
+
console.error = Logger.error
|
|
124
|
+
console.debug = Logger.debug
|
|
125
|
+
|
|
126
|
+
module.exports = Logger;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
const nodemailer = require('nodemailer');
|
|
2
|
+
const Logger = require("./logger");
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Obtiene la instancia del servicio para envío de correo electrónico.
|
|
6
|
+
* @param {object} mailSettings Parámetros de conexión.
|
|
7
|
+
* @returns Instancia de conexión al servidor de envío de correo.
|
|
8
|
+
* @see {@link https://nodemailer.com/smtp|NodeMailer SMTP TRANSPORT}
|
|
9
|
+
*/
|
|
10
|
+
exports.getEmailSender = async (mailSettings) => {
|
|
11
|
+
const { host, port = '2525', user, pass, encryption = 'tls' } = mailSettings;
|
|
12
|
+
|
|
13
|
+
const emailTransportOptions = { host, port, 'auth': { user, pass } };
|
|
14
|
+
switch (encryption) {
|
|
15
|
+
case 'tls':
|
|
16
|
+
emailTransportOptions.tls = { rejectUnauthorized: true }
|
|
17
|
+
break;
|
|
18
|
+
case 'ssl':
|
|
19
|
+
emailTransportOptions.secure = true
|
|
20
|
+
break;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Se conecta al servidor de envío de correos
|
|
24
|
+
const transporter = nodemailer.createTransport(emailTransportOptions);
|
|
25
|
+
return new Promise((resolve, reject) => {
|
|
26
|
+
transporter.verify(err => {
|
|
27
|
+
if (err) {
|
|
28
|
+
Logger.error(err);
|
|
29
|
+
reject(err);
|
|
30
|
+
} else {
|
|
31
|
+
Logger.debug(`Connected to email server ${host}`);
|
|
32
|
+
resolve(transporter);
|
|
33
|
+
}
|
|
34
|
+
})
|
|
35
|
+
});
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Realiza el envío del mensaje de correo electrónico.
|
|
40
|
+
* @param {*} mailSender Instancia de conexión al servidor de envío de correos.
|
|
41
|
+
* @param {*} emailOptions Objeto con las opciones de correo electrónico.
|
|
42
|
+
* @returns Respuesta del envío del mensaje.
|
|
43
|
+
*/
|
|
44
|
+
exports.sendEmail = async (mailSender, emailOptions, skipAttachment = true) => {
|
|
45
|
+
return new Promise((resolve, reject) => {
|
|
46
|
+
mailSender.sendMail(emailOptions).then(resolve).catch(err => {
|
|
47
|
+
if (skipAttachment && emailOptions?.attachments?.length) {
|
|
48
|
+
Logger.error("NodeMailer: Deleting attachments", {
|
|
49
|
+
count: emailOptions.attachments.length,
|
|
50
|
+
action: "cleanup",
|
|
51
|
+
source: "emailService"
|
|
52
|
+
});
|
|
53
|
+
Logger.error(err);
|
|
54
|
+
delete emailOptions.attachments;
|
|
55
|
+
this.sendEmail(mailSender, emailOptions, false).then(resolve).catch(reject);
|
|
56
|
+
} else {
|
|
57
|
+
reject(err);
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
const VtexApi = require("../../vtex/clients/VtexApi");
|
|
2
|
+
const Logger = require("./logger");
|
|
3
|
+
const Account = require("../../entities/account");
|
|
4
|
+
|
|
5
|
+
// VARIABLES ACCOUNT: unitProductValue (especificaciones de producto), componentsKitQuantity (cantidad de componentes del kit)
|
|
6
|
+
|
|
7
|
+
const convertQuantity = async (skuVtex, skuRefId, quantity, accountConfig, individualUnits) => {
|
|
8
|
+
|
|
9
|
+
Logger.setAccount(accountConfig);
|
|
10
|
+
Logger.debug('ProductUnitConversion: Inicio conversión', { skuVtex, skuRefId, quantity, accountConfig });
|
|
11
|
+
|
|
12
|
+
try {
|
|
13
|
+
const config = accountConfig?.ProductUnitConversion;
|
|
14
|
+
|
|
15
|
+
if (!config || !config.isActive) {
|
|
16
|
+
return quantity;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const unitProductFieldName = config.unitProduct; // String del nombre del campo
|
|
20
|
+
const componentsKits = config.useComponentsKits; // Booleano que indica si se utilizan kits de componentes
|
|
21
|
+
let unitProductValue = 1; // Valor por defecto
|
|
22
|
+
let componentsKitsQuantity = 1; // Valor por defecto
|
|
23
|
+
let componentsKitsQuantityMain = 1; // Valor por defecto
|
|
24
|
+
let unitMultiplierProduct = 1; // Valor por defecto unidad multiplicadora
|
|
25
|
+
let individualUnitsQuantity = individualUnits || 1;
|
|
26
|
+
|
|
27
|
+
let targetSku = [];
|
|
28
|
+
|
|
29
|
+
const vtexApi = new VtexApi(
|
|
30
|
+
accountConfig.AccountName,
|
|
31
|
+
accountConfig.Credentials.key,
|
|
32
|
+
accountConfig.Credentials.token
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
const detailSkuVtexPrincipal = await vtexApi.getDetailSkuById(skuVtex);
|
|
36
|
+
Logger.debug('ProductUnitConversion: Detalle SKU VTEX principal', { detailSkuVtexPrincipal });
|
|
37
|
+
|
|
38
|
+
if (!detailSkuVtexPrincipal || !Array.isArray(detailSkuVtexPrincipal) || detailSkuVtexPrincipal.length === 0) {
|
|
39
|
+
return quantity;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const productDetailVtexPrincipal = detailSkuVtexPrincipal[0];
|
|
43
|
+
|
|
44
|
+
if (productDetailVtexPrincipal && productDetailVtexPrincipal?.UnitMultiplier) {
|
|
45
|
+
unitMultiplierProduct= productDetailVtexPrincipal?.UnitMultiplier;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (productDetailVtexPrincipal?.KitItems && productDetailVtexPrincipal.KitItems.length > 0) {
|
|
49
|
+
componentsKitsQuantityMain = productDetailVtexPrincipal.KitItems[0]?.Amount || 1;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (componentsKits && config?.relationalProductPrefix?.length > 0) {
|
|
53
|
+
const relationSkuRef = buildKitSku(skuRefId, config.relationalProductPrefix);
|
|
54
|
+
targetSku = await vtexApi.getDetailSkuPerSkuRef(relationSkuRef);
|
|
55
|
+
|
|
56
|
+
for (let i = 0; i < targetSku.length; i++) {
|
|
57
|
+
const sku = targetSku[i];
|
|
58
|
+
if (sku.KitItems.length === 1) {
|
|
59
|
+
componentsKitsQuantity = sku.KitItems[0].Amount || 1;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (unitProductFieldName && unitProductFieldName !== "" && accountConfig) {
|
|
65
|
+
const specificationProductVtex = await getProductSpecificationPerProductId(productDetailVtexPrincipal.ProductId, vtexApi);
|
|
66
|
+
if (specificationProductVtex && specificationProductVtex[unitProductFieldName]) {
|
|
67
|
+
unitProductValue = parseInt(specificationProductVtex[unitProductFieldName][0]) || 1;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const expression = getExpression(skuRefId, config.rules);
|
|
72
|
+
|
|
73
|
+
let variables = {
|
|
74
|
+
quantity,
|
|
75
|
+
unitProductValue,
|
|
76
|
+
componentsKitsQuantity,
|
|
77
|
+
componentsKitsQuantityMain,
|
|
78
|
+
individualUnitsQuantity,
|
|
79
|
+
unitMultiplierProduct
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
Logger.debug('ProductUnitConversion: Evaluando expresión', { expression, variables });
|
|
83
|
+
const result = evaluateExpression(expression, variables);
|
|
84
|
+
|
|
85
|
+
Logger.debug('ProductUnitConversion: Resultado de conversión', { result });
|
|
86
|
+
return typeof result === 'number' ? result : quantity;
|
|
87
|
+
|
|
88
|
+
} catch (error) {
|
|
89
|
+
Logger.error('ProductUnitConversion: Error en conversión', { skuVtex, skuRefId, quantity, error: error.message });
|
|
90
|
+
return quantity;
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
const buildKitSku = (skuRefId, prefixes) => {
|
|
95
|
+
if (!prefixes || !Array.isArray(prefixes)) {
|
|
96
|
+
return skuRefId;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
let kitSku = [];
|
|
100
|
+
|
|
101
|
+
prefixes.forEach(prefix => {
|
|
102
|
+
if (prefix && prefix.value) {
|
|
103
|
+
if (prefix.position === 'initial') {
|
|
104
|
+
if (!skuRefId.startsWith(prefix.value)) {
|
|
105
|
+
kitSku.push(`${prefix.value}${skuRefId}`);
|
|
106
|
+
}
|
|
107
|
+
} else if (prefix.position === 'end') {
|
|
108
|
+
if (!skuRefId.endsWith(prefix.value)) {
|
|
109
|
+
kitSku.push(`${skuRefId}${prefix.value}`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
return kitSku;
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
const getExpression = (sku, rules) => {
|
|
120
|
+
if (!rules) {
|
|
121
|
+
return 'quantity';
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (rules.items && rules.items[sku]) {
|
|
125
|
+
return rules.items[sku];
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return rules.default || 'quantity';
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
const evaluateExpression = (expression, variables) => {
|
|
132
|
+
try {
|
|
133
|
+
const { quantity, unitProductValue, componentsKitsQuantity, componentsKitsQuantityMain, individualUnitsQuantity, unitMultiplierProduct } = variables;
|
|
134
|
+
const result = eval(expression);
|
|
135
|
+
return Math.round(parseFloat(result));
|
|
136
|
+
} catch (error) {
|
|
137
|
+
Logger.error('ProductUnitConversion: Error evaluando expresión', {
|
|
138
|
+
expression,
|
|
139
|
+
variables,
|
|
140
|
+
error: error.message
|
|
141
|
+
});
|
|
142
|
+
return variables.quantity;
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
const getProductSpecificationPerProductId = async (productId, vtexApi) => {
|
|
147
|
+
try {
|
|
148
|
+
const response = await vtexApi.fetch(`/catalog_system/pvt/products/${productId}/specification`, {
|
|
149
|
+
method: "GET",
|
|
150
|
+
});
|
|
151
|
+
if (response?.status < 200 || response?.status > 299) {
|
|
152
|
+
throw new Error("Error getting SKU in VTEX");
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
let specifications = {};
|
|
156
|
+
for (let i = 0; i < response.data.length; i++) {
|
|
157
|
+
const esp = response.data[i];
|
|
158
|
+
specifications[esp.Name] = esp.Value;
|
|
159
|
+
}
|
|
160
|
+
return specifications;
|
|
161
|
+
|
|
162
|
+
} catch (error) {
|
|
163
|
+
Logger.error("Error getting product specification", { productId, error: error.message });
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
module.exports = convertQuantity;
|