gemcap-be-common 1.4.152 → 1.4.154
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/models/FinancialSpreading.model.d.ts +0 -1
- package/models/FinancialSpreading.model.js +0 -1
- package/models/FinancialSpreading.model.ts +0 -2
- package/models/_index.d.ts +6 -6
- package/package.json +1 -1
- package/services/financial-spreading.service.js +54 -16
- package/services/financial-spreading.service.ts +80 -19
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -24,7 +24,6 @@ exports.financialSpreadingViewValidationSchema = joi_1.default.object({
|
|
|
24
24
|
year: joi_1.default.number().integer().min(1900).max(9999),
|
|
25
25
|
sheetId: joi_1.default.string().required(),
|
|
26
26
|
amount: joi_1.default.number().required().allow(0),
|
|
27
|
-
isFixedCost: joi_1.default.boolean().allow(null),
|
|
28
27
|
minus_1: joi_1.default.number(),
|
|
29
28
|
minus_2: joi_1.default.number(),
|
|
30
29
|
minus_3: joi_1.default.number(),
|
|
@@ -21,7 +21,6 @@ export interface IFinancialSpreadingView {
|
|
|
21
21
|
month: number;
|
|
22
22
|
sheetId: string;
|
|
23
23
|
amount: number;
|
|
24
|
-
isFixedCost?: boolean;
|
|
25
24
|
minus_1?: number;
|
|
26
25
|
minus_2?: number;
|
|
27
26
|
minus_3?: number;
|
|
@@ -81,7 +80,6 @@ export const financialSpreadingViewValidationSchema = Joi.object<IFinancialSprea
|
|
|
81
80
|
year: Joi.number().integer().min(1900).max(9999),
|
|
82
81
|
sheetId: Joi.string().required(),
|
|
83
82
|
amount: Joi.number().required().allow(0),
|
|
84
|
-
isFixedCost: Joi.boolean().allow(null),
|
|
85
83
|
minus_1: Joi.number(),
|
|
86
84
|
minus_2: Joi.number(),
|
|
87
85
|
minus_3: Joi.number(),
|
package/models/_index.d.ts
CHANGED
|
@@ -31,10 +31,10 @@ export declare const allSchemas: {
|
|
|
31
31
|
createdAt: NativeDate;
|
|
32
32
|
updatedAt: NativeDate;
|
|
33
33
|
} & {
|
|
34
|
-
|
|
34
|
+
amount: number;
|
|
35
35
|
bbcSheetId: import("mongoose").Types.ObjectId;
|
|
36
|
+
order: number;
|
|
36
37
|
apDate: Date;
|
|
37
|
-
amount: number;
|
|
38
38
|
__v?: number;
|
|
39
39
|
poNumber?: string;
|
|
40
40
|
customerName?: string;
|
|
@@ -45,10 +45,10 @@ export declare const allSchemas: {
|
|
|
45
45
|
createdAt: NativeDate;
|
|
46
46
|
updatedAt: NativeDate;
|
|
47
47
|
} & {
|
|
48
|
-
|
|
48
|
+
amount: number;
|
|
49
49
|
bbcSheetId: import("mongoose").Types.ObjectId;
|
|
50
|
+
order: number;
|
|
50
51
|
apDate: Date;
|
|
51
|
-
amount: number;
|
|
52
52
|
__v?: number;
|
|
53
53
|
poNumber?: string;
|
|
54
54
|
customerName?: string;
|
|
@@ -59,10 +59,10 @@ export declare const allSchemas: {
|
|
|
59
59
|
createdAt: NativeDate;
|
|
60
60
|
updatedAt: NativeDate;
|
|
61
61
|
} & {
|
|
62
|
-
|
|
62
|
+
amount: number;
|
|
63
63
|
bbcSheetId: import("mongoose").Types.ObjectId;
|
|
64
|
+
order: number;
|
|
64
65
|
apDate: Date;
|
|
65
|
-
amount: number;
|
|
66
66
|
__v?: number;
|
|
67
67
|
poNumber?: string;
|
|
68
68
|
customerName?: string;
|
package/package.json
CHANGED
|
@@ -196,11 +196,10 @@ class FinancialSpreadingService {
|
|
|
196
196
|
return { success: false, data, sheets, message: 'Invalid data' };
|
|
197
197
|
}
|
|
198
198
|
await Promise.all(editableData.map(async (item) => {
|
|
199
|
-
const { _id,
|
|
199
|
+
const { _id, ...rest } = item;
|
|
200
200
|
const update = {
|
|
201
201
|
amount: rest.amount,
|
|
202
202
|
};
|
|
203
|
-
console.debug({ _id, update });
|
|
204
203
|
if (_id.includes('new_')) {
|
|
205
204
|
if (rest.sheetId.includes('new_')) {
|
|
206
205
|
rest.sheetId = sheetMap[rest.sheetId];
|
|
@@ -403,23 +402,62 @@ class FinancialSpreadingService {
|
|
|
403
402
|
v: header,
|
|
404
403
|
s: { font: { bold: true } },
|
|
405
404
|
}));
|
|
405
|
+
const buildAggregatedRow = (title, rows) => {
|
|
406
|
+
const oldData = range.map((r) => rows.reduce((sum, row) => new decimal_js_1.default(sum).add(row[`minus_${r}`] ?? 0).toNumber(), 0));
|
|
407
|
+
const current = rows.reduce((sum, row) => new decimal_js_1.default(sum).add(row.amount).toNumber(), 0);
|
|
408
|
+
return [
|
|
409
|
+
{ v: '', s: { font: { bold: true } } },
|
|
410
|
+
{ v: title, s: { font: { italic: true } } },
|
|
411
|
+
...oldData.map((v) => ({ v, t: 'n' })),
|
|
412
|
+
{ v: current, t: 'n' },
|
|
413
|
+
];
|
|
414
|
+
};
|
|
406
415
|
await Promise.all([FinancialSpreadingSheet_model_1.EFinancialSpreadingType.PROFIT_LOSS, FinancialSpreadingSheet_model_1.EFinancialSpreadingType.BALANCE_SHEET].map(async (financialSpreadingType) => {
|
|
407
416
|
const financialSpreadingData = await this.getFinancialSpreadingData({ ...params, financialSpreadingType }, monthDeep);
|
|
408
417
|
const sheetsView = financialSpreadingData.sheets;
|
|
409
|
-
const
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
const
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
418
|
+
const data = financialSpreadingData.data;
|
|
419
|
+
const sheetById = lodash_1.default.keyBy(sheetsView, '_id');
|
|
420
|
+
const dataByRowType = lodash_1.default.groupBy(data, (row) => {
|
|
421
|
+
const sheet = sheetById[row.sheetId];
|
|
422
|
+
return sheet?.rowType;
|
|
423
|
+
});
|
|
424
|
+
const rows = [];
|
|
425
|
+
for (const [rowType, rowsData] of Object.entries(dataByRowType)) {
|
|
426
|
+
// ===== OPERATING EXPENSES (special case)
|
|
427
|
+
if (rowType === FinancialSpreadingSheet_model_1.EFinanceSpreadingPLTotal.OPERATING_EXPENSES) {
|
|
428
|
+
const fixed = rowsData.filter(r => sheetById[r.sheetId]?.isFixedCost);
|
|
429
|
+
const variable = rowsData.filter(r => !sheetById[r.sheetId]?.isFixedCost);
|
|
430
|
+
if (fixed.length) {
|
|
431
|
+
rows.push(buildAggregatedRow('Fixed operating expenses', fixed));
|
|
432
|
+
}
|
|
433
|
+
if (variable.length) {
|
|
434
|
+
rows.push(buildAggregatedRow('Variable operating expenses', variable));
|
|
435
|
+
}
|
|
436
|
+
continue;
|
|
437
|
+
}
|
|
438
|
+
// ===== DEFAULT ROW RENDERING
|
|
439
|
+
rowsData.forEach((rowData) => {
|
|
440
|
+
const sheet = sheetById[rowData.sheetId];
|
|
441
|
+
if (!sheet)
|
|
442
|
+
return;
|
|
443
|
+
const oldData = range.map(r => rowData[`minus_${r}`]);
|
|
444
|
+
const baseRow = [
|
|
445
|
+
{ v: sheet.isTotal ? sheet.name : '', s: { font: { bold: true } } },
|
|
446
|
+
{ v: sheet.isTotal ? '' : sheet.name, s: { font: { italic: true } } },
|
|
447
|
+
...oldData.map(v => ({ v, t: 'n' })),
|
|
448
|
+
{ v: rowData.amount, t: 'n' },
|
|
449
|
+
];
|
|
450
|
+
const style = sheet.isTotal ? rowStyles[sheet.rowType] ?? {} : {};
|
|
451
|
+
rows.push(baseRow.map(cell => ({
|
|
452
|
+
...cell,
|
|
453
|
+
s: lodash_1.default.merge(cell.s, style),
|
|
454
|
+
})));
|
|
455
|
+
});
|
|
456
|
+
}
|
|
457
|
+
fullData[financialSpreadingType] = [
|
|
458
|
+
fullHeaders,
|
|
459
|
+
...rows,
|
|
460
|
+
];
|
|
423
461
|
}));
|
|
424
462
|
return await this.uploadsService.convertDataToFileWithStyleOld({
|
|
425
463
|
'PROFIT LOSS': fullData[FinancialSpreadingSheet_model_1.EFinancialSpreadingType.PROFIT_LOSS],
|
|
@@ -213,7 +213,7 @@ export class FinancialSpreadingService {
|
|
|
213
213
|
order: sheet.order,
|
|
214
214
|
suborder: sheet.suborder,
|
|
215
215
|
rowType: sheet.rowType as EFinanceSpreadingPLTotal | EFinanceSpreadingBSTotal,
|
|
216
|
-
}
|
|
216
|
+
};
|
|
217
217
|
if (sheet.isFixedCost) {
|
|
218
218
|
update.isFixedCost = sheet.isFixedCost;
|
|
219
219
|
}
|
|
@@ -230,14 +230,12 @@ export class FinancialSpreadingService {
|
|
|
230
230
|
return { success: false, data, sheets, message: 'Invalid data' };
|
|
231
231
|
}
|
|
232
232
|
await Promise.all(editableData.map(async (item) => {
|
|
233
|
-
const { _id,
|
|
233
|
+
const { _id, ...rest } = item;
|
|
234
234
|
|
|
235
235
|
const update: Partial<IFinancialSpreading> = {
|
|
236
236
|
amount: rest.amount,
|
|
237
237
|
};
|
|
238
238
|
|
|
239
|
-
console.debug({ _id, update });
|
|
240
|
-
|
|
241
239
|
if (_id.includes('new_')) {
|
|
242
240
|
if (rest.sheetId.includes('new_')) {
|
|
243
241
|
rest.sheetId = sheetMap[rest.sheetId];
|
|
@@ -464,27 +462,90 @@ export class FinancialSpreadingService {
|
|
|
464
462
|
s: { font: { bold: true } },
|
|
465
463
|
}));
|
|
466
464
|
|
|
465
|
+
const buildAggregatedRow = (
|
|
466
|
+
title: string,
|
|
467
|
+
rows: IFinancialSpreadingViewWithDeepData[],
|
|
468
|
+
): IExcelDataCellWithStyles[] => {
|
|
469
|
+
const oldData = range.map((r) =>
|
|
470
|
+
rows.reduce((sum, row) => new Decimal(sum).add(row[`minus_${r}`] as number ?? 0).toNumber(), 0),
|
|
471
|
+
);
|
|
472
|
+
|
|
473
|
+
const current = rows.reduce((sum, row) => new Decimal(sum).add(row.amount).toNumber(), 0);
|
|
474
|
+
|
|
475
|
+
return [
|
|
476
|
+
{ v: '', s: { font: { bold: true } } },
|
|
477
|
+
{ v: title, s: { font: { italic: true } } },
|
|
478
|
+
...oldData.map((v) => ({ v, t: 'n' })),
|
|
479
|
+
{ v: current, t: 'n' },
|
|
480
|
+
];
|
|
481
|
+
};
|
|
482
|
+
|
|
467
483
|
await Promise.all([EFinancialSpreadingType.PROFIT_LOSS, EFinancialSpreadingType.BALANCE_SHEET].map(async (financialSpreadingType) => {
|
|
468
484
|
const financialSpreadingData = await this.getFinancialSpreadingData(
|
|
469
485
|
{ ...params, financialSpreadingType },
|
|
470
486
|
monthDeep,
|
|
471
487
|
);
|
|
472
488
|
|
|
473
|
-
const sheetsView = financialSpreadingData.sheets as
|
|
474
|
-
const
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
489
|
+
const sheetsView = financialSpreadingData.sheets as IFinancialSpreadingSheetView[];
|
|
490
|
+
const data = financialSpreadingData.data as unknown as IFinancialSpreadingViewWithDeepData[];
|
|
491
|
+
|
|
492
|
+
const sheetById = _.keyBy(sheetsView, '_id');
|
|
493
|
+
|
|
494
|
+
const dataByRowType = _.groupBy(data, (row) => {
|
|
495
|
+
const sheet = sheetById[row.sheetId];
|
|
496
|
+
return sheet?.rowType;
|
|
497
|
+
});
|
|
498
|
+
|
|
499
|
+
const rows: IExcelDataCellWithStyles[][] = [];
|
|
500
|
+
|
|
501
|
+
for (const [rowType, rowsData] of Object.entries(dataByRowType)) {
|
|
502
|
+
|
|
503
|
+
// ===== OPERATING EXPENSES (special case)
|
|
504
|
+
if (rowType === EFinanceSpreadingPLTotal.OPERATING_EXPENSES) {
|
|
505
|
+
|
|
506
|
+
const fixed = rowsData.filter(r => sheetById[r.sheetId]?.isFixedCost);
|
|
507
|
+
const variable = rowsData.filter(r => !sheetById[r.sheetId]?.isFixedCost);
|
|
508
|
+
|
|
509
|
+
if (fixed.length) {
|
|
510
|
+
rows.push(buildAggregatedRow('Fixed operating expenses', fixed));
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
if (variable.length) {
|
|
514
|
+
rows.push(buildAggregatedRow('Variable operating expenses', variable));
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
continue;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
// ===== DEFAULT ROW RENDERING
|
|
521
|
+
rowsData.forEach((rowData) => {
|
|
522
|
+
const sheet = sheetById[rowData.sheetId];
|
|
523
|
+
if (!sheet) return;
|
|
524
|
+
|
|
525
|
+
const oldData = range.map(r => rowData[`minus_${r}`]);
|
|
526
|
+
|
|
527
|
+
const baseRow: IExcelDataCellWithStyles[] = [
|
|
528
|
+
{ v: sheet.isTotal ? sheet.name : '', s: { font: { bold: true } } },
|
|
529
|
+
{ v: sheet.isTotal ? '' : sheet.name, s: { font: { italic: true } } },
|
|
530
|
+
...oldData.map(v => ({ v, t: 'n' })),
|
|
531
|
+
{ v: rowData.amount, t: 'n' },
|
|
532
|
+
];
|
|
533
|
+
|
|
534
|
+
const style = sheet.isTotal ? rowStyles[sheet.rowType] ?? {} : {};
|
|
535
|
+
|
|
536
|
+
rows.push(
|
|
537
|
+
baseRow.map(cell => ({
|
|
538
|
+
...cell,
|
|
539
|
+
s: _.merge(cell.s, style),
|
|
540
|
+
})),
|
|
541
|
+
);
|
|
542
|
+
});
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
fullData[financialSpreadingType] = [
|
|
546
|
+
fullHeaders,
|
|
547
|
+
...rows,
|
|
548
|
+
];
|
|
488
549
|
}));
|
|
489
550
|
|
|
490
551
|
return await this.uploadsService.convertDataToFileWithStyleOld({
|