closer-cli 2.7.0 → 2.11.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/CHANGELOG.md +35 -0
- package/cmds/importData_cmds/multiple.js +4 -3
- package/cmds/importData_cmds/single.js +4 -1
- package/helpers.js +54 -19
- package/package.json +1 -1
- package/cmds/importStock.js +0 -213
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,41 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# [2.11.0](https://code.hfarm.dev/closer/closer/compare/v2.10.0...v2.11.0) (2022-05-18)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* **#PJX-445:** Multilingua ([f24f066](https://code.hfarm.dev/closer/closer/commits/f24f0668b7c0c8338c8d91db68afc871efb534ed)), closes [#PJX-445](https://code.hfarm.dev/closer/closer/issues/PJX-445)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# [2.9.0](https://code.hfarm.dev/closer/closer/compare/v2.8.0...v2.9.0) (2022-05-09)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
### Features
|
|
21
|
+
|
|
22
|
+
* **#PJX-442:** Import ad hoc disponibilità incrementale non bloccante ([aad991b](https://code.hfarm.dev/closer/closer/commits/aad991ba97e76977c6a6a2d73ef614026324b0d3)), closes [#PJX-442](https://code.hfarm.dev/closer/closer/issues/PJX-442)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
# [2.8.0](https://code.hfarm.dev/closer/closer/compare/v2.7.1...v2.8.0) (2022-04-27)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
### Features
|
|
32
|
+
|
|
33
|
+
* **#PJX-433:** [Import FTP] Cambiare il valore di default del separatore csv ([ef27bf1](https://code.hfarm.dev/closer/closer/commits/ef27bf17847f17b94ba5ec82846a9c94f521be22)), closes [#PJX-433](https://code.hfarm.dev/closer/closer/issues/PJX-433)
|
|
34
|
+
* **#PJX-437:** [Import] Archiviare anche il file csv sorgente ([9a729c5](https://code.hfarm.dev/closer/closer/commits/9a729c54982537e3bb6eca4bffc1f23c6bcc8aaf)), closes [#PJX-437](https://code.hfarm.dev/closer/closer/issues/PJX-437)
|
|
35
|
+
* **#PJX-439:** Anagrafiche con zero righe ([571ec16](https://code.hfarm.dev/closer/closer/commits/571ec169766cd784e6b7e905fa801f238da31fb6)), closes [#PJX-439](https://code.hfarm.dev/closer/closer/issues/PJX-439)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
|
|
6
41
|
# [2.6.0](https://code.hfarm.dev/closer/closer/compare/v2.5.1...v2.6.0) (2022-04-19)
|
|
7
42
|
|
|
8
43
|
|
|
@@ -19,7 +19,8 @@ const {
|
|
|
19
19
|
callBeforeDataImportProcess,
|
|
20
20
|
callAfterDataImportProcess,
|
|
21
21
|
getExecutionTime,
|
|
22
|
-
getArchiveFolder
|
|
22
|
+
getArchiveFolder,
|
|
23
|
+
renameWithTimestamp
|
|
23
24
|
} = require('../../helpers')
|
|
24
25
|
|
|
25
26
|
exports.command = 'multiple [options]'
|
|
@@ -274,9 +275,9 @@ exports.handler = async argv => {
|
|
|
274
275
|
|
|
275
276
|
report.result = reportRows
|
|
276
277
|
|
|
277
|
-
// const message = getDataImportMessageReport(report)
|
|
278
|
-
|
|
279
278
|
await callAfterDataImportProcess(spinner, ws, report)
|
|
280
279
|
|
|
280
|
+
await renameWithTimestamp(argv.out)
|
|
281
|
+
|
|
281
282
|
process.exit()
|
|
282
283
|
}
|
|
@@ -14,7 +14,8 @@ const {
|
|
|
14
14
|
ALLOWED_CSV_FILES,
|
|
15
15
|
download,
|
|
16
16
|
validateCsvFromFile,
|
|
17
|
-
getArchiveFolder
|
|
17
|
+
getArchiveFolder,
|
|
18
|
+
renameWithTimestamp
|
|
18
19
|
} = require('../../helpers')
|
|
19
20
|
|
|
20
21
|
exports.command = 'single [options]'
|
|
@@ -213,5 +214,7 @@ exports.handler = async argv => {
|
|
|
213
214
|
|
|
214
215
|
await callAfterDataImportProcess(spinner, ws, report)
|
|
215
216
|
|
|
217
|
+
await renameWithTimestamp(argv.out)
|
|
218
|
+
|
|
216
219
|
process.exit()
|
|
217
220
|
}
|
package/helpers.js
CHANGED
|
@@ -23,6 +23,9 @@ exports.createSocketConnection = (endpoint, adminSecret) => {
|
|
|
23
23
|
|
|
24
24
|
exports.ALLOWED_CSV_FILES = {
|
|
25
25
|
product: 'products.csv',
|
|
26
|
+
localizedProduct: 'localizedProducts.csv',
|
|
27
|
+
localizedFilter: 'localizedFilters.csv',
|
|
28
|
+
localizedVariant: 'localizedVariants.csv',
|
|
26
29
|
price: 'prices.csv',
|
|
27
30
|
group: 'groups.csv',
|
|
28
31
|
lookup: 'lookups.csv',
|
|
@@ -36,13 +39,15 @@ exports.ALLOWED_CSV_FILES = {
|
|
|
36
39
|
userCustomer: 'userCustomers.csv'
|
|
37
40
|
}
|
|
38
41
|
|
|
39
|
-
|
|
42
|
+
const getCsvFilesFromDir = dir =>
|
|
40
43
|
fs.readdirSync(dir).filter(file => path.extname(file).toLowerCase() === '.csv')
|
|
41
44
|
|
|
45
|
+
exports.getCsvFilesFromDir = getCsvFilesFromDir
|
|
46
|
+
|
|
42
47
|
exports.getGoogleSheetCsvUrl = (docId, sheet) =>
|
|
43
48
|
`https://docs.google.com/spreadsheets/d/${docId}/gviz/tq?tqx=out:csv&sheet=${sheet}`
|
|
44
49
|
|
|
45
|
-
exports.importCsvFromFile = (file, csvType, outputDir, spinner, ws, delimiter = '
|
|
50
|
+
exports.importCsvFromFile = (file, csvType, outputDir, spinner, ws, delimiter = ';') =>
|
|
46
51
|
new Promise(resolve => {
|
|
47
52
|
const socket = this.createSocketConnection(ws.endpoint, ws.adminSecret)
|
|
48
53
|
|
|
@@ -54,6 +59,9 @@ exports.importCsvFromFile = (file, csvType, outputDir, spinner, ws, delimiter =
|
|
|
54
59
|
fs.mkdirSync(outputDir, { recursive: true })
|
|
55
60
|
}
|
|
56
61
|
|
|
62
|
+
const filename = path.basename(file)
|
|
63
|
+
fs.copyFileSync(file, path.resolve(outputDir, filename))
|
|
64
|
+
|
|
57
65
|
const errorCsvFile = path.resolve(outputDir, `${csvType}_errors.csv`)
|
|
58
66
|
const errorFileStream = fs.createWriteStream(errorCsvFile)
|
|
59
67
|
|
|
@@ -66,8 +74,6 @@ exports.importCsvFromFile = (file, csvType, outputDir, spinner, ws, delimiter =
|
|
|
66
74
|
let countFailed = 0
|
|
67
75
|
let countSkipped = 0
|
|
68
76
|
|
|
69
|
-
const filename = path.basename(file)
|
|
70
|
-
|
|
71
77
|
spinner.start('Loading...')
|
|
72
78
|
|
|
73
79
|
const importRowSuccess = () => {
|
|
@@ -247,20 +253,29 @@ exports.validateCsvFromFile = (file, csvType, ws, delimiter = ';') =>
|
|
|
247
253
|
}
|
|
248
254
|
|
|
249
255
|
if (lineNumber === 1) {
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
256
|
+
if (line === '') {
|
|
257
|
+
resolve({
|
|
258
|
+
csvType,
|
|
259
|
+
executionTime: this.getExecutionTime(hrstart),
|
|
260
|
+
inputFile: filename
|
|
261
|
+
})
|
|
262
|
+
} else {
|
|
263
|
+
const rows = parse(`${header}\n${line}`, {
|
|
264
|
+
columns: true,
|
|
265
|
+
skip_empty_lines: true,
|
|
266
|
+
skipLinesWithEmptyValues: true,
|
|
267
|
+
delimiter
|
|
268
|
+
})
|
|
269
|
+
|
|
270
|
+
const packet = {
|
|
271
|
+
csvColumns: Object.keys(rows[0]),
|
|
272
|
+
csvType,
|
|
273
|
+
type: 'validateCsvHeaderRequest'
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
socket.send(JSON.stringify(packet))
|
|
261
277
|
}
|
|
262
278
|
|
|
263
|
-
socket.send(JSON.stringify(packet))
|
|
264
279
|
readStream.destroy()
|
|
265
280
|
}
|
|
266
281
|
|
|
@@ -420,7 +435,6 @@ exports.refreshOrders = (spinner, ws) =>
|
|
|
420
435
|
const { type, payload } = JSON.parse(packet)
|
|
421
436
|
switch (type) {
|
|
422
437
|
case 'refreshDraftOrdersResponse': {
|
|
423
|
-
console.log(JSON.stringify({ type, payload }))
|
|
424
438
|
spinner.text = this.printRefreshedOrders({
|
|
425
439
|
...payload,
|
|
426
440
|
executionTime: this.getExecutionTime(hrstart)
|
|
@@ -710,11 +724,32 @@ exports.flushMedia = (spinner, ws) =>
|
|
|
710
724
|
})
|
|
711
725
|
|
|
712
726
|
exports.getArchiveFolder = instanceEndpoint => {
|
|
713
|
-
const date = new Date()
|
|
714
727
|
const prefix = 'closer'
|
|
715
728
|
const instance = slugify(instanceEndpoint.split('/')[0], { lower: true })
|
|
729
|
+
const ts = getTimestampForFilename()
|
|
730
|
+
return `${prefix}_${instance}/${ts}`
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
exports.renameWithTimestamp = dirPath => {
|
|
734
|
+
const ts = getTimestampForFilename()
|
|
735
|
+
|
|
736
|
+
const files = getCsvFilesFromDir(dirPath).map(filename => {
|
|
737
|
+
const oldPath = path.resolve(dirPath, filename)
|
|
738
|
+
const [name, ext] = oldPath.split('.')
|
|
739
|
+
const newPath = `${name}_${ts}.${ext}`
|
|
740
|
+
return {
|
|
741
|
+
oldPath,
|
|
742
|
+
newPath
|
|
743
|
+
}
|
|
744
|
+
})
|
|
745
|
+
|
|
746
|
+
files.forEach(file => fs.rename(file.oldPath, file.newPath, () => {}))
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
const getTimestampForFilename = () => {
|
|
750
|
+
const date = new Date()
|
|
716
751
|
const [isoDateString, isoTimeString] = date.toISOString().split('T')
|
|
717
752
|
const dateString = isoDateString.split('-').join('')
|
|
718
753
|
const timeString = isoTimeString.split(':').join('').split('.')[0]
|
|
719
|
-
return `${
|
|
754
|
+
return `${dateString}_${timeString}`.split(':').join('')
|
|
720
755
|
}
|
package/package.json
CHANGED
package/cmds/importStock.js
DELETED
|
@@ -1,213 +0,0 @@
|
|
|
1
|
-
/* eslint-disable no-await-in-loop */
|
|
2
|
-
/* eslint-disable no-restricted-syntax */
|
|
3
|
-
/* eslint-disable no-console */
|
|
4
|
-
const fs = require('fs')
|
|
5
|
-
const chalk = require('chalk')
|
|
6
|
-
const path = require('path')
|
|
7
|
-
|
|
8
|
-
const Ora = require('ora')
|
|
9
|
-
const prompts = require('prompts')
|
|
10
|
-
const {
|
|
11
|
-
importCsvFromFile,
|
|
12
|
-
getExecutionTime,
|
|
13
|
-
callAfterDataImportProcess,
|
|
14
|
-
ALLOWED_CSV_FILES,
|
|
15
|
-
download,
|
|
16
|
-
validateCsvFromFile,
|
|
17
|
-
getArchiveFolder,
|
|
18
|
-
getGoogleSheetCsvUrl
|
|
19
|
-
} = require('../helpers')
|
|
20
|
-
|
|
21
|
-
exports.command = 'import:stock'
|
|
22
|
-
|
|
23
|
-
exports.desc = 'Import Stock Availability from CSV file'
|
|
24
|
-
|
|
25
|
-
exports.builder = yargs => {
|
|
26
|
-
yargs
|
|
27
|
-
.usage(`Usage: ${chalk.cyan('$0 import:stock')} [options]`)
|
|
28
|
-
.option('fromFile', {
|
|
29
|
-
alias: 'f',
|
|
30
|
-
describe: 'File to import',
|
|
31
|
-
type: 'string'
|
|
32
|
-
})
|
|
33
|
-
.option('fromUrl', {
|
|
34
|
-
alias: 'u',
|
|
35
|
-
describe: 'Remote URL file to import',
|
|
36
|
-
type: 'string'
|
|
37
|
-
})
|
|
38
|
-
.option('fromDir', {
|
|
39
|
-
alias: 'd',
|
|
40
|
-
describe: 'Directory path that contains file to import',
|
|
41
|
-
type: 'string'
|
|
42
|
-
})
|
|
43
|
-
.option('fromGoogleDocId', {
|
|
44
|
-
alias: 'g',
|
|
45
|
-
describe: 'Google Doc ID that contains sheet to import',
|
|
46
|
-
type: 'string'
|
|
47
|
-
})
|
|
48
|
-
// .conflicts('fromFile', 'fromUrl', 'fromDir', 'fromGoogleDocId')
|
|
49
|
-
.check(argv => {
|
|
50
|
-
if (!argv.fromFile && !argv.fromUrl && !argv.fromDir && !argv.fromGoogleDocId) {
|
|
51
|
-
throw new Error(
|
|
52
|
-
'Missing required argument: fromFile OR fromUrl OR fromDir OR fromGoogleDocId'
|
|
53
|
-
)
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
if (argv.fromFile) {
|
|
57
|
-
fs.accessSync(argv.fromFile, fs.constants.F_OK)
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
if (argv.fromDir) {
|
|
61
|
-
fs.accessSync(argv.fromDir, fs.constants.F_OK)
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
return true
|
|
65
|
-
})
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
exports.handler = async argv => {
|
|
69
|
-
// eslint-disable-next-line no-param-reassign
|
|
70
|
-
argv.out = argv.out || getArchiveFolder(argv.endpoint)
|
|
71
|
-
|
|
72
|
-
const spinner = new Ora()
|
|
73
|
-
const hrstart = process.hrtime()
|
|
74
|
-
|
|
75
|
-
const report = {
|
|
76
|
-
start: new Date(),
|
|
77
|
-
end: null,
|
|
78
|
-
time: null,
|
|
79
|
-
endpoint: argv.endpoint,
|
|
80
|
-
mode: null,
|
|
81
|
-
type: [],
|
|
82
|
-
result: []
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const ws = {
|
|
86
|
-
endpoint: argv.endpoint,
|
|
87
|
-
adminSecret: argv['admin-secret']
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
const interactive = !argv.nonInteractive
|
|
91
|
-
|
|
92
|
-
const csvType = 'stockAvailability'
|
|
93
|
-
|
|
94
|
-
let file
|
|
95
|
-
if (argv.fromDir) {
|
|
96
|
-
file = {
|
|
97
|
-
file: path.resolve(argv.fromDir, ALLOWED_CSV_FILES.stockAvailability),
|
|
98
|
-
csvType
|
|
99
|
-
}
|
|
100
|
-
} else if (argv.fromGoogleDocId) {
|
|
101
|
-
file = {
|
|
102
|
-
url: getGoogleSheetCsvUrl(argv.fromGoogleDocId, csvType),
|
|
103
|
-
csvType
|
|
104
|
-
}
|
|
105
|
-
} else if (argv.fromFile) {
|
|
106
|
-
file = {
|
|
107
|
-
file: argv.fromFile,
|
|
108
|
-
csvType
|
|
109
|
-
}
|
|
110
|
-
} else if (argv.fromUrl) {
|
|
111
|
-
file = {
|
|
112
|
-
url: argv.fromUrl,
|
|
113
|
-
csvType
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
let mode
|
|
118
|
-
if (interactive && !argv.mode) {
|
|
119
|
-
const answers = await prompts(
|
|
120
|
-
[
|
|
121
|
-
{
|
|
122
|
-
type: 'select',
|
|
123
|
-
name: 'mode',
|
|
124
|
-
message: 'Import Mode',
|
|
125
|
-
choices: [
|
|
126
|
-
{
|
|
127
|
-
title: 'Incremental',
|
|
128
|
-
value: 'incremental'
|
|
129
|
-
},
|
|
130
|
-
{
|
|
131
|
-
title: 'Full',
|
|
132
|
-
description: 'Before starting, all database records will be logically deleted',
|
|
133
|
-
value: 'full'
|
|
134
|
-
}
|
|
135
|
-
],
|
|
136
|
-
hint: ' '
|
|
137
|
-
}
|
|
138
|
-
],
|
|
139
|
-
{ onCancel: () => process.exit() }
|
|
140
|
-
)
|
|
141
|
-
|
|
142
|
-
mode = answers.mode
|
|
143
|
-
} else {
|
|
144
|
-
mode = argv.mode
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
if (interactive) {
|
|
148
|
-
console.log('')
|
|
149
|
-
const { confirmed } = await prompts(
|
|
150
|
-
[
|
|
151
|
-
{
|
|
152
|
-
type: 'confirm',
|
|
153
|
-
name: 'confirmed',
|
|
154
|
-
message: 'Continue?',
|
|
155
|
-
initial: false
|
|
156
|
-
}
|
|
157
|
-
],
|
|
158
|
-
{ onCancel: () => process.exit() }
|
|
159
|
-
)
|
|
160
|
-
|
|
161
|
-
if (!confirmed) {
|
|
162
|
-
process.exit()
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
console.log('')
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
let filepath = argv.fromFile
|
|
169
|
-
|
|
170
|
-
if (argv.fromUrl || argv.fromGoogleDocId) {
|
|
171
|
-
spinner.start('Downloading file...')
|
|
172
|
-
filepath = await download(file.url, argv.out, `${csvType}.csv`)
|
|
173
|
-
spinner.succeed('Downloaded file')
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
const validation = await validateCsvFromFile(filepath, csvType, ws, argv.csvDelimiter)
|
|
177
|
-
|
|
178
|
-
if (validation.error) {
|
|
179
|
-
console.log(`ERROR => [${chalk.red(validation.inputFile)}] ${validation.error}`)
|
|
180
|
-
process.exit()
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
const csvReport = await importCsvFromFile(
|
|
184
|
-
filepath,
|
|
185
|
-
csvType,
|
|
186
|
-
argv.out,
|
|
187
|
-
spinner,
|
|
188
|
-
ws,
|
|
189
|
-
argv.csvDelimiter
|
|
190
|
-
)
|
|
191
|
-
|
|
192
|
-
//
|
|
193
|
-
// Report
|
|
194
|
-
//
|
|
195
|
-
|
|
196
|
-
report.end = new Date()
|
|
197
|
-
report.time = getExecutionTime(hrstart)
|
|
198
|
-
report.mode = mode
|
|
199
|
-
report.type = [csvType]
|
|
200
|
-
|
|
201
|
-
const reportRows = []
|
|
202
|
-
|
|
203
|
-
reportRows.push({
|
|
204
|
-
type: 'import.csv',
|
|
205
|
-
payload: csvReport
|
|
206
|
-
})
|
|
207
|
-
|
|
208
|
-
report.result = reportRows
|
|
209
|
-
|
|
210
|
-
await callAfterDataImportProcess(spinner, ws, report)
|
|
211
|
-
|
|
212
|
-
process.exit()
|
|
213
|
-
}
|