@cyklang/cli 0.1.2 → 0.2.1
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/build/AssetCommand.d.ts +4 -0
- package/build/AssetCommand.js +293 -0
- package/build/Cmd.d.ts +2 -1
- package/build/Cmd.js +3 -3
- package/build/DBClient.d.ts +1 -0
- package/build/DBClient.js +51 -17
- package/build/ModuleCommand.js +28 -6
- package/build/TableCommand.js +235 -45
- package/build/index.js +3 -0
- package/package.json +6 -3
- package/pgdata/entry.csv +22 -0
- package/pgdata/setting.csv +4 -0
- package/src/AssetCommand.ts +307 -0
- package/src/Cmd.ts +4 -3
- package/src/DBClient.ts +70 -31
- package/src/ModuleCommand.ts +31 -5
- package/src/TableCommand.ts +269 -56
- package/src/index.ts +3 -0
- package/test/cyklang.xsd +439 -0
- package/test/t0.output +4 -0
- package/test/t0.xml +26 -0
- package/test/t01.output +32 -0
- package/test/t01.xml +185 -0
- package/test/t02.output +10 -0
- package/test/t02.xml +88 -0
- package/test/t03.output +9 -0
- package/test/t03.xml +74 -0
- package/test/t04.output +29 -0
- package/test/t04.xml +116 -0
- package/test/t05.output +18 -0
- package/test/t05.xml +41 -0
- package/test/t06.output +4 -0
- package/test/t06.xml +16 -0
- package/test/t07.output +5 -0
- package/test/t07.xml +82 -0
- package/test/t08.output +8 -0
- package/test/t08.xml +57 -0
- package/test/t09.output +10 -0
- package/test/t09.xml +29 -0
- package/test/t10.xml +125 -0
- package/test/t11.output +3 -0
- package/test/t11.xml +25 -0
- package/test/t12.output +7 -0
- package/test/t12.xml +42 -0
- package/test/t13.xml +23 -0
- package/test/t14.output +50 -0
- package/test/t14.xml +82 -0
- package/test/t14.xsd +102 -0
- package/test/t15.xml +47 -0
- package/test/t16.output +49 -0
- package/test/t16.xml +86 -0
- package/test/t17.output +5 -0
- package/test/t17.xml +21 -0
- package/test/t18.output +22 -0
- package/test/t18.xml +59 -0
- package/test/t19.xml +234 -0
- package/test/t20.xml +15 -0
- package/test/t21.output +21 -0
- package/test/t21.xml +71 -0
- package/test/t22.xml +23 -0
- package/test/t23.xml +44 -0
- package/test/t24.xml +10 -0
- package/test/test.json +113 -0
package/build/TableCommand.js
CHANGED
|
@@ -29,6 +29,8 @@ const loglevel_1 = __importDefault(require("loglevel"));
|
|
|
29
29
|
const commander_1 = require("commander");
|
|
30
30
|
const child_process_1 = require("child_process");
|
|
31
31
|
const Cmd_1 = require("./Cmd");
|
|
32
|
+
const DBClient_1 = require("./DBClient");
|
|
33
|
+
const form_data_1 = __importDefault(require("form-data"));
|
|
32
34
|
const logger = loglevel_1.default.getLogger("TableCommand.ts");
|
|
33
35
|
logger.setLevel("debug");
|
|
34
36
|
class TableCommand extends commander_1.Command {
|
|
@@ -36,6 +38,11 @@ class TableCommand extends commander_1.Command {
|
|
|
36
38
|
super(name);
|
|
37
39
|
this.description('import/export table rows').version('0.1');
|
|
38
40
|
this.addCommand(new TableExportCmd());
|
|
41
|
+
this.addCommand(new TableImportCmd());
|
|
42
|
+
this.addCommand(new TableList('list', 'list database tables'));
|
|
43
|
+
this.addCommand(new TableList('l', '(l)ist database tables'));
|
|
44
|
+
this.addCommand(new TableQuery('query', 'query select table content'));
|
|
45
|
+
this.addCommand(new TableQuery('q', 'query select table content'));
|
|
39
46
|
}
|
|
40
47
|
}
|
|
41
48
|
exports.TableCommand = TableCommand;
|
|
@@ -52,13 +59,56 @@ class TableExportCmd extends Cmd_1.Cmd {
|
|
|
52
59
|
await this.prologue(options);
|
|
53
60
|
if (this.dbManager === undefined)
|
|
54
61
|
throw 'dbManager undefined';
|
|
55
|
-
await commandImportExport(this.dbManager, 'to', tables, options)
|
|
62
|
+
// await commandImportExport(this.dbManager, 'to', tables, options)
|
|
63
|
+
try {
|
|
64
|
+
if (options.file === undefined && options.dir === undefined)
|
|
65
|
+
throw '--file or --dir mandatory';
|
|
66
|
+
if (options.file !== undefined && options.dir !== undefined)
|
|
67
|
+
throw '--file and --dir are mutually exclusive';
|
|
68
|
+
if (tables.length === 0)
|
|
69
|
+
throw 'at least one table name is mandatory';
|
|
70
|
+
if (tables.length > 1 && options.dir === undefined)
|
|
71
|
+
throw 'for multiple tables, --dir is mandatory';
|
|
72
|
+
for (let indi = 0; indi < tables.length; indi++) {
|
|
73
|
+
const tableName = tables[indi];
|
|
74
|
+
const dbTable = await this.dbManager.dbTableExist(tableName);
|
|
75
|
+
if (dbTable === undefined) {
|
|
76
|
+
logger.info('table ' + tableName + ' not found');
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
const filename = buildFilename(dbTable.name, options);
|
|
80
|
+
await this.copyTo(dbTable, filename);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
catch (err) {
|
|
84
|
+
logger.error(err);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
async copyTo(dbTable, filename) {
|
|
88
|
+
if (this.dbRemote === undefined)
|
|
89
|
+
throw 'dbRemote undefined';
|
|
90
|
+
try {
|
|
91
|
+
const writeStream = fs.createWriteStream(filename);
|
|
92
|
+
const response = await this.dbRemote.apiServer.get('/admin/export/' + dbTable.name, { responseType: 'stream' });
|
|
93
|
+
const stream = response;
|
|
94
|
+
stream.on('data', (data) => {
|
|
95
|
+
logger.debug('**** DATA ****', data.length);
|
|
96
|
+
const textDecoder = new TextDecoder();
|
|
97
|
+
const chunk = (textDecoder.decode(data));
|
|
98
|
+
writeStream.write(chunk);
|
|
99
|
+
});
|
|
100
|
+
stream.on('end', () => logger.debug('**** DONE ****'));
|
|
101
|
+
}
|
|
102
|
+
catch (err) {
|
|
103
|
+
logger.error(err);
|
|
104
|
+
}
|
|
56
105
|
}
|
|
57
106
|
}
|
|
58
107
|
class TableImportCmd extends Cmd_1.Cmd {
|
|
59
108
|
constructor() {
|
|
60
109
|
super('import');
|
|
61
110
|
this.description('import from CSV file(s)')
|
|
111
|
+
.argument('<tables...>', 'table(s) to import')
|
|
62
112
|
.option('-f --file <file>', 'name of the file to import, defaults to <table_name>.csv')
|
|
63
113
|
.option('-d --dir <directory>', 'name of the directory where to find files to import')
|
|
64
114
|
.action(async (tables, options) => this.commandImport(tables, options));
|
|
@@ -67,9 +117,72 @@ class TableImportCmd extends Cmd_1.Cmd {
|
|
|
67
117
|
await this.prologue(options);
|
|
68
118
|
if (this.dbManager === undefined)
|
|
69
119
|
throw 'dbManager undefined';
|
|
70
|
-
await commandImportExport(this.dbManager, '
|
|
120
|
+
// await commandImportExport(this.dbManager, 'to', tables, options)
|
|
121
|
+
try {
|
|
122
|
+
if (options.file === undefined && options.dir === undefined)
|
|
123
|
+
throw '--file or --dir mandatory';
|
|
124
|
+
if (options.file !== undefined && options.dir !== undefined)
|
|
125
|
+
throw '--file and --dir are mutually exclusive';
|
|
126
|
+
if (tables.length === 0)
|
|
127
|
+
throw 'at least one table name is mandatory';
|
|
128
|
+
if (tables.length > 1 && options.dir === undefined)
|
|
129
|
+
throw 'for multiple tables, --dir is mandatory';
|
|
130
|
+
for (let indi = 0; indi < tables.length; indi++) {
|
|
131
|
+
const tableName = tables[indi];
|
|
132
|
+
const dbTable = await this.dbManager.dbTableExist(tableName);
|
|
133
|
+
if (dbTable === undefined) {
|
|
134
|
+
logger.info('table ' + tableName + ' not found');
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
const filename = buildFilename(dbTable.name, options);
|
|
138
|
+
this.copyFrom(dbTable, filename);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
catch (err) {
|
|
142
|
+
logger.error(err);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
async copyFrom(dbTable, filename) {
|
|
146
|
+
if (this.dbRemote === undefined)
|
|
147
|
+
throw 'dbRemote undefined';
|
|
148
|
+
try {
|
|
149
|
+
const file = fs.createReadStream(filename);
|
|
150
|
+
const form = new form_data_1.default();
|
|
151
|
+
form.append('uploadFile', file);
|
|
152
|
+
const route = '/admin/import/' + dbTable.name;
|
|
153
|
+
const resp = await this.dbRemote.apiServer.post(route, form);
|
|
154
|
+
if (resp.status === 200) {
|
|
155
|
+
logger.debug(filename + ' uploaded');
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
catch (err) {
|
|
159
|
+
logger.error(err);
|
|
160
|
+
}
|
|
71
161
|
}
|
|
72
162
|
}
|
|
163
|
+
function buildFilename(tableName, options) {
|
|
164
|
+
let filename;
|
|
165
|
+
if (options.file !== undefined) {
|
|
166
|
+
if (fs.existsSync(options.file) && fs.lstatSync(options.file).isDirectory())
|
|
167
|
+
throw '--file ' + options.file + ' is a directory';
|
|
168
|
+
filename = options.file;
|
|
169
|
+
}
|
|
170
|
+
else if (options.dir === undefined)
|
|
171
|
+
throw '--file and --dir unspecified';
|
|
172
|
+
else if (fs.existsSync(options.dir) === false)
|
|
173
|
+
throw 'directory ' + options.dir + ' does not exist';
|
|
174
|
+
else if (fs.lstatSync(options.dir).isFile()) {
|
|
175
|
+
throw ("--dir " + options.dir + " is a file ");
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
let directory = options.dir.trim();
|
|
179
|
+
if (directory[directory.length - 1] !== '/') {
|
|
180
|
+
directory += '/';
|
|
181
|
+
}
|
|
182
|
+
filename = directory + tableName + '.csv';
|
|
183
|
+
}
|
|
184
|
+
return filename;
|
|
185
|
+
}
|
|
73
186
|
const commandImportExport = async (dbManager, direction, tables, options) => {
|
|
74
187
|
logger.debug('tables : ', tables, 'options : ', options);
|
|
75
188
|
try {
|
|
@@ -88,53 +201,130 @@ const commandImportExport = async (dbManager, direction, tables, options) => {
|
|
|
88
201
|
logger.info('table ' + tableName + ' not found');
|
|
89
202
|
continue;
|
|
90
203
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
204
|
+
psqlCmd(dbTable, direction, options);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
catch (err) {
|
|
208
|
+
logger.error(err);
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
//--------------------------------------------------------------------------------------------------------------------
|
|
212
|
+
// function psqlCmd
|
|
213
|
+
// invoke local install of psql CLI
|
|
214
|
+
//--------------------------------------------------------------------------------------------------------------------
|
|
215
|
+
function psqlCmd(dbTable, direction, options) {
|
|
216
|
+
let lcols;
|
|
217
|
+
for (let indj = 0; indj < dbTable.columns.length; indj++) {
|
|
218
|
+
const dbColumn = dbTable.columns[indj];
|
|
219
|
+
if (lcols === undefined) {
|
|
220
|
+
lcols = "(";
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
lcols += ",";
|
|
224
|
+
}
|
|
225
|
+
lcols += dbColumn.name;
|
|
226
|
+
}
|
|
227
|
+
lcols += ")";
|
|
228
|
+
let psql_cmd = "psql -c";
|
|
229
|
+
if (process.env.HEROKU_CLI !== undefined) {
|
|
230
|
+
psql_cmd = process.env.HEROKU_CLI + ' -c ';
|
|
231
|
+
}
|
|
232
|
+
let filename;
|
|
233
|
+
if (options.file !== undefined) {
|
|
234
|
+
if (fs.existsSync(options.file) && fs.lstatSync(options.file).isDirectory())
|
|
235
|
+
throw '--file ' + options.file + ' is a directory';
|
|
236
|
+
filename = options.file;
|
|
237
|
+
}
|
|
238
|
+
else if (options.dir === undefined)
|
|
239
|
+
throw '--file and --dir unspecified';
|
|
240
|
+
else if (fs.existsSync(options.dir) === false)
|
|
241
|
+
throw 'directory ' + options.dir + ' does not exist';
|
|
242
|
+
else if (fs.lstatSync(options.dir).isFile()) {
|
|
243
|
+
logger.debug("--dir " + options.dir + " is a file ");
|
|
244
|
+
}
|
|
245
|
+
else {
|
|
246
|
+
let directory = options.dir.trim();
|
|
247
|
+
if (directory[directory.length - 1] !== '/') {
|
|
248
|
+
directory += '/';
|
|
249
|
+
}
|
|
250
|
+
filename = directory + dbTable.name + '.csv';
|
|
251
|
+
}
|
|
252
|
+
let copy_cmd = "\\copy " + dbTable.name + lcols + direction + " '" + filename + "' csv header";
|
|
253
|
+
const shell_cmd = psql_cmd + '"' + copy_cmd + '"';
|
|
254
|
+
logger.debug(shell_cmd);
|
|
255
|
+
const child = (0, child_process_1.spawn)(shell_cmd.trim(), { stdio: 'inherit', shell: true });
|
|
256
|
+
}
|
|
257
|
+
//--------------------------------------------------------------------------------------------------------------------
|
|
258
|
+
// class TableList
|
|
259
|
+
//--------------------------------------------------------------------------------------------------------------------
|
|
260
|
+
class TableList extends Cmd_1.Cmd {
|
|
261
|
+
constructor(name, description) {
|
|
262
|
+
super(name);
|
|
263
|
+
this.description(description)
|
|
264
|
+
.option('-s --sort <columns>', 'sort list by column numbers (begins with 0) separated by comma')
|
|
265
|
+
.action(async (options) => {
|
|
266
|
+
await this.commandList(options);
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
async commandList(options) {
|
|
270
|
+
await this.prologue(options);
|
|
271
|
+
if (this.dbManager === undefined)
|
|
272
|
+
throw 'dbManager undefined';
|
|
273
|
+
const dbClient = new DBClient_1.DBClient(this.dbManager);
|
|
274
|
+
dbClient.selectFromTable('List of Tables', 'cyk_table', { fields: 'table_id,table_name,table_description,table_access', sort: options.sort || '1' });
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
//--------------------------------------------------------------------------------------------------------------------
|
|
278
|
+
// class TableQuery
|
|
279
|
+
//--------------------------------------------------------------------------------------------------------------------
|
|
280
|
+
class TableQuery extends Cmd_1.Cmd {
|
|
281
|
+
constructor(name, description) {
|
|
282
|
+
super(name);
|
|
283
|
+
this.description(description)
|
|
284
|
+
.argument('<table>', 'table to query')
|
|
285
|
+
.option('--where <clause_where_sql>', 'criteria in SQL syntax')
|
|
286
|
+
.option('-s --sort <columns>', 'sort by columns positions (begins by 0) separated by comma')
|
|
287
|
+
.option('-w --width <colwidth>', 'columns widths separated by comma')
|
|
288
|
+
.action(async (table, options) => {
|
|
289
|
+
this.commandQuery(table, options);
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
async commandQuery(table, options) {
|
|
293
|
+
try {
|
|
294
|
+
await this.prologue(options);
|
|
295
|
+
if (this.dbManager === undefined)
|
|
296
|
+
throw 'dbManager undefined';
|
|
297
|
+
const dbTable = await this.dbManager.dbTableExist(table);
|
|
298
|
+
if (dbTable === undefined)
|
|
299
|
+
throw 'table ' + table + ' not found';
|
|
300
|
+
let fields = '';
|
|
301
|
+
for (let ind = 0; ind < dbTable.columns.length; ind++) {
|
|
302
|
+
const dbColumn = dbTable.columns[ind];
|
|
303
|
+
let ok = false;
|
|
304
|
+
let fieldName = dbColumn.name;
|
|
305
|
+
if (dbColumn.dbType === 'text' || dbColumn.dbType === 'bytea') {
|
|
306
|
+
ok = false;
|
|
307
|
+
fieldName = 'length(' + dbColumn.name + ')';
|
|
96
308
|
}
|
|
97
309
|
else {
|
|
98
|
-
|
|
310
|
+
ok = true;
|
|
99
311
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
if (process.env.HEROKU_CLI !== undefined) {
|
|
105
|
-
psql_cmd = process.env.HEROKU_CLI + ' -c ';
|
|
106
|
-
}
|
|
107
|
-
let filename;
|
|
108
|
-
if (options.file !== undefined) {
|
|
109
|
-
if (fs.existsSync(options.file) && fs.lstatSync(options.file).isDirectory())
|
|
110
|
-
throw '--file ' + options.file + ' is a directory';
|
|
111
|
-
filename = options.file;
|
|
112
|
-
}
|
|
113
|
-
else if (options.dir === undefined)
|
|
114
|
-
throw '--file and --dir unspecified';
|
|
115
|
-
else if (fs.existsSync(options.dir) === false)
|
|
116
|
-
throw 'directory ' + options.dir + ' does not exist';
|
|
117
|
-
else if (fs.lstatSync(options.dir).isFile()) {
|
|
118
|
-
logger.debug("--dir " + options.dir + " is a file ");
|
|
119
|
-
}
|
|
120
|
-
else {
|
|
121
|
-
let directory = options.dir.trim();
|
|
122
|
-
if (directory[directory.length - 1] !== '/') {
|
|
123
|
-
directory += '/';
|
|
312
|
+
if (ok === true) {
|
|
313
|
+
if (fields !== '')
|
|
314
|
+
fields += ',';
|
|
315
|
+
fields += fieldName;
|
|
124
316
|
}
|
|
125
|
-
filename = directory + tableName + '.csv';
|
|
126
317
|
}
|
|
127
|
-
|
|
128
|
-
const
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
318
|
+
logger.debug('commandQuery', table);
|
|
319
|
+
const dbClient = new DBClient_1.DBClient(this.dbManager);
|
|
320
|
+
let title = 'Table ' + table;
|
|
321
|
+
if (options.where !== undefined) {
|
|
322
|
+
title += ' where ' + options.where;
|
|
323
|
+
}
|
|
324
|
+
dbClient.selectFromTable(title, table, { fields: fields, width: options.width, sort: options.sort || '1', where: options.where });
|
|
325
|
+
}
|
|
326
|
+
catch (err) {
|
|
327
|
+
logger.error(err);
|
|
135
328
|
}
|
|
136
329
|
}
|
|
137
|
-
|
|
138
|
-
logger.error(err);
|
|
139
|
-
}
|
|
140
|
-
};
|
|
330
|
+
}
|
package/build/index.js
CHANGED
|
@@ -13,12 +13,15 @@ const TableCommand_1 = require("./TableCommand");
|
|
|
13
13
|
const TestCommand_1 = require("./TestCommand");
|
|
14
14
|
const RunCommand_1 = require("./RunCommand");
|
|
15
15
|
const InitCommand_1 = require("./InitCommand");
|
|
16
|
+
const AssetCommand_1 = require("./AssetCommand");
|
|
16
17
|
const logger = loglevel_1.default.getLogger("index.ts");
|
|
17
18
|
logger.setLevel("debug");
|
|
18
19
|
const program = new commander_1.Command();
|
|
19
20
|
program.name('cyk').description('cyklang CLI')
|
|
20
21
|
.version('0.2');
|
|
21
22
|
program.addCommand(new InitCommand_1.InitCommand('init'));
|
|
23
|
+
program.addCommand(new AssetCommand_1.AssetCommand('asset', 'manage assets'));
|
|
24
|
+
program.addCommand(new AssetCommand_1.AssetCommand('a', 'manage assets'));
|
|
22
25
|
program.addCommand(new ModuleCommand_1.ModuleCommand('module'));
|
|
23
26
|
program.addCommand(new ModuleCommand_1.ModuleCommand('m'));
|
|
24
27
|
program.addCommand(new UserCommand_1.UserCommand('user'));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cyklang/cli",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "cyklang CLI",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -11,20 +11,23 @@
|
|
|
11
11
|
"npm:upgrade": "npx npm-check-updates -iu",
|
|
12
12
|
"refresh": "rm -rf ./node_modules ./package-lock.json && npm install",
|
|
13
13
|
"dev": "nodemon -e ts --ignore build --exec \"npm run global\" ",
|
|
14
|
-
"test": "
|
|
14
|
+
"test": "cyk test test/t*.xml"
|
|
15
15
|
},
|
|
16
16
|
"keywords": [],
|
|
17
17
|
"author": "",
|
|
18
18
|
"license": "ISC",
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@cyklang/core": "^0.3.
|
|
20
|
+
"@cyklang/core": "^0.3.6",
|
|
21
21
|
"commander": "^9.4.0",
|
|
22
22
|
"dotenv": "^16.0.1",
|
|
23
|
+
"form-data": "^4.0.0",
|
|
23
24
|
"loglevel": "^1.8.0",
|
|
25
|
+
"mime-types": "^2.1.35",
|
|
24
26
|
"pako": "^2.0.4",
|
|
25
27
|
"xml": "^1.0.1"
|
|
26
28
|
},
|
|
27
29
|
"devDependencies": {
|
|
30
|
+
"@types/mime-types": "^2.1.1",
|
|
28
31
|
"@types/pako": "^2.0.0",
|
|
29
32
|
"@types/sax": "^1.2.4",
|
|
30
33
|
"@types/xml": "^1.0.8",
|
package/pgdata/entry.csv
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
entry_id,entry_year,entry_date,entry_jnl,entry_doc,entry_acct,entry_debit,entry_credit,entry_aux,entry_ord,entry_letter,entry_letter_date
|
|
2
|
+
43,2021,2021-01-03,1,16,60221,75.00,,,1,,
|
|
3
|
+
44,2021,2021-01-03,1,16,44566,0.00,,,2,,
|
|
4
|
+
45,2021,2021-01-03,1,16,4011,,75.00,5,3,,
|
|
5
|
+
15,2021,2021-01-01,2,6,4011,1100.00,,12,1,,
|
|
6
|
+
16,2021,2021-01-01,2,6,44566,,100.00,,2,,
|
|
7
|
+
17,2021,2021-01-01,2,6,701,,1000.00,,3,,
|
|
8
|
+
21,2021,2021-01-01,3,10,4011,100.00,,11,1,,
|
|
9
|
+
2,2021,2021-01-01,1,2,44566,10.00,,,2,,
|
|
10
|
+
1,2021,2021-01-01,1,2,601,50.00,,,1,,
|
|
11
|
+
3,2021,2021-01-01,1,2,4011,,60.00,3,3,,
|
|
12
|
+
22,2021,2021-01-01,3,10,512,,100.00,,2,,
|
|
13
|
+
23,2021,2021-01-01,,11,431,500.00,,,1,,
|
|
14
|
+
12,2021,2021-01-02,1,5,6061,50.00,,,1,,
|
|
15
|
+
13,2021,2021-01-02,1,5,44566,0.00,,,2,,
|
|
16
|
+
14,2021,2021-01-02,1,5,4011,,50.00,5,3,,
|
|
17
|
+
40,2021,2021-01-01,,11,512,,500.00,,2,,
|
|
18
|
+
46,2021,2021-01-01,3,17,4011,100.00,,11,1,,
|
|
19
|
+
47,2021,2021-01-01,3,17,512,,100.00,,2,,
|
|
20
|
+
9,2021,2021-01-01,1,4,6061,100.00,,,1,,
|
|
21
|
+
10,2021,2021-01-01,1,4,44566,20.00,,,2,,
|
|
22
|
+
11,2021,2021-01-01,1,4,4011,,120.00,11,3,,
|