closer-cli 2.48.0 ā 2.48.2
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/CHANGELOG.md +16 -0
- package/cmds/importData.js +249 -39
- package/cmds/importMedia.js +39 -45
- package/helpers.js +67 -798
- package/index.js +4 -4
- package/package.json +5 -8
- package/cmds/importData_cmds/multiple.js +0 -341
- package/cmds/importData_cmds/single.js +0 -281
package/index.js
CHANGED
|
@@ -7,7 +7,7 @@ import yargs from 'yargs'
|
|
|
7
7
|
import * as ImportData from './cmds/importData.js'
|
|
8
8
|
import * as ImportMedia from './cmds/importMedia.js'
|
|
9
9
|
|
|
10
|
-
console.log(chalk.bold(`\n
|
|
10
|
+
console.log(chalk.bold(`\nš Closer CLI (${pkg.version})\n`))
|
|
11
11
|
|
|
12
12
|
yargs(process.argv.slice(2))
|
|
13
13
|
.scriptName('closer')
|
|
@@ -17,9 +17,9 @@ yargs(process.argv.slice(2))
|
|
|
17
17
|
describe: 'Closer URL',
|
|
18
18
|
demandOption: true
|
|
19
19
|
})
|
|
20
|
-
.option('
|
|
21
|
-
alias: 'secret',
|
|
22
|
-
describe: 'Closer Secret',
|
|
20
|
+
.option('k', {
|
|
21
|
+
alias: 'secret-key',
|
|
22
|
+
describe: 'Closer Secret Key',
|
|
23
23
|
demandOption: true
|
|
24
24
|
})
|
|
25
25
|
.command(ImportData.command, ImportData.desc, ImportData.builder, ImportData.handler)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "closer-cli",
|
|
3
|
-
"version": "2.48.
|
|
3
|
+
"version": "2.48.2",
|
|
4
4
|
"description": "",
|
|
5
5
|
"exports": "./index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -12,20 +12,17 @@
|
|
|
12
12
|
"author": "Francesco Pasqua <cesconix@me.com>",
|
|
13
13
|
"license": "ISC",
|
|
14
14
|
"dependencies": {
|
|
15
|
+
"axios": "^1.3.4",
|
|
15
16
|
"chalk": "^5.1.2",
|
|
16
|
-
"csv-parse": "^5.3.1",
|
|
17
|
-
"csv-stringify": "^6.2.0",
|
|
18
17
|
"del": "^7.0.0",
|
|
19
|
-
"
|
|
18
|
+
"form-data": "^4.0.0",
|
|
20
19
|
"got": "^12.5.2",
|
|
21
|
-
"mv": "^2.1.1",
|
|
22
20
|
"ora": "^6.1.2",
|
|
23
21
|
"prompts": "^2.4.2",
|
|
24
|
-
"
|
|
25
|
-
"rimraf": "^3.0.2",
|
|
22
|
+
"qs": "^6.11.0",
|
|
26
23
|
"slugify": "^1.6.3",
|
|
27
24
|
"ws": "^8.0.0",
|
|
28
25
|
"yargs": "^17.0.1"
|
|
29
26
|
},
|
|
30
|
-
"gitHead": "
|
|
27
|
+
"gitHead": "1fbbcab302b63f3123c234824fb8784cd7f286f2"
|
|
31
28
|
}
|
|
@@ -1,341 +0,0 @@
|
|
|
1
|
-
/* eslint-disable no-console */
|
|
2
|
-
/* eslint-disable no-await-in-loop */
|
|
3
|
-
/* eslint-disable no-restricted-syntax */
|
|
4
|
-
import { accessSync, constants, existsSync, mkdirSync } from 'fs'
|
|
5
|
-
import path from 'path'
|
|
6
|
-
import chalk from 'chalk'
|
|
7
|
-
import prompts from 'prompts'
|
|
8
|
-
import Ora from 'ora'
|
|
9
|
-
import move from 'mv'
|
|
10
|
-
import { promisify } from 'util'
|
|
11
|
-
import { deleteAsync } from 'del'
|
|
12
|
-
|
|
13
|
-
import {
|
|
14
|
-
getCsvFilesFromDir,
|
|
15
|
-
ALLOWED_CSV_FILES,
|
|
16
|
-
getGoogleSheetCsvUrl,
|
|
17
|
-
importCsvFromFile,
|
|
18
|
-
validateCsvFromFile,
|
|
19
|
-
refreshOrders,
|
|
20
|
-
download,
|
|
21
|
-
callBeforeDataImportProcess,
|
|
22
|
-
callAfterDataImportProcess,
|
|
23
|
-
getExecutionTime,
|
|
24
|
-
getArchiveFolder,
|
|
25
|
-
sendImportErrorMail,
|
|
26
|
-
deleteRowsBeforeImportDate,
|
|
27
|
-
readImportDir
|
|
28
|
-
} from '../../helpers.js'
|
|
29
|
-
|
|
30
|
-
const mv = promisify(move)
|
|
31
|
-
|
|
32
|
-
export const command = 'multiple [options]'
|
|
33
|
-
|
|
34
|
-
export const desc = 'Import different CSV files'
|
|
35
|
-
|
|
36
|
-
export function builder(yargs) {
|
|
37
|
-
yargs
|
|
38
|
-
.usage(`Usage: ${chalk.cyan('$0 import:data multiple')} [options]`)
|
|
39
|
-
.option('fromDir', {
|
|
40
|
-
alias: 'd',
|
|
41
|
-
describe: 'Directory path that contains files to import',
|
|
42
|
-
type: 'string'
|
|
43
|
-
})
|
|
44
|
-
.option('fromGoogleDocId', {
|
|
45
|
-
alias: 'g',
|
|
46
|
-
describe: 'Google Doc ID that contains sheets to import',
|
|
47
|
-
type: 'string'
|
|
48
|
-
})
|
|
49
|
-
.conflicts('fromDir', 'fromGoogleDocId')
|
|
50
|
-
.check(argv => {
|
|
51
|
-
if (!argv.fromDir && !argv.fromGoogleDocId) {
|
|
52
|
-
throw new Error('Missing required argument: fromDir OR fromGoogleDocId')
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
if (argv.fromDir) {
|
|
56
|
-
accessSync(argv.fromDir, constants.F_OK)
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
return true
|
|
60
|
-
})
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
export async function handler(argv) {
|
|
64
|
-
// eslint-disable-next-line no-param-reassign
|
|
65
|
-
argv.out = argv.out || getArchiveFolder(argv.endpoint)
|
|
66
|
-
|
|
67
|
-
const spinner = new Ora()
|
|
68
|
-
const hrstart = process.hrtime()
|
|
69
|
-
|
|
70
|
-
const importProcess = {
|
|
71
|
-
importProcessStart: new Date(),
|
|
72
|
-
importProcessEnd: null,
|
|
73
|
-
time: null,
|
|
74
|
-
endpoint: argv.endpoint,
|
|
75
|
-
mode: null,
|
|
76
|
-
name: argv.name,
|
|
77
|
-
type: [],
|
|
78
|
-
result: []
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
const dirPathTemp = path.resolve(argv.out, `${importProcess.name}_temp`)
|
|
82
|
-
const dirPathFinal = path.resolve(argv.out, importProcess.name)
|
|
83
|
-
const dirPathOriginal = path.resolve(dirPathTemp, '_original')
|
|
84
|
-
|
|
85
|
-
const interactive = !argv.nonInteractive
|
|
86
|
-
|
|
87
|
-
const ws = {
|
|
88
|
-
endpoint: argv.endpoint,
|
|
89
|
-
secret: argv.secret
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
let csvChoices = []
|
|
93
|
-
|
|
94
|
-
if (argv.fromDir) {
|
|
95
|
-
const csvFilesFromDir = getCsvFilesFromDir(argv.fromDir)
|
|
96
|
-
|
|
97
|
-
csvChoices = Object.keys(ALLOWED_CSV_FILES).map(csvType => ({
|
|
98
|
-
title: ALLOWED_CSV_FILES[csvType],
|
|
99
|
-
csvType,
|
|
100
|
-
value: {
|
|
101
|
-
file: path.resolve(argv.fromDir, ALLOWED_CSV_FILES[csvType]),
|
|
102
|
-
csvType
|
|
103
|
-
},
|
|
104
|
-
disabled: !csvFilesFromDir.includes(ALLOWED_CSV_FILES[csvType])
|
|
105
|
-
}))
|
|
106
|
-
} else {
|
|
107
|
-
csvChoices = Object.keys(ALLOWED_CSV_FILES).map(csvType => ({
|
|
108
|
-
title: csvType,
|
|
109
|
-
csvType,
|
|
110
|
-
value: {
|
|
111
|
-
url: getGoogleSheetCsvUrl(argv.fromGoogleDocId, csvType),
|
|
112
|
-
csvType
|
|
113
|
-
}
|
|
114
|
-
}))
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
let files
|
|
118
|
-
if (interactive && !argv.type) {
|
|
119
|
-
const answers = await prompts(
|
|
120
|
-
[
|
|
121
|
-
{
|
|
122
|
-
instructions: false,
|
|
123
|
-
name: 'files',
|
|
124
|
-
type: 'multiselect',
|
|
125
|
-
message: argv.fromDir ? 'Select Files' : 'Select Sheets',
|
|
126
|
-
warn: argv.fromDir && 'File not found',
|
|
127
|
-
choices: csvChoices,
|
|
128
|
-
min: 1
|
|
129
|
-
}
|
|
130
|
-
],
|
|
131
|
-
{ onCancel: () => process.exit() }
|
|
132
|
-
)
|
|
133
|
-
|
|
134
|
-
files = answers.files
|
|
135
|
-
} else {
|
|
136
|
-
files = argv.type.map(type => {
|
|
137
|
-
const choice = csvChoices.find(csvChoice => csvChoice.csvType === type)
|
|
138
|
-
return choice.value
|
|
139
|
-
})
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
importProcess.type = files.map(f => f.csvType)
|
|
143
|
-
|
|
144
|
-
let mode
|
|
145
|
-
if (interactive && !argv.mode) {
|
|
146
|
-
const answers = await prompts(
|
|
147
|
-
[
|
|
148
|
-
{
|
|
149
|
-
type: 'select',
|
|
150
|
-
name: 'mode',
|
|
151
|
-
message: 'Import Mode',
|
|
152
|
-
choices: [
|
|
153
|
-
{
|
|
154
|
-
title: 'Incremental',
|
|
155
|
-
value: 'incremental'
|
|
156
|
-
},
|
|
157
|
-
{
|
|
158
|
-
title: 'Full',
|
|
159
|
-
description: 'Before starting, all database records will be logically deleted',
|
|
160
|
-
value: 'full'
|
|
161
|
-
}
|
|
162
|
-
],
|
|
163
|
-
hint: ' '
|
|
164
|
-
}
|
|
165
|
-
],
|
|
166
|
-
{ onCancel: () => process.exit() }
|
|
167
|
-
)
|
|
168
|
-
|
|
169
|
-
mode = answers.mode
|
|
170
|
-
} else {
|
|
171
|
-
mode = argv.mode
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
importProcess.mode = mode
|
|
175
|
-
|
|
176
|
-
const validations = []
|
|
177
|
-
const csvReports = []
|
|
178
|
-
|
|
179
|
-
const parsedFiles = []
|
|
180
|
-
|
|
181
|
-
if (!existsSync(dirPathFinal) && !existsSync(dirPathOriginal)) {
|
|
182
|
-
mkdirSync(dirPathOriginal, { recursive: true })
|
|
183
|
-
} else {
|
|
184
|
-
console.log('')
|
|
185
|
-
console.log(`ERROR => directory "${dirPathFinal}" already exists, change the import name.`)
|
|
186
|
-
process.exit(1)
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
if (argv.fromGoogleDocId) {
|
|
190
|
-
console.log('')
|
|
191
|
-
spinner.start('Downloading Google sheets...')
|
|
192
|
-
for (const item of files) {
|
|
193
|
-
const filepath = await download(
|
|
194
|
-
item.url,
|
|
195
|
-
dirPathOriginal,
|
|
196
|
-
`${importProcess.name}_${item.csvType}.csv`
|
|
197
|
-
)
|
|
198
|
-
parsedFiles.push({ file: filepath, csvType: item.csvType })
|
|
199
|
-
}
|
|
200
|
-
spinner.succeed('Google sheets downloaded')
|
|
201
|
-
} else {
|
|
202
|
-
for (const file of files) {
|
|
203
|
-
const dst = path.resolve(dirPathOriginal, `${importProcess.name}_${file.csvType}.csv`)
|
|
204
|
-
await mv(file.file, dst)
|
|
205
|
-
parsedFiles.push({ file: dst, csvType: file.csvType })
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
//
|
|
210
|
-
// Validate CSV headers sequentially
|
|
211
|
-
//
|
|
212
|
-
for (const item of parsedFiles) {
|
|
213
|
-
const validation = await validateCsvFromFile(
|
|
214
|
-
item.file,
|
|
215
|
-
item.csvType,
|
|
216
|
-
ws,
|
|
217
|
-
argv.csvDelimiter,
|
|
218
|
-
importProcess
|
|
219
|
-
)
|
|
220
|
-
validations.push(validation)
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
const invalidFiles = validations.filter(v => v.error)
|
|
224
|
-
if (invalidFiles.length > 0) {
|
|
225
|
-
console.log('')
|
|
226
|
-
console.log(invalidFiles.map(f => `ERROR => [${chalk.red(f.inputFile)}] ${f.error}`).join('\n'))
|
|
227
|
-
process.exit(1)
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
if (interactive) {
|
|
231
|
-
console.log('')
|
|
232
|
-
const { confirmed } = await prompts(
|
|
233
|
-
[
|
|
234
|
-
{
|
|
235
|
-
type: 'confirm',
|
|
236
|
-
name: 'confirmed',
|
|
237
|
-
message: 'Continue?',
|
|
238
|
-
initial: false
|
|
239
|
-
}
|
|
240
|
-
],
|
|
241
|
-
{ onCancel: () => process.exit() }
|
|
242
|
-
)
|
|
243
|
-
|
|
244
|
-
if (!confirmed) {
|
|
245
|
-
process.exit()
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
console.log('')
|
|
250
|
-
|
|
251
|
-
//
|
|
252
|
-
// Call ImportService.beforeImportProcess (import flag)
|
|
253
|
-
//
|
|
254
|
-
if (!argv.skipTasksBeforeImport) {
|
|
255
|
-
try {
|
|
256
|
-
await callBeforeDataImportProcess(spinner, ws, importProcess)
|
|
257
|
-
} catch (e) {
|
|
258
|
-
process.exit(1)
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
//
|
|
263
|
-
// Import CSV files sequentially
|
|
264
|
-
//
|
|
265
|
-
const partitionsForCsvType = new Map()
|
|
266
|
-
|
|
267
|
-
for (const item of parsedFiles) {
|
|
268
|
-
const csvReport = await importCsvFromFile({
|
|
269
|
-
file: item.file,
|
|
270
|
-
csvType: item.csvType,
|
|
271
|
-
outputDir: dirPathTemp,
|
|
272
|
-
spinner,
|
|
273
|
-
ws,
|
|
274
|
-
delimiter: argv.csvDelimiter,
|
|
275
|
-
importProcess
|
|
276
|
-
})
|
|
277
|
-
csvReports.push(csvReport)
|
|
278
|
-
if (csvReport.countFailed > 0 || csvReport.countSkipped > 0) {
|
|
279
|
-
sendImportErrorMail(ws, importProcess, csvReport)
|
|
280
|
-
}
|
|
281
|
-
partitionsForCsvType.set(csvReport.csvType, Array.from(csvReport.partitions))
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
//
|
|
285
|
-
// Import FULL?
|
|
286
|
-
//
|
|
287
|
-
if (mode === 'full') {
|
|
288
|
-
await deleteRowsBeforeImportDate(
|
|
289
|
-
importProcess,
|
|
290
|
-
Object.fromEntries(partitionsForCsvType),
|
|
291
|
-
spinner,
|
|
292
|
-
ws
|
|
293
|
-
)
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
//
|
|
297
|
-
// Refresh Orders of type Draft, Template
|
|
298
|
-
//
|
|
299
|
-
// eslint-disable-next-line no-unused-vars
|
|
300
|
-
const refreshedOrders = await refreshOrders(spinner, ws, importProcess)
|
|
301
|
-
|
|
302
|
-
//
|
|
303
|
-
// importProcess
|
|
304
|
-
//
|
|
305
|
-
|
|
306
|
-
importProcess.importProcessEnd = new Date()
|
|
307
|
-
importProcess.time = getExecutionTime(hrstart)
|
|
308
|
-
|
|
309
|
-
const importProcessRows = []
|
|
310
|
-
|
|
311
|
-
csvReports.forEach(csvReport => {
|
|
312
|
-
importProcessRows.push({
|
|
313
|
-
type: 'import.csv',
|
|
314
|
-
payload: csvReport
|
|
315
|
-
})
|
|
316
|
-
})
|
|
317
|
-
|
|
318
|
-
importProcessRows.push({
|
|
319
|
-
type: 'refreshed.orders',
|
|
320
|
-
payload: refreshedOrders
|
|
321
|
-
})
|
|
322
|
-
|
|
323
|
-
importProcess.result = importProcessRows
|
|
324
|
-
|
|
325
|
-
await callAfterDataImportProcess(spinner, ws, importProcess)
|
|
326
|
-
|
|
327
|
-
await deleteAsync(path.resolve(dirPathTemp, '_processing'))
|
|
328
|
-
|
|
329
|
-
const reportFiles = await readImportDir(dirPathTemp)
|
|
330
|
-
|
|
331
|
-
for (const reportFile of reportFiles) {
|
|
332
|
-
const { filename, size } = reportFile
|
|
333
|
-
if ((filename.includes('skipped') || filename.includes('errors')) && size === 0) {
|
|
334
|
-
await deleteAsync(path.resolve(dirPathTemp, filename))
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
await mv(dirPathTemp, dirPathFinal)
|
|
339
|
-
|
|
340
|
-
process.exit()
|
|
341
|
-
}
|
|
@@ -1,281 +0,0 @@
|
|
|
1
|
-
/* eslint-disable no-console */
|
|
2
|
-
/* eslint-disable no-await-in-loop */
|
|
3
|
-
/* eslint-disable no-restricted-syntax */
|
|
4
|
-
import { accessSync, constants, existsSync, mkdirSync } from 'fs'
|
|
5
|
-
import path from 'path'
|
|
6
|
-
import chalk from 'chalk'
|
|
7
|
-
import prompts from 'prompts'
|
|
8
|
-
import Ora from 'ora'
|
|
9
|
-
import move from 'mv'
|
|
10
|
-
import { promisify } from 'util'
|
|
11
|
-
import { deleteAsync } from 'del'
|
|
12
|
-
|
|
13
|
-
import {
|
|
14
|
-
ALLOWED_CSV_FILES,
|
|
15
|
-
importCsvFromFile,
|
|
16
|
-
validateCsvFromFile,
|
|
17
|
-
refreshOrders,
|
|
18
|
-
download,
|
|
19
|
-
callBeforeDataImportProcess,
|
|
20
|
-
callAfterDataImportProcess,
|
|
21
|
-
getExecutionTime,
|
|
22
|
-
getArchiveFolder,
|
|
23
|
-
sendImportErrorMail,
|
|
24
|
-
deleteRowsBeforeImportDate,
|
|
25
|
-
readImportDir
|
|
26
|
-
} from '../../helpers.js'
|
|
27
|
-
|
|
28
|
-
const mv = promisify(move)
|
|
29
|
-
|
|
30
|
-
export const command = 'single [options]'
|
|
31
|
-
|
|
32
|
-
export const desc = 'Import only one CSV file'
|
|
33
|
-
|
|
34
|
-
export function builder(yargs) {
|
|
35
|
-
yargs
|
|
36
|
-
.usage(`Usage: ${chalk.cyan('$0 import:data single')} [options]`)
|
|
37
|
-
.option('fromFile', {
|
|
38
|
-
alias: 'f',
|
|
39
|
-
describe: 'File to import',
|
|
40
|
-
type: 'string'
|
|
41
|
-
})
|
|
42
|
-
.option('fromUrl', {
|
|
43
|
-
alias: 'u',
|
|
44
|
-
describe: 'Remote URL file to import',
|
|
45
|
-
type: 'string'
|
|
46
|
-
})
|
|
47
|
-
.conflicts('fromFile', 'fromUrl')
|
|
48
|
-
.check(argv => {
|
|
49
|
-
if (!argv.fromFile && !argv.fromUrl) {
|
|
50
|
-
throw new Error('Missing required argument: fromFile OR fromUrl')
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
if (argv.fromFile) {
|
|
54
|
-
accessSync(argv.fromFile, constants.F_OK)
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
return true
|
|
58
|
-
})
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
export async function handler(argv) {
|
|
62
|
-
// eslint-disable-next-line no-param-reassign
|
|
63
|
-
argv.out = argv.out || getArchiveFolder(argv.endpoint)
|
|
64
|
-
|
|
65
|
-
const spinner = new Ora()
|
|
66
|
-
const hrstart = process.hrtime()
|
|
67
|
-
|
|
68
|
-
const importProcess = {
|
|
69
|
-
importProcessStart: new Date(),
|
|
70
|
-
importProcessEnd: null,
|
|
71
|
-
time: null,
|
|
72
|
-
endpoint: argv.endpoint,
|
|
73
|
-
mode: null,
|
|
74
|
-
name: argv.name,
|
|
75
|
-
type: [],
|
|
76
|
-
result: []
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
const dirPathTemp = path.resolve(argv.out, `${importProcess.name}_temp`)
|
|
80
|
-
const dirPathFinal = path.resolve(argv.out, importProcess.name)
|
|
81
|
-
const dirPathOriginal = path.resolve(dirPathTemp, '_original')
|
|
82
|
-
|
|
83
|
-
const interactive = !argv.nonInteractive
|
|
84
|
-
|
|
85
|
-
const ws = {
|
|
86
|
-
endpoint: argv.endpoint,
|
|
87
|
-
secret: argv.secret
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
let type
|
|
91
|
-
if (interactive && !argv.type) {
|
|
92
|
-
const answers = await prompts(
|
|
93
|
-
[
|
|
94
|
-
{
|
|
95
|
-
instructions: false,
|
|
96
|
-
name: 'type',
|
|
97
|
-
type: 'select',
|
|
98
|
-
message: 'Select Type',
|
|
99
|
-
choices: Object.keys(ALLOWED_CSV_FILES).map(csvType => ({
|
|
100
|
-
title: csvType,
|
|
101
|
-
value: csvType
|
|
102
|
-
}))
|
|
103
|
-
}
|
|
104
|
-
],
|
|
105
|
-
{ onCancel: () => process.exit() }
|
|
106
|
-
)
|
|
107
|
-
|
|
108
|
-
type = answers.type
|
|
109
|
-
} else {
|
|
110
|
-
// eslint-disable-next-line prefer-destructuring
|
|
111
|
-
type = argv.type[0]
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
importProcess.type = [type]
|
|
115
|
-
|
|
116
|
-
let mode
|
|
117
|
-
if (interactive && !argv.mode) {
|
|
118
|
-
const answers = await prompts(
|
|
119
|
-
[
|
|
120
|
-
{
|
|
121
|
-
type: 'select',
|
|
122
|
-
name: 'mode',
|
|
123
|
-
message: 'Import Mode',
|
|
124
|
-
choices: [
|
|
125
|
-
{
|
|
126
|
-
title: 'Incremental',
|
|
127
|
-
value: 'incremental'
|
|
128
|
-
},
|
|
129
|
-
{
|
|
130
|
-
title: 'Full',
|
|
131
|
-
description: 'Before starting, all database records will be logically deleted',
|
|
132
|
-
value: 'full'
|
|
133
|
-
}
|
|
134
|
-
],
|
|
135
|
-
hint: ' '
|
|
136
|
-
}
|
|
137
|
-
],
|
|
138
|
-
{ onCancel: () => process.exit() }
|
|
139
|
-
)
|
|
140
|
-
|
|
141
|
-
mode = answers.mode
|
|
142
|
-
} else {
|
|
143
|
-
mode = argv.mode
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
importProcess.mode = mode
|
|
147
|
-
|
|
148
|
-
if (!existsSync(dirPathFinal) && !existsSync(dirPathOriginal)) {
|
|
149
|
-
mkdirSync(dirPathOriginal, { recursive: true })
|
|
150
|
-
} else {
|
|
151
|
-
console.log('')
|
|
152
|
-
console.log(`ERROR => directory "${dirPathFinal}" already exists, change the import name.`)
|
|
153
|
-
process.exit(1)
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
if (interactive) {
|
|
157
|
-
console.log('')
|
|
158
|
-
const { confirmed } = await prompts(
|
|
159
|
-
[
|
|
160
|
-
{
|
|
161
|
-
type: 'confirm',
|
|
162
|
-
name: 'confirmed',
|
|
163
|
-
message: 'Continue?',
|
|
164
|
-
initial: false
|
|
165
|
-
}
|
|
166
|
-
],
|
|
167
|
-
{ onCancel: () => process.exit() }
|
|
168
|
-
)
|
|
169
|
-
|
|
170
|
-
if (!confirmed) {
|
|
171
|
-
process.exit()
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
console.log('')
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
let filepath = null
|
|
178
|
-
|
|
179
|
-
if (argv.fromUrl) {
|
|
180
|
-
spinner.start('Downloading file...')
|
|
181
|
-
filepath = await download(argv.fromUrl, dirPathOriginal, `${importProcess.name}_${type}.csv`)
|
|
182
|
-
spinner.succeed('Downloaded file')
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
if (argv.fromFile) {
|
|
186
|
-
filepath = path.resolve(dirPathOriginal, `${importProcess.name}_${type}.csv`)
|
|
187
|
-
await mv(argv.fromFile, filepath)
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
const validation = await validateCsvFromFile(filepath, type, ws, argv.csvDelimiter, importProcess)
|
|
191
|
-
|
|
192
|
-
if (validation.error) {
|
|
193
|
-
console.log(`ERROR => [${chalk.red(validation.inputFile)}] ${validation.error}`)
|
|
194
|
-
process.exit(1)
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
//
|
|
198
|
-
// Call ImportService.beforeImportProcess (import flag)
|
|
199
|
-
//
|
|
200
|
-
if (!argv.skipTasksBeforeImport) {
|
|
201
|
-
try {
|
|
202
|
-
await callBeforeDataImportProcess(spinner, ws, importProcess)
|
|
203
|
-
} catch (e) {
|
|
204
|
-
process.exit(1)
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
const partitionsForCsvType = new Map()
|
|
209
|
-
|
|
210
|
-
const csvReport = await importCsvFromFile({
|
|
211
|
-
file: filepath,
|
|
212
|
-
csvType: type,
|
|
213
|
-
outputDir: dirPathTemp,
|
|
214
|
-
spinner,
|
|
215
|
-
ws,
|
|
216
|
-
delimiter: argv.csvDelimiter,
|
|
217
|
-
importProcess
|
|
218
|
-
})
|
|
219
|
-
|
|
220
|
-
if (csvReport.countFailed > 0 || csvReport.countSkipped > 0) {
|
|
221
|
-
sendImportErrorMail(ws, importProcess, csvReport)
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
partitionsForCsvType.set(csvReport.csvType, Array.from(csvReport.partitions))
|
|
225
|
-
|
|
226
|
-
//
|
|
227
|
-
// Import FULL?
|
|
228
|
-
//
|
|
229
|
-
if (mode === 'full') {
|
|
230
|
-
await deleteRowsBeforeImportDate(
|
|
231
|
-
importProcess,
|
|
232
|
-
Object.fromEntries(partitionsForCsvType),
|
|
233
|
-
spinner,
|
|
234
|
-
ws
|
|
235
|
-
)
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
//
|
|
239
|
-
// Refresh Orders of type Draft, Template
|
|
240
|
-
//
|
|
241
|
-
|
|
242
|
-
const refreshedOrders = await refreshOrders(spinner, ws, importProcess)
|
|
243
|
-
|
|
244
|
-
//
|
|
245
|
-
// importProcess
|
|
246
|
-
//
|
|
247
|
-
|
|
248
|
-
importProcess.importProcessEnd = new Date()
|
|
249
|
-
importProcess.time = getExecutionTime(hrstart)
|
|
250
|
-
|
|
251
|
-
const importProcessRows = []
|
|
252
|
-
|
|
253
|
-
importProcessRows.push({
|
|
254
|
-
type: 'import.csv',
|
|
255
|
-
payload: csvReport
|
|
256
|
-
})
|
|
257
|
-
|
|
258
|
-
importProcessRows.push({
|
|
259
|
-
type: 'refreshed.orders',
|
|
260
|
-
payload: refreshedOrders
|
|
261
|
-
})
|
|
262
|
-
|
|
263
|
-
importProcess.result = importProcessRows
|
|
264
|
-
|
|
265
|
-
await callAfterDataImportProcess(spinner, ws, importProcess)
|
|
266
|
-
|
|
267
|
-
await deleteAsync(path.resolve(dirPathTemp, '_processing'))
|
|
268
|
-
|
|
269
|
-
const reportFiles = await readImportDir(dirPathTemp)
|
|
270
|
-
|
|
271
|
-
for (const reportFile of reportFiles) {
|
|
272
|
-
const { filename, size } = reportFile
|
|
273
|
-
if ((filename.includes('skipped') || filename.includes('errors')) && size === 0) {
|
|
274
|
-
await deleteAsync(path.resolve(dirPathTemp, filename))
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
await mv(dirPathTemp, dirPathFinal)
|
|
279
|
-
|
|
280
|
-
process.exit()
|
|
281
|
-
}
|