closer-cli 0.0.3 → 0.3.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/cmds/importData.js +42 -0
- package/cmds/importData_cmds/multiple.js +277 -0
- package/cmds/importData_cmds/single.js +213 -0
- package/cmds/importMedia.js +63 -0
- package/csv/customers.csv +6 -0
- package/csv/fieldConfigurations.csv +33 -0
- package/csv/groups.csv +3 -0
- package/csv/labels.csv +49 -0
- package/csv/lookups.csv +11 -0
- package/csv/prices.csv +319 -0
- package/csv/products.csv +319 -0
- package/csv/simple_customers.csv +6 -0
- package/csv/simple_userCustomer.csv +36 -0
- package/csv/simple_users.csv +8 -0
- package/csv/users.csv +8 -0
- package/helpers.js +706 -0
- package/index.js +10 -132
- package/package.json +7 -2
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
const { ALLOWED_CSV_FILES } = require('../helpers')
|
|
2
|
+
|
|
3
|
+
exports.command = 'import:data <command>'
|
|
4
|
+
exports.desc = 'Import CSV data to Closer'
|
|
5
|
+
|
|
6
|
+
exports.builder = yargs => {
|
|
7
|
+
yargs
|
|
8
|
+
.commandDir('importData_cmds')
|
|
9
|
+
.option('type', {
|
|
10
|
+
alias: 't',
|
|
11
|
+
describe: 'CSV type to consider during import',
|
|
12
|
+
choices: Object.keys(ALLOWED_CSV_FILES),
|
|
13
|
+
array: true
|
|
14
|
+
})
|
|
15
|
+
.option('mode', {
|
|
16
|
+
alias: 'm',
|
|
17
|
+
describe: 'Import mode, if "full" all database records will be logically deleted',
|
|
18
|
+
choices: ['full', 'incremental']
|
|
19
|
+
})
|
|
20
|
+
.option('non-interactive', {
|
|
21
|
+
describe: '',
|
|
22
|
+
type: 'bool'
|
|
23
|
+
})
|
|
24
|
+
.option('out', {
|
|
25
|
+
alias: 'o',
|
|
26
|
+
describe: 'Directory path that will contain errored CSV files',
|
|
27
|
+
type: 'string',
|
|
28
|
+
default: '.out'
|
|
29
|
+
})
|
|
30
|
+
.option('skipTasksBeforeImport', {
|
|
31
|
+
describe: 'Skip tasks before start import process',
|
|
32
|
+
type: 'bool'
|
|
33
|
+
})
|
|
34
|
+
.option('csvDelimiter', {
|
|
35
|
+
describe: 'CSV Delimiter',
|
|
36
|
+
type: 'string',
|
|
37
|
+
default: ','
|
|
38
|
+
})
|
|
39
|
+
.implies('non-interactive', ['type', 'mode'])
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
exports.handler = () => {}
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
/* eslint-disable no-await-in-loop */
|
|
3
|
+
/* eslint-disable no-restricted-syntax */
|
|
4
|
+
const fs = require('fs')
|
|
5
|
+
const path = require('path')
|
|
6
|
+
const chalk = require('chalk')
|
|
7
|
+
const prompts = require('prompts')
|
|
8
|
+
const Ora = require('ora')
|
|
9
|
+
const {
|
|
10
|
+
getCsvFilesFromDir,
|
|
11
|
+
ALLOWED_CSV_FILES,
|
|
12
|
+
getGoogleSheetCsvUrl,
|
|
13
|
+
importCsvFromFile,
|
|
14
|
+
validateCsvFromFile,
|
|
15
|
+
refreshOrders,
|
|
16
|
+
truncateTablesByCsvTypes,
|
|
17
|
+
download,
|
|
18
|
+
callBeforeDataImportProcess,
|
|
19
|
+
callAfterDataImportProcess,
|
|
20
|
+
getExecutionTime
|
|
21
|
+
} = require('../../helpers')
|
|
22
|
+
|
|
23
|
+
exports.command = 'multiple [options]'
|
|
24
|
+
|
|
25
|
+
exports.desc = 'Import different CSV files'
|
|
26
|
+
|
|
27
|
+
exports.builder = yargs => {
|
|
28
|
+
yargs
|
|
29
|
+
.usage(`Usage: ${chalk.cyan('$0 import multiple')} [options]`)
|
|
30
|
+
.option('fromDir', {
|
|
31
|
+
alias: 'd',
|
|
32
|
+
describe: 'Directory path that contains files to import',
|
|
33
|
+
type: 'string'
|
|
34
|
+
})
|
|
35
|
+
.option('fromGoogleDocId', {
|
|
36
|
+
alias: 'g',
|
|
37
|
+
describe: 'Google Doc ID that contains sheets to import',
|
|
38
|
+
type: 'string'
|
|
39
|
+
})
|
|
40
|
+
.conflicts('fromDir', 'fromGoogleDocId')
|
|
41
|
+
.check(argv => {
|
|
42
|
+
if (!argv.fromDir && !argv.fromGoogleDocId) {
|
|
43
|
+
throw new Error('Missing required argument: fromDir OR fromGoogleDocId')
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (argv.fromDir) {
|
|
47
|
+
fs.accessSync(argv.fromDir, fs.constants.F_OK)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return true
|
|
51
|
+
})
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
exports.handler = async argv => {
|
|
55
|
+
const hrstart = process.hrtime()
|
|
56
|
+
const report = {
|
|
57
|
+
start: new Date(),
|
|
58
|
+
end: null,
|
|
59
|
+
time: null,
|
|
60
|
+
endpoint: argv.endpoint,
|
|
61
|
+
mode: null,
|
|
62
|
+
type: [],
|
|
63
|
+
result: []
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const interactive = !argv.nonInteractive
|
|
67
|
+
|
|
68
|
+
let csvChoices = []
|
|
69
|
+
|
|
70
|
+
if (argv.fromDir) {
|
|
71
|
+
const csvFilesFromDir = getCsvFilesFromDir(argv.fromDir)
|
|
72
|
+
|
|
73
|
+
csvChoices = Object.keys(ALLOWED_CSV_FILES).map(csvType => ({
|
|
74
|
+
title: ALLOWED_CSV_FILES[csvType],
|
|
75
|
+
csvType,
|
|
76
|
+
value: {
|
|
77
|
+
file: path.resolve(argv.fromDir, ALLOWED_CSV_FILES[csvType]),
|
|
78
|
+
csvType
|
|
79
|
+
},
|
|
80
|
+
disabled: !csvFilesFromDir.includes(ALLOWED_CSV_FILES[csvType])
|
|
81
|
+
}))
|
|
82
|
+
} else {
|
|
83
|
+
csvChoices = Object.keys(ALLOWED_CSV_FILES).map(csvType => ({
|
|
84
|
+
title: csvType,
|
|
85
|
+
csvType,
|
|
86
|
+
value: {
|
|
87
|
+
url: getGoogleSheetCsvUrl(argv.fromGoogleDocId, csvType),
|
|
88
|
+
csvType
|
|
89
|
+
}
|
|
90
|
+
}))
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
let files
|
|
94
|
+
if (interactive && !argv.type) {
|
|
95
|
+
const answers = await prompts(
|
|
96
|
+
[
|
|
97
|
+
{
|
|
98
|
+
instructions: false,
|
|
99
|
+
name: 'files',
|
|
100
|
+
type: 'multiselect',
|
|
101
|
+
message: argv.fromDir ? 'Select Files' : 'Select Sheets',
|
|
102
|
+
warn: argv.fromDir && 'File not found',
|
|
103
|
+
choices: csvChoices,
|
|
104
|
+
min: 1
|
|
105
|
+
}
|
|
106
|
+
],
|
|
107
|
+
{ onCancel: () => process.exit() }
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
files = answers.files
|
|
111
|
+
} else {
|
|
112
|
+
files = argv.type.map(type => {
|
|
113
|
+
const choice = csvChoices.find(csvChoice => csvChoice.csvType === type)
|
|
114
|
+
return choice.value
|
|
115
|
+
})
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
let mode
|
|
119
|
+
if (interactive && !argv.mode) {
|
|
120
|
+
const answers = await prompts(
|
|
121
|
+
[
|
|
122
|
+
{
|
|
123
|
+
type: 'select',
|
|
124
|
+
name: 'mode',
|
|
125
|
+
message: 'Import Mode',
|
|
126
|
+
choices: [
|
|
127
|
+
{
|
|
128
|
+
title: 'Incremental',
|
|
129
|
+
value: 'incremental'
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
title: 'Full',
|
|
133
|
+
description: 'Before starting, all database records will be logically deleted',
|
|
134
|
+
value: 'full'
|
|
135
|
+
}
|
|
136
|
+
],
|
|
137
|
+
hint: ' '
|
|
138
|
+
}
|
|
139
|
+
],
|
|
140
|
+
{ onCancel: () => process.exit() }
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
mode = answers.mode
|
|
144
|
+
} else {
|
|
145
|
+
mode = argv.mode
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const spinner = new Ora()
|
|
149
|
+
|
|
150
|
+
const validations = []
|
|
151
|
+
const csvReports = []
|
|
152
|
+
|
|
153
|
+
const ws = {
|
|
154
|
+
endpoint: argv.endpoint,
|
|
155
|
+
adminSecret: argv['admin-secret']
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
let parsedFiles = [...files]
|
|
159
|
+
|
|
160
|
+
if (argv.fromGoogleDocId) {
|
|
161
|
+
parsedFiles = []
|
|
162
|
+
console.log('')
|
|
163
|
+
spinner.start('Downloading Google sheets...')
|
|
164
|
+
for (const item of files) {
|
|
165
|
+
const filepath = await download(item.url, argv.out, `${item.csvType}.csv`)
|
|
166
|
+
parsedFiles.push({ file: filepath, csvType: item.csvType })
|
|
167
|
+
}
|
|
168
|
+
spinner.succeed('Google sheets downloaded')
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
//
|
|
172
|
+
// Validate CSV headers sequentially
|
|
173
|
+
//
|
|
174
|
+
for (const item of parsedFiles) {
|
|
175
|
+
const validation = await validateCsvFromFile(item.file, item.csvType, ws, argv.csvDelimiter)
|
|
176
|
+
validations.push(validation)
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const invalidFiles = validations.filter(v => v.error)
|
|
180
|
+
if (invalidFiles.length > 0) {
|
|
181
|
+
console.log('')
|
|
182
|
+
console.log(invalidFiles.map(f => `ERROR => [${chalk.red(f.inputFile)}] ${f.error}`).join('\n'))
|
|
183
|
+
process.exit()
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if (interactive) {
|
|
187
|
+
console.log('')
|
|
188
|
+
const { confirmed } = await prompts(
|
|
189
|
+
[
|
|
190
|
+
{
|
|
191
|
+
type: 'confirm',
|
|
192
|
+
name: 'confirmed',
|
|
193
|
+
message: 'Continue?',
|
|
194
|
+
initial: false
|
|
195
|
+
}
|
|
196
|
+
],
|
|
197
|
+
{ onCancel: () => process.exit() }
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
if (!confirmed) {
|
|
201
|
+
process.exit()
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
console.log('')
|
|
206
|
+
|
|
207
|
+
//
|
|
208
|
+
// Call ImportService.beforeImportProcess (import flag)
|
|
209
|
+
//
|
|
210
|
+
if (!argv.skipTasksBeforeImport) {
|
|
211
|
+
try {
|
|
212
|
+
await callBeforeDataImportProcess(spinner, ws)
|
|
213
|
+
} catch (e) {
|
|
214
|
+
process.exit()
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
//
|
|
219
|
+
// Import FULL?
|
|
220
|
+
//
|
|
221
|
+
if (mode === 'full') {
|
|
222
|
+
const csvTypes = parsedFiles.map(i => i.csvType)
|
|
223
|
+
await truncateTablesByCsvTypes(csvTypes, spinner, ws)
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
//
|
|
227
|
+
// Import CSV files sequentially
|
|
228
|
+
//
|
|
229
|
+
for (const item of parsedFiles) {
|
|
230
|
+
const csvReport = await importCsvFromFile(
|
|
231
|
+
item.file,
|
|
232
|
+
item.csvType,
|
|
233
|
+
argv.out,
|
|
234
|
+
spinner,
|
|
235
|
+
ws,
|
|
236
|
+
argv.csvDelimiter
|
|
237
|
+
)
|
|
238
|
+
csvReports.push(csvReport)
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
//
|
|
242
|
+
// Refresh Orders of type Draft
|
|
243
|
+
//
|
|
244
|
+
// eslint-disable-next-line no-unused-vars
|
|
245
|
+
const refreshedOrders = await refreshOrders(spinner, ws)
|
|
246
|
+
|
|
247
|
+
//
|
|
248
|
+
// Report
|
|
249
|
+
//
|
|
250
|
+
|
|
251
|
+
report.end = new Date()
|
|
252
|
+
report.time = getExecutionTime(hrstart)
|
|
253
|
+
report.mode = mode
|
|
254
|
+
report.type = files.map(f => f.csvType)
|
|
255
|
+
|
|
256
|
+
const reportRows = []
|
|
257
|
+
|
|
258
|
+
csvReports.forEach(csvReport => {
|
|
259
|
+
reportRows.push({
|
|
260
|
+
type: 'import.csv',
|
|
261
|
+
payload: csvReport
|
|
262
|
+
})
|
|
263
|
+
})
|
|
264
|
+
|
|
265
|
+
reportRows.push({
|
|
266
|
+
type: 'refreshed.orders',
|
|
267
|
+
payload: refreshedOrders
|
|
268
|
+
})
|
|
269
|
+
|
|
270
|
+
report.result = reportRows
|
|
271
|
+
|
|
272
|
+
// const message = getDataImportMessageReport(report)
|
|
273
|
+
|
|
274
|
+
await callAfterDataImportProcess(spinner, ws, report)
|
|
275
|
+
|
|
276
|
+
process.exit()
|
|
277
|
+
}
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
/* eslint-disable no-restricted-syntax */
|
|
2
|
+
/* eslint-disable no-console */
|
|
3
|
+
const fs = require('fs')
|
|
4
|
+
const chalk = require('chalk')
|
|
5
|
+
|
|
6
|
+
const Ora = require('ora')
|
|
7
|
+
const prompts = require('prompts')
|
|
8
|
+
const {
|
|
9
|
+
importCsvFromFile,
|
|
10
|
+
getExecutionTime,
|
|
11
|
+
refreshOrders,
|
|
12
|
+
callAfterDataImportProcess,
|
|
13
|
+
callBeforeDataImportProcess,
|
|
14
|
+
ALLOWED_CSV_FILES,
|
|
15
|
+
download,
|
|
16
|
+
validateCsvFromFile
|
|
17
|
+
} = require('../../helpers')
|
|
18
|
+
|
|
19
|
+
exports.command = 'single [options]'
|
|
20
|
+
|
|
21
|
+
exports.desc = 'Import only one CSV file'
|
|
22
|
+
|
|
23
|
+
exports.builder = yargs => {
|
|
24
|
+
yargs
|
|
25
|
+
.usage(`Usage: ${chalk.cyan('$0 import single')} [options]`)
|
|
26
|
+
.option('fromFile', {
|
|
27
|
+
alias: 'f',
|
|
28
|
+
describe: 'File to import',
|
|
29
|
+
type: 'string'
|
|
30
|
+
})
|
|
31
|
+
.option('fromUrl', {
|
|
32
|
+
alias: 'u',
|
|
33
|
+
describe: 'Remote URL file to import',
|
|
34
|
+
type: 'string'
|
|
35
|
+
})
|
|
36
|
+
.conflicts('fromFile', 'fromUrl')
|
|
37
|
+
.check(argv => {
|
|
38
|
+
if (!argv.fromFile && !argv.fromUrl) {
|
|
39
|
+
throw new Error('Missing required argument: fromFile OR fromUrl')
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (argv.fromFile) {
|
|
43
|
+
fs.accessSync(argv.fromFile, fs.constants.F_OK)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return true
|
|
47
|
+
})
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
exports.handler = async argv => {
|
|
51
|
+
const spinner = new Ora()
|
|
52
|
+
const hrstart = process.hrtime()
|
|
53
|
+
|
|
54
|
+
const report = {
|
|
55
|
+
start: new Date(),
|
|
56
|
+
end: null,
|
|
57
|
+
time: null,
|
|
58
|
+
endpoint: argv.endpoint,
|
|
59
|
+
mode: null,
|
|
60
|
+
type: [],
|
|
61
|
+
result: []
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const ws = {
|
|
65
|
+
endpoint: argv.endpoint,
|
|
66
|
+
adminSecret: argv['admin-secret']
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const interactive = !argv.nonInteractive
|
|
70
|
+
|
|
71
|
+
let type
|
|
72
|
+
if (interactive && !argv.type) {
|
|
73
|
+
const answers = await prompts(
|
|
74
|
+
[
|
|
75
|
+
{
|
|
76
|
+
instructions: false,
|
|
77
|
+
name: 'type',
|
|
78
|
+
type: 'select',
|
|
79
|
+
message: 'Select Type',
|
|
80
|
+
choices: Object.keys(ALLOWED_CSV_FILES).map(csvType => ({
|
|
81
|
+
title: csvType,
|
|
82
|
+
value: csvType
|
|
83
|
+
}))
|
|
84
|
+
}
|
|
85
|
+
],
|
|
86
|
+
{ onCancel: () => process.exit() }
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
type = answers.type
|
|
90
|
+
} else {
|
|
91
|
+
// eslint-disable-next-line prefer-destructuring
|
|
92
|
+
type = argv.type[0]
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
let mode
|
|
96
|
+
if (interactive && !argv.mode) {
|
|
97
|
+
const answers = await prompts(
|
|
98
|
+
[
|
|
99
|
+
{
|
|
100
|
+
type: 'select',
|
|
101
|
+
name: 'mode',
|
|
102
|
+
message: 'Import Mode',
|
|
103
|
+
choices: [
|
|
104
|
+
{
|
|
105
|
+
title: 'Incremental',
|
|
106
|
+
value: 'incremental'
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
title: 'Full',
|
|
110
|
+
description: 'Before starting, all database records will be logically deleted',
|
|
111
|
+
value: 'full'
|
|
112
|
+
}
|
|
113
|
+
],
|
|
114
|
+
hint: ' '
|
|
115
|
+
}
|
|
116
|
+
],
|
|
117
|
+
{ onCancel: () => process.exit() }
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
mode = answers.mode
|
|
121
|
+
} else {
|
|
122
|
+
mode = argv.mode
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (interactive) {
|
|
126
|
+
console.log('')
|
|
127
|
+
const { confirmed } = await prompts(
|
|
128
|
+
[
|
|
129
|
+
{
|
|
130
|
+
type: 'confirm',
|
|
131
|
+
name: 'confirmed',
|
|
132
|
+
message: 'Continue?',
|
|
133
|
+
initial: false
|
|
134
|
+
}
|
|
135
|
+
],
|
|
136
|
+
{ onCancel: () => process.exit() }
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
if (!confirmed) {
|
|
140
|
+
process.exit()
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
console.log('')
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
let csvReport
|
|
147
|
+
|
|
148
|
+
let filepath = argv.fromFile
|
|
149
|
+
|
|
150
|
+
if (argv.fromUrl) {
|
|
151
|
+
spinner.start('Downloading file...')
|
|
152
|
+
filepath = await download(argv.fromUrl, argv.out, `${type}.csv`)
|
|
153
|
+
spinner.succeed('Downloaded file')
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const validation = await validateCsvFromFile(filepath, type, ws, argv.csvDelimiter)
|
|
157
|
+
|
|
158
|
+
if (validation.error) {
|
|
159
|
+
console.log(`ERROR => [${chalk.red(validation.inputFile)}] ${validation.error}`)
|
|
160
|
+
process.exit()
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
//
|
|
164
|
+
// Call ImportService.beforeImportProcess (import flag)
|
|
165
|
+
//
|
|
166
|
+
if (!argv.skipTasksBeforeImport) {
|
|
167
|
+
try {
|
|
168
|
+
await callBeforeDataImportProcess(spinner, ws)
|
|
169
|
+
} catch (e) {
|
|
170
|
+
process.exit()
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if (argv.fromFile) {
|
|
175
|
+
csvReport = await importCsvFromFile(
|
|
176
|
+
argv.fromFile,
|
|
177
|
+
type,
|
|
178
|
+
argv.out,
|
|
179
|
+
spinner,
|
|
180
|
+
ws,
|
|
181
|
+
argv.csvDelimiter
|
|
182
|
+
)
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const refreshedOrders = await refreshOrders(spinner, ws)
|
|
186
|
+
|
|
187
|
+
//
|
|
188
|
+
// Report
|
|
189
|
+
//
|
|
190
|
+
|
|
191
|
+
report.end = new Date()
|
|
192
|
+
report.time = getExecutionTime(hrstart)
|
|
193
|
+
report.mode = mode
|
|
194
|
+
report.type = [type]
|
|
195
|
+
|
|
196
|
+
const reportRows = []
|
|
197
|
+
|
|
198
|
+
reportRows.push({
|
|
199
|
+
type: 'import.csv',
|
|
200
|
+
payload: csvReport
|
|
201
|
+
})
|
|
202
|
+
|
|
203
|
+
reportRows.push({
|
|
204
|
+
type: 'refreshed.orders',
|
|
205
|
+
payload: refreshedOrders
|
|
206
|
+
})
|
|
207
|
+
|
|
208
|
+
report.result = reportRows
|
|
209
|
+
|
|
210
|
+
await callAfterDataImportProcess(spinner, ws, report)
|
|
211
|
+
|
|
212
|
+
process.exit()
|
|
213
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
const chalk = require('chalk')
|
|
2
|
+
const Ora = require('ora')
|
|
3
|
+
const {
|
|
4
|
+
importMedia,
|
|
5
|
+
flushMedia,
|
|
6
|
+
getExecutionTime,
|
|
7
|
+
callAfterMediaImportProcess
|
|
8
|
+
} = require('../helpers')
|
|
9
|
+
|
|
10
|
+
exports.command = 'import:media'
|
|
11
|
+
exports.desc = 'Import media (images, 360, videos) to Closer'
|
|
12
|
+
|
|
13
|
+
exports.builder = yargs => {
|
|
14
|
+
yargs
|
|
15
|
+
.usage(`Usage: ${chalk.cyan('$0 import:media')} [options]`)
|
|
16
|
+
|
|
17
|
+
.option('flush', {
|
|
18
|
+
describe: 'Delete all before the import process (DB records and files from disk).',
|
|
19
|
+
type: 'bool'
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
.option('reprocess', {
|
|
23
|
+
describe: 'Reprocess media that were already processed by previous import.',
|
|
24
|
+
type: 'bool'
|
|
25
|
+
})
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
exports.handler = async argv => {
|
|
29
|
+
const spinner = new Ora()
|
|
30
|
+
const hrstart = process.hrtime()
|
|
31
|
+
|
|
32
|
+
const report = {
|
|
33
|
+
start: new Date(),
|
|
34
|
+
end: null,
|
|
35
|
+
time: null,
|
|
36
|
+
endpoint: argv.endpoint,
|
|
37
|
+
flush: argv.flush,
|
|
38
|
+
reprocess: argv.reprocess,
|
|
39
|
+
result: null
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const ws = {
|
|
43
|
+
endpoint: argv.endpoint,
|
|
44
|
+
adminSecret: argv['admin-secret']
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (argv.flush) {
|
|
48
|
+
await flushMedia(spinner, ws)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const result = await importMedia(argv.reprocess, spinner, ws)
|
|
52
|
+
|
|
53
|
+
//
|
|
54
|
+
// Report
|
|
55
|
+
//
|
|
56
|
+
report.end = new Date()
|
|
57
|
+
report.time = getExecutionTime(hrstart)
|
|
58
|
+
report.result = result
|
|
59
|
+
|
|
60
|
+
await callAfterMediaImportProcess(spinner, ws, report)
|
|
61
|
+
|
|
62
|
+
process.exit()
|
|
63
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
CustomerCode,CustomerName,PricebookCode,CustomerEmail,AddressStreet,AddressCity,AddressState,AddressZip,AddressCountry,GroupCodes,Markup
|
|
2
|
+
CUST01,Customer 01,SPB,cust01@example.com,Via Garibaldi,Vicenza,VI,36100,Italia,AI|WA,1.2
|
|
3
|
+
CUST02,Customer 02,SPB,cust02@example.com,Via De Gasperi,Roma,RM,00165,Italia,AI|WA,1.3
|
|
4
|
+
CUST03,Customer 03,SPB,cust03@example.com,Prato della Valle,Padova,PD,35100,Italia,AI|WA,1.0
|
|
5
|
+
CUST04,Customer 04,SPB,cust04@example.com,Via Etnea,Catania,CT,95121,Italia,AI,1.0
|
|
6
|
+
CUST05,Customer 05,SPB,cust05@example.com,Via Manzoni,Milano,MI,20121,Italia,WA,1.2
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
Entity,Key,Field,Value
|
|
2
|
+
Order,label,inputField1,Partita IVA
|
|
3
|
+
Order,schema,inputField1,"{""type"": ""string"", ""minLength"": 11, ""maxLength"": 12}"
|
|
4
|
+
Order,enabled,inputField1,true
|
|
5
|
+
Order,required,inputField1,true
|
|
6
|
+
Order,component,inputField1,text
|
|
7
|
+
Order,position,inputField1,5
|
|
8
|
+
Order,label,inputField2,Shipping Notes
|
|
9
|
+
Order,component,inputField2,text
|
|
10
|
+
Order,enabled,inputField2,true
|
|
11
|
+
Order,position,inputField2,2
|
|
12
|
+
Order,schema,inputField2,"{""type"": ""string""}"
|
|
13
|
+
Order,required,inputField2,false
|
|
14
|
+
Order,label,inputField3,Payment days
|
|
15
|
+
Order,component,inputField3,number
|
|
16
|
+
Order,enabled,inputField3,true
|
|
17
|
+
Order,position,inputField3,3
|
|
18
|
+
Order,required,inputField3,true
|
|
19
|
+
Order,schema,inputField3,"{""type"": ""integer"", ""minimum"": 0, ""maximum"": 120}"
|
|
20
|
+
Order,label,inputField4,Payment Method
|
|
21
|
+
Order,component,inputField4,dropdown
|
|
22
|
+
Order,required,inputField4,true
|
|
23
|
+
Order,enabled,inputField4,true
|
|
24
|
+
Order,schema,inputField4,"{""type"": ""string""}"
|
|
25
|
+
Order,dataSource,inputField4,"[{""value"":""BT"", ""label"":""Bank Transfer""},{""value"":""CC"", ""label"":""Credit Card""},{""value"":""PP"", ""label"":""PayPal""}]"
|
|
26
|
+
Order,position,inputField4,1
|
|
27
|
+
Order,component,customerLookup1,dropdown
|
|
28
|
+
Order,required,customerLookup1,true
|
|
29
|
+
Order,enabled,customerLookup1,true
|
|
30
|
+
Order,schema,customerLookup1,"{""type"": ""string""}"
|
|
31
|
+
Order,position,customerLookup1,4
|
|
32
|
+
Order,label,customerLookup1,Courier
|
|
33
|
+
Order,dataSource,customerLookup1,lookup
|
package/csv/groups.csv
ADDED
package/csv/labels.csv
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
Locale,Key,Value
|
|
2
|
+
en,filter1,Product Type
|
|
3
|
+
en,filter2,Product Group
|
|
4
|
+
en,filter3,Color Group
|
|
5
|
+
en,filter4,Delivery
|
|
6
|
+
en,filter5,Made In
|
|
7
|
+
en,filter6,Fit
|
|
8
|
+
en,filter7,Line
|
|
9
|
+
en,filter8,Price Class
|
|
10
|
+
it,filter1,Tipologia Prodotto
|
|
11
|
+
it,filter2,Gruppo Prodotto
|
|
12
|
+
it,filter3,Gruppo Colore
|
|
13
|
+
it,filter4,Consegna
|
|
14
|
+
it,filter5,Made In
|
|
15
|
+
it,filter6,Vestibilità
|
|
16
|
+
it,filter7,Linea
|
|
17
|
+
it,filter8,Fascia di Prezzo
|
|
18
|
+
it,label1,Composizione
|
|
19
|
+
en,label1,Composition
|
|
20
|
+
en,label2,Notes
|
|
21
|
+
it,label2,Note
|
|
22
|
+
it,label3,Barcode
|
|
23
|
+
en,label3,Barcode
|
|
24
|
+
it,label4,Note Espositore
|
|
25
|
+
en,label4,Merchandiser Notes
|
|
26
|
+
en,label5,Cancelled Notes
|
|
27
|
+
it,label5,Note di Cancellazione
|
|
28
|
+
it,macrofilter1,Stagione
|
|
29
|
+
en,macrofilter1,Season
|
|
30
|
+
it,variant1,Tessuto
|
|
31
|
+
en,variant1,Fabric
|
|
32
|
+
it,variant2,Colore
|
|
33
|
+
en,variant2,Color
|
|
34
|
+
en,request-forgot-password_notification-title,Forgot your password?
|
|
35
|
+
it,request-forgot-password_notification-title,Hai dimenticato la password?
|
|
36
|
+
en,request-forgot-password_notification-message,"To create a new password, just copy the following code to the app: ${forgotPasswordToken}"
|
|
37
|
+
it,request-forgot-password_notification-message,"Per creare una nuova password, copia il seguente codice nell'app: ${forgotPasswordToken}"
|
|
38
|
+
en,forgot-password_notification-title,Your password has been updated
|
|
39
|
+
it,forgot-password_notification-title,La tua password è stata aggiornata
|
|
40
|
+
en,forgot-password_notification-message,Welcome back ${user.name}! Your Closer account password has been updated.
|
|
41
|
+
it,forgot-password_notification-message,Bentornato ${user.name}! La password del tuo account Closer è stata aggiornata.
|
|
42
|
+
en,change-order-owner-source-user_notification-title,Order shared
|
|
43
|
+
it,change-order-owner-source-user_notification-title,Ordine condiviso
|
|
44
|
+
en,change-order-owner-source-user_notification-message,You shared the order ${orderId} with ${targetUser.name}.
|
|
45
|
+
it,change-order-owner-source-user_notification-message,Hai condiviso l'ordine ${orderId} con ${targetUser.name}.
|
|
46
|
+
en,change-order-owner-target-user_notification-title,You have received an order
|
|
47
|
+
it,change-order-owner-target-user_notification-title,Hai ricevuto un ordine
|
|
48
|
+
en,change-order-owner-target-user_notification-message,${targetUser.name} sent you an order ${orderId}.
|
|
49
|
+
it,change-order-owner-target-user_notification-message,${targetUser.name} ti ha inviato un ordine ${orderId}.
|
package/csv/lookups.csv
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
CustomerCode,Field,Code,Description,Entity,Position
|
|
2
|
+
CUST01,customerLookup1,BT,BRT Bartolini,Order,1
|
|
3
|
+
CUST01,customerLookup1,CC,UPS,Order,2
|
|
4
|
+
CUST02,customerLookup1,BC,SDA Poste Italiane,Order,1
|
|
5
|
+
CUST02,customerLookup1,CC,UPS,Order,2
|
|
6
|
+
CUST03,customerLookup1,CC,UPS,Order,1
|
|
7
|
+
CUST03,customerLookup1,PP,DHL,Order,2
|
|
8
|
+
CUST04,customerLookup1,BT,BRT Bartolini,Order,1
|
|
9
|
+
CUST04,customerLookup1,PP,DHL,Order,2
|
|
10
|
+
CUST05,customerLookup1,CC,UPS,Order,1
|
|
11
|
+
CUST05,customerLookup1,BC,SDA Poste Italiane,Order,2
|