@dssp/dkpi 1.0.0-alpha.7 β 1.0.0-alpha.70
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/KPI-STATISTICS-SERVICE.md +233 -0
- package/_index.html +0 -5
- package/assets/favicon.ico +0 -0
- package/assets/images/project-image.png +0 -0
- package/assets/manifest/apple-1024.png +0 -0
- package/assets/manifest/apple-120.png +0 -0
- package/assets/manifest/apple-152.png +0 -0
- package/assets/manifest/apple-167.png +0 -0
- package/assets/manifest/apple-180.png +0 -0
- package/assets/manifest/apple-touch-icon.png +0 -0
- package/assets/manifest/badge-128x128.png +0 -0
- package/assets/manifest/chrome-splashscreen-icon-384x384.png +0 -0
- package/assets/manifest/chrome-touch-icon-192x192.png +0 -0
- package/assets/manifest/icon-128x128.png +0 -0
- package/assets/manifest/icon-192x192.png +0 -0
- package/assets/manifest/icon-512x512.png +0 -0
- package/assets/manifest/icon-72x72.png +0 -0
- package/assets/manifest/icon-96x96.png +0 -0
- package/assets/manifest/image-metaog.png +0 -0
- package/assets/manifest/maskable_icon.png +0 -0
- package/assets/manifest/ms-icon-144x144.png +0 -0
- package/assets/manifest/ms-touch-icon-144x144-precomposed.png +0 -0
- package/assets/videos/intro.mp4 +0 -0
- package/dist-client/bootstrap.js +64 -4
- package/dist-client/bootstrap.js.map +1 -1
- package/dist-client/components/kpi-2d-lookup-chart.d.ts +43 -0
- package/dist-client/components/kpi-2d-lookup-chart.js +253 -0
- package/dist-client/components/kpi-2d-lookup-chart.js.map +1 -0
- package/dist-client/components/kpi-boxplot-chart.d.ts +24 -0
- package/dist-client/components/kpi-boxplot-chart.js +291 -0
- package/dist-client/components/kpi-boxplot-chart.js.map +1 -0
- package/dist-client/components/kpi-lookup-chart.d.ts +53 -0
- package/dist-client/components/kpi-lookup-chart.js +430 -0
- package/dist-client/components/kpi-lookup-chart.js.map +1 -0
- package/dist-client/components/kpi-mini-trend-chart.d.ts +14 -0
- package/dist-client/components/kpi-mini-trend-chart.js +148 -0
- package/dist-client/components/kpi-mini-trend-chart.js.map +1 -0
- package/dist-client/components/kpi-radar-chart.d.ts +17 -0
- package/dist-client/components/kpi-radar-chart.js +259 -0
- package/dist-client/components/kpi-radar-chart.js.map +1 -0
- package/dist-client/components/kpi-single-boxplot-chart.d.ts +24 -0
- package/dist-client/components/kpi-single-boxplot-chart.js +391 -0
- package/dist-client/components/kpi-single-boxplot-chart.js.map +1 -0
- package/dist-client/components/kpi-trend-chart.d.ts +25 -0
- package/dist-client/components/kpi-trend-chart.js +220 -0
- package/dist-client/components/kpi-trend-chart.js.map +1 -0
- package/dist-client/components/sv-pagenation-control.d.ts +18 -0
- package/dist-client/components/sv-pagenation-control.js +142 -0
- package/dist-client/components/sv-pagenation-control.js.map +1 -0
- package/dist-client/google-map/common-google-map.d.ts +35 -0
- package/dist-client/google-map/common-google-map.js +345 -0
- package/dist-client/google-map/common-google-map.js.map +1 -0
- package/dist-client/google-map/google-map-loader.d.ts +6 -0
- package/dist-client/google-map/google-map-loader.js +23 -0
- package/dist-client/google-map/google-map-loader.js.map +1 -0
- package/dist-client/icons/menu-icons.d.ts +6 -0
- package/dist-client/icons/menu-icons.js +42 -0
- package/dist-client/icons/menu-icons.js.map +1 -1
- package/dist-client/pages/kpi-admin/dssp-kpi-list-page.d.ts +22 -0
- package/dist-client/pages/kpi-admin/dssp-kpi-list-page.js +57 -0
- package/dist-client/pages/kpi-admin/dssp-kpi-list-page.js.map +1 -0
- package/dist-client/pages/kpi-admin/dssp-kpi-overview.d.ts +46 -0
- package/dist-client/pages/kpi-admin/dssp-kpi-overview.js +378 -0
- package/dist-client/pages/kpi-admin/dssp-kpi-overview.js.map +1 -0
- package/dist-client/pages/kpi-admin/kpi-grade-2d-editor.d.ts +20 -0
- package/dist-client/pages/kpi-admin/kpi-grade-2d-editor.js +445 -0
- package/dist-client/pages/kpi-admin/kpi-grade-2d-editor.js.map +1 -0
- package/dist-client/pages/kpi-admin/kpi-system-guide.d.ts +18 -0
- package/dist-client/pages/kpi-admin/kpi-system-guide.js +535 -0
- package/dist-client/pages/kpi-admin/kpi-system-guide.js.map +1 -0
- package/dist-client/pages/kpi-dashboard/cards/kpi-level1-card.d.ts +18 -0
- package/dist-client/pages/kpi-dashboard/cards/kpi-level1-card.js +259 -0
- package/dist-client/pages/kpi-dashboard/cards/kpi-level1-card.js.map +1 -0
- package/dist-client/pages/kpi-dashboard/cards/kpi-level2-comparison.d.ts +22 -0
- package/dist-client/pages/kpi-dashboard/cards/kpi-level2-comparison.js +346 -0
- package/dist-client/pages/kpi-dashboard/cards/kpi-level2-comparison.js.map +1 -0
- package/dist-client/pages/kpi-dashboard/cards/kpi-level3-comparison.d.ts +26 -0
- package/dist-client/pages/kpi-dashboard/cards/kpi-level3-comparison.js +433 -0
- package/dist-client/pages/kpi-dashboard/cards/kpi-level3-comparison.js.map +1 -0
- package/dist-client/pages/kpi-dashboard/components/kpi-chart-toggle.d.ts +8 -0
- package/dist-client/pages/kpi-dashboard/components/kpi-chart-toggle.js +78 -0
- package/dist-client/pages/kpi-dashboard/components/kpi-chart-toggle.js.map +1 -0
- package/dist-client/pages/kpi-dashboard/components/kpi-left-panel.d.ts +38 -0
- package/dist-client/pages/kpi-dashboard/components/kpi-left-panel.js +851 -0
- package/dist-client/pages/kpi-dashboard/components/kpi-left-panel.js.map +1 -0
- package/dist-client/pages/kpi-dashboard/components/kpi-map-panel.d.ts +42 -0
- package/dist-client/pages/kpi-dashboard/components/kpi-map-panel.js +316 -0
- package/dist-client/pages/kpi-dashboard/components/kpi-map-panel.js.map +1 -0
- package/dist-client/pages/kpi-dashboard/components/kpi-region-popup.d.ts +28 -0
- package/dist-client/pages/kpi-dashboard/components/kpi-region-popup.js +497 -0
- package/dist-client/pages/kpi-dashboard/components/kpi-region-popup.js.map +1 -0
- package/dist-client/pages/kpi-dashboard/kpi-alert-panel.d.ts +18 -0
- package/dist-client/pages/kpi-dashboard/kpi-alert-panel.js +131 -0
- package/dist-client/pages/kpi-dashboard/kpi-alert-panel.js.map +1 -0
- package/dist-client/pages/kpi-dashboard/kpi-dashboard-map.d.ts +52 -0
- package/dist-client/pages/kpi-dashboard/kpi-dashboard-map.js +798 -0
- package/dist-client/pages/kpi-dashboard/kpi-dashboard-map.js.map +1 -0
- package/dist-client/pages/kpi-dashboard/kpi-dashboard.d.ts +63 -0
- package/dist-client/pages/kpi-dashboard/kpi-dashboard.js +1089 -0
- package/dist-client/pages/kpi-dashboard/kpi-dashboard.js.map +1 -0
- package/dist-client/pages/kpi-dashboard/kpi-grade-visualization.d.ts +12 -0
- package/dist-client/pages/kpi-dashboard/kpi-grade-visualization.js +82 -0
- package/dist-client/pages/kpi-dashboard/kpi-grade-visualization.js.map +1 -0
- package/dist-client/pages/kpi-dashboard/kpi-history-viewer.d.ts +11 -0
- package/dist-client/pages/kpi-dashboard/kpi-history-viewer.js +65 -0
- package/dist-client/pages/kpi-dashboard/kpi-history-viewer.js.map +1 -0
- package/dist-client/pages/kpi-dashboard/kpi-list-summary.d.ts +13 -0
- package/dist-client/pages/kpi-dashboard/kpi-list-summary.js +115 -0
- package/dist-client/pages/kpi-dashboard/kpi-list-summary.js.map +1 -0
- package/dist-client/pages/kpi-dashboard/kpi-performance-summary.d.ts +15 -0
- package/dist-client/pages/kpi-dashboard/kpi-performance-summary.js +147 -0
- package/dist-client/pages/kpi-dashboard/kpi-performance-summary.js.map +1 -0
- package/dist-client/pages/kpi-dashboard/kpi-value-entry.d.ts +7 -0
- package/dist-client/pages/kpi-dashboard/kpi-value-entry.js +86 -0
- package/dist-client/pages/kpi-dashboard/kpi-value-entry.js.map +1 -0
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-editor-page.d.ts +57 -0
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-editor-page.js +719 -0
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-editor-page.js.map +1 -0
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-importer.d.ts +23 -0
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-importer.js +76 -0
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-importer.js.map +1 -0
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-list-page.d.ts +68 -0
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-list-page.js +380 -0
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-list-page.js.map +1 -0
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-form.d.ts +12 -0
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-form.js +174 -0
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-form.js.map +1 -0
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-page.d.ts +40 -0
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-page.js +190 -0
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-page.js.map +1 -0
- package/dist-client/pages/kpi-value/kpi-value-importer.d.ts +23 -0
- package/dist-client/pages/kpi-value/kpi-value-importer.js +93 -0
- package/dist-client/pages/kpi-value/kpi-value-importer.js.map +1 -0
- package/dist-client/pages/kpi-value/kpi-value-list-page.d.ts +71 -0
- package/dist-client/pages/kpi-value/kpi-value-list-page.js +464 -0
- package/dist-client/pages/kpi-value/kpi-value-list-page.js.map +1 -0
- package/dist-client/pages/project-complete-tabs/pc-tab1-plan.d.ts +14 -0
- package/dist-client/pages/project-complete-tabs/pc-tab1-plan.js +339 -0
- package/dist-client/pages/project-complete-tabs/pc-tab1-plan.js.map +1 -0
- package/dist-client/pages/project-complete-tabs/pc-tab2-rating.d.ts +14 -0
- package/dist-client/pages/project-complete-tabs/pc-tab2-rating.js +276 -0
- package/dist-client/pages/project-complete-tabs/pc-tab2-rating.js.map +1 -0
- package/dist-client/pages/project-complete-tabs/pc-tab3-upload.d.ts +18 -0
- package/dist-client/pages/project-complete-tabs/pc-tab3-upload.js +307 -0
- package/dist-client/pages/project-complete-tabs/pc-tab3-upload.js.map +1 -0
- package/dist-client/pages/project-complete-tabs/pc-tab4-monthly.d.ts +18 -0
- package/dist-client/pages/project-complete-tabs/pc-tab4-monthly.js +433 -0
- package/dist-client/pages/project-complete-tabs/pc-tab4-monthly.js.map +1 -0
- package/dist-client/pages/sv-project-complete.d.ts +21 -0
- package/dist-client/pages/sv-project-complete.js +213 -0
- package/dist-client/pages/sv-project-complete.js.map +1 -0
- package/dist-client/pages/sv-project-completed-list.d.ts +27 -0
- package/dist-client/pages/sv-project-completed-list.js +416 -0
- package/dist-client/pages/sv-project-completed-list.js.map +1 -0
- package/dist-client/pages/sv-project-detail.d.ts +46 -0
- package/dist-client/pages/sv-project-detail.js +1236 -0
- package/dist-client/pages/sv-project-detail.js.map +1 -0
- package/dist-client/pages/sv-project-list.d.ts +165 -0
- package/dist-client/pages/sv-project-list.js +488 -0
- package/dist-client/pages/sv-project-list.js.map +1 -0
- package/dist-client/route.d.ts +1 -1
- package/dist-client/route.js +35 -1
- package/dist-client/route.js.map +1 -1
- package/dist-client/shared/complete-api.d.ts +8 -0
- package/dist-client/shared/complete-api.js +177 -0
- package/dist-client/shared/complete-api.js.map +1 -0
- package/dist-client/shared/func.d.ts +2 -0
- package/dist-client/shared/func.js +22 -0
- package/dist-client/shared/func.js.map +1 -0
- package/dist-client/themes/dark.css +24 -24
- package/dist-client/themes/light.css +23 -23
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-client/viewparts/menu-tools.d.ts +40 -5
- package/dist-client/viewparts/menu-tools.js +289 -34
- package/dist-client/viewparts/menu-tools.js.map +1 -1
- package/dist-server/index.d.ts +2 -0
- package/dist-server/index.js +5 -0
- package/dist-server/index.js.map +1 -1
- package/dist-server/migrations/index.d.ts +1 -0
- package/dist-server/migrations/index.js +12 -0
- package/dist-server/migrations/index.js.map +1 -0
- package/dist-server/scripts/calculate-kpi-scores.d.ts +10 -0
- package/dist-server/scripts/calculate-kpi-scores.js +333 -0
- package/dist-server/scripts/calculate-kpi-scores.js.map +1 -0
- package/dist-server/scripts/load-grade-data-migration.d.ts +14 -0
- package/dist-server/scripts/load-grade-data-migration.js +279 -0
- package/dist-server/scripts/load-grade-data-migration.js.map +1 -0
- package/dist-server/scripts/propagate-parent-kpi-values.d.ts +14 -0
- package/dist-server/scripts/propagate-parent-kpi-values.js +786 -0
- package/dist-server/scripts/propagate-parent-kpi-values.js.map +1 -0
- package/dist-server/scripts/recalculate-by-project-name.d.ts +2 -0
- package/dist-server/scripts/recalculate-by-project-name.js +72 -0
- package/dist-server/scripts/recalculate-by-project-name.js.map +1 -0
- package/dist-server/service/index.d.ts +4 -0
- package/dist-server/service/index.js +20 -0
- package/dist-server/service/index.js.map +1 -0
- package/dist-server/service/kpi-metric-value/index.d.ts +4 -0
- package/dist-server/service/kpi-metric-value/index.js +8 -0
- package/dist-server/service/kpi-metric-value/index.js.map +1 -0
- package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.d.ts +74 -0
- package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.js +687 -0
- package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.js.map +1 -0
- package/dist-server/service/kpi-metric-value/kpi-metric-value-query.d.ts +7 -0
- package/dist-server/service/kpi-metric-value/kpi-metric-value-query.js +52 -0
- package/dist-server/service/kpi-metric-value/kpi-metric-value-query.js.map +1 -0
- package/dist-server/service/kpi-stat/index.d.ts +4 -0
- package/dist-server/service/kpi-stat/index.js +8 -0
- package/dist-server/service/kpi-stat/index.js.map +1 -0
- package/dist-server/service/kpi-stat/kpi-stat-query.d.ts +12 -0
- package/dist-server/service/kpi-stat/kpi-stat-query.js +662 -0
- package/dist-server/service/kpi-stat/kpi-stat-query.js.map +1 -0
- package/dist-server/service/kpi-stat/kpi-stat-types.d.ts +32 -0
- package/dist-server/service/kpi-stat/kpi-stat-types.js +180 -0
- package/dist-server/service/kpi-stat/kpi-stat-types.js.map +1 -0
- package/dist-server/service/kpi-value/index.d.ts +3 -0
- package/dist-server/service/kpi-value/index.js +7 -0
- package/dist-server/service/kpi-value/index.js.map +1 -0
- package/dist-server/service/kpi-value/kpi-value-query.d.ts +8 -0
- package/dist-server/service/kpi-value/kpi-value-query.js +69 -0
- package/dist-server/service/kpi-value/kpi-value-query.js.map +1 -0
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/kpi-module-service-tests.md +1286 -0
- package/kpi-module-test-report.md +676 -0
- package/kpi-module-unit-test-detailed-report.md +925 -0
- package/kpi-module-unit-tests-detailed.md +1452 -0
- package/package.json +65 -55
- package/recalculate-batch.sh +64 -0
- package/recalculate-projects-range.sh +98 -0
- package/schema.graphql +2514 -455
- package/things-factory.config.js +11 -1
- package/views/auth-page.html +0 -1
- package/views/public/home.html +0 -1
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
#!/usr/bin/env ts-node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.calculateKpiScores = calculateKpiScores;
|
|
5
|
+
exports.listKpisWithLookupTables = listKpisWithLookupTables;
|
|
6
|
+
const typeorm_1 = require("typeorm");
|
|
7
|
+
function isGrade2DLookup(grades) {
|
|
8
|
+
return grades && typeof grades === 'object' && !Array.isArray(grades) && grades.type === 'PROGRESS_DEVIATION_LOOKUP';
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* 2D lookup tableμμ μ μ κ³μ° (X13: 곡μ λ₯ Γ νΈμ°¨ β μ μ)
|
|
12
|
+
* @param deviationValue νΈμ°¨μ¨ (formula κ²°κ³Ό)
|
|
13
|
+
* @param grades 2D lookup grades κ°μ²΄
|
|
14
|
+
* @param progressRate 곡μ λ₯ (0~100)
|
|
15
|
+
*/
|
|
16
|
+
function calculate2DScore(deviationValue, grades, progressRate) {
|
|
17
|
+
if (!grades.rows || grades.rows.length === 0)
|
|
18
|
+
return null;
|
|
19
|
+
const progressIndex = Math.min(99, Math.max(0, Math.floor(progressRate)));
|
|
20
|
+
const row = grades.rows.find(r => r.progressRate === progressIndex);
|
|
21
|
+
if (!row)
|
|
22
|
+
return null;
|
|
23
|
+
if (deviationValue < row.boundary5to4)
|
|
24
|
+
return 5;
|
|
25
|
+
if (deviationValue < row.boundary4to3)
|
|
26
|
+
return 4;
|
|
27
|
+
if (deviationValue < row.boundary3to2)
|
|
28
|
+
return 3;
|
|
29
|
+
if (deviationValue < row.boundary2to1)
|
|
30
|
+
return 2;
|
|
31
|
+
return 1;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Calculate KPI scores based on lookup tables (grades)
|
|
35
|
+
* Processes kpi-values and updates scores based on KPI grades
|
|
36
|
+
*/
|
|
37
|
+
async function calculateKpiScores(specificKpiName, forceRecalculate = false) {
|
|
38
|
+
var _a;
|
|
39
|
+
// Set NODE_ENV if not set
|
|
40
|
+
if (!process.env.NODE_ENV) {
|
|
41
|
+
process.env.NODE_ENV = 'development';
|
|
42
|
+
}
|
|
43
|
+
// Initialize Things-Factory environment
|
|
44
|
+
const { config } = require('@things-factory/env');
|
|
45
|
+
const ormconfig = require('@things-factory/shell/dist-server/initializers/ormconfig.js');
|
|
46
|
+
const connectionConfig = config.get('ormconfig');
|
|
47
|
+
let connection;
|
|
48
|
+
console.log('π Starting KPI Score Calculation...');
|
|
49
|
+
try {
|
|
50
|
+
// Create database connection using Things-Factory pattern
|
|
51
|
+
console.log('π Connecting to database...');
|
|
52
|
+
connection = await (0, typeorm_1.createConnection)(Object.assign(Object.assign(Object.assign({}, ormconfig), connectionConfig), { logging: false }));
|
|
53
|
+
// Register the connection with Things-Factory shell
|
|
54
|
+
const { addDataSource } = require('@things-factory/shell');
|
|
55
|
+
addDataSource('default', connection);
|
|
56
|
+
console.log('β
Database connected');
|
|
57
|
+
// Now we can use getRepository with the registered connection
|
|
58
|
+
const { getRepository } = require('@things-factory/shell');
|
|
59
|
+
const { Kpi } = require('@things-factory/kpi');
|
|
60
|
+
const kpiRepository = getRepository(Kpi);
|
|
61
|
+
// Get KPI-Value repository (assuming it exists)
|
|
62
|
+
let kpiValueRepository;
|
|
63
|
+
try {
|
|
64
|
+
const { KpiValue } = require('@things-factory/kpi');
|
|
65
|
+
kpiValueRepository = getRepository(KpiValue);
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
console.error('β KpiValue entity not found. Please ensure it exists in @things-factory/kpi');
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
// Get KPIs with grades (lookup tables)
|
|
72
|
+
let kpisQuery = kpiRepository
|
|
73
|
+
.createQueryBuilder('kpi')
|
|
74
|
+
.leftJoinAndSelect('kpi.domain', 'domain')
|
|
75
|
+
.where('kpi.grades IS NOT NULL')
|
|
76
|
+
.andWhere('domain.name = :domainName', { domainName: 'SYSTEM' });
|
|
77
|
+
if (specificKpiName) {
|
|
78
|
+
kpisQuery = kpisQuery.andWhere('kpi.name = :name', { name: specificKpiName });
|
|
79
|
+
console.log(`π― Processing specific KPI: ${specificKpiName}`);
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
console.log('π― Processing all KPIs with lookup tables');
|
|
83
|
+
}
|
|
84
|
+
const kpis = await kpisQuery.getMany();
|
|
85
|
+
if (kpis.length === 0) {
|
|
86
|
+
console.log('β οΈ No KPIs found with lookup tables (grades)');
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
console.log(`π Found ${kpis.length} KPIs with lookup tables`);
|
|
90
|
+
let totalProcessed = 0;
|
|
91
|
+
let totalUpdated = 0;
|
|
92
|
+
let errorCount = 0;
|
|
93
|
+
// 2D lookup KPI (X13)μ νμν Project entity μ€λΉ
|
|
94
|
+
let projectRepository = null;
|
|
95
|
+
const progressRateCache = new Map();
|
|
96
|
+
try {
|
|
97
|
+
const { Project } = require('@dssp/project');
|
|
98
|
+
projectRepository = getRepository(Project);
|
|
99
|
+
}
|
|
100
|
+
catch (_b) {
|
|
101
|
+
console.log('β οΈ @dssp/project not found β 2D lookup KPIs will use default progressRate');
|
|
102
|
+
}
|
|
103
|
+
for (const kpi of kpis) {
|
|
104
|
+
try {
|
|
105
|
+
console.log(`\nπ Processing KPI: ${kpi.name}`);
|
|
106
|
+
const is2D = isGrade2DLookup(kpi.grades);
|
|
107
|
+
if (!is2D && (!kpi.grades || !Array.isArray(kpi.grades) || kpi.grades.length === 0)) {
|
|
108
|
+
console.log(` β οΈ No grades found, skipping`);
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
if (is2D) {
|
|
112
|
+
console.log(` π 2D Lookup table: ${kpi.grades.rows.length} rows`);
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
console.log(` π Lookup table: ${kpi.grades.length} grades`);
|
|
116
|
+
}
|
|
117
|
+
// Get KPI values for this KPI
|
|
118
|
+
let kpiValuesQuery = kpiValueRepository
|
|
119
|
+
.createQueryBuilder('kpiValue')
|
|
120
|
+
.leftJoinAndSelect('kpiValue.kpi', 'kpi')
|
|
121
|
+
.where('kpi.id = :kpiId', { kpiId: kpi.id })
|
|
122
|
+
.andWhere('kpiValue.value IS NOT NULL');
|
|
123
|
+
if (!forceRecalculate) {
|
|
124
|
+
// Only process null or 0 scores by default
|
|
125
|
+
kpiValuesQuery = kpiValuesQuery.andWhere('(kpiValue.score IS NULL OR kpiValue.score = 0)');
|
|
126
|
+
}
|
|
127
|
+
const kpiValues = await kpiValuesQuery.getMany();
|
|
128
|
+
if (kpiValues.length === 0) {
|
|
129
|
+
console.log(` β
No null/zero scores found (all values already calculated)`);
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
console.log(` π’ Processing ${kpiValues.length} null/zero scores`);
|
|
133
|
+
let updatedCount = 0;
|
|
134
|
+
for (const kpiValue of kpiValues) {
|
|
135
|
+
const value = kpiValue.value;
|
|
136
|
+
let calculatedScore;
|
|
137
|
+
if (is2D) {
|
|
138
|
+
// 2D lookup: projectμ totalProgress μ‘°ν
|
|
139
|
+
let progressRate = 50; // default
|
|
140
|
+
const projectId = kpiValue.group;
|
|
141
|
+
if (projectId && projectRepository) {
|
|
142
|
+
if (progressRateCache.has(projectId)) {
|
|
143
|
+
progressRate = progressRateCache.get(projectId);
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
const project = await projectRepository.findOne({ where: { id: projectId } });
|
|
147
|
+
progressRate = (_a = project === null || project === void 0 ? void 0 : project.totalProgress) !== null && _a !== void 0 ? _a : 50;
|
|
148
|
+
progressRateCache.set(projectId, progressRate);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
calculatedScore = calculate2DScore(value, kpi.grades, progressRate);
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
calculatedScore = calculateScoreFromGrades(value, kpi.grades);
|
|
155
|
+
}
|
|
156
|
+
if (calculatedScore !== null) {
|
|
157
|
+
// Only update if the score is actually different
|
|
158
|
+
if (kpiValue.score !== calculatedScore) {
|
|
159
|
+
const oldScore = kpiValue.score;
|
|
160
|
+
kpiValue.score = calculatedScore;
|
|
161
|
+
await kpiValueRepository.save(kpiValue);
|
|
162
|
+
updatedCount++;
|
|
163
|
+
console.log(` π Value ${value} β Score ${calculatedScore} (was ${oldScore || 'null'})`);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
console.log(` β οΈ Value ${value} is below all ranges in lookup table`);
|
|
168
|
+
}
|
|
169
|
+
totalProcessed++;
|
|
170
|
+
}
|
|
171
|
+
console.log(` β
Updated ${updatedCount}/${kpiValues.length} values`);
|
|
172
|
+
totalUpdated += updatedCount;
|
|
173
|
+
}
|
|
174
|
+
catch (kpiError) {
|
|
175
|
+
console.log(` β Error processing KPI ${kpi.name}: ${kpiError.message}`);
|
|
176
|
+
errorCount++;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
console.log(`\nπ KPI Score Calculation Complete!`);
|
|
180
|
+
console.log(` π KPIs processed: ${kpis.length}`);
|
|
181
|
+
console.log(` π’ Total values processed: ${totalProcessed}`);
|
|
182
|
+
console.log(` β
Scores updated: ${totalUpdated}`);
|
|
183
|
+
console.log(` β Errors: ${errorCount}`);
|
|
184
|
+
if (errorCount > 0) {
|
|
185
|
+
console.log(`\nβ οΈ Some KPIs had errors. Check the logs above for details.`);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
catch (error) {
|
|
189
|
+
console.error(`β Fatal error during score calculation:`, error);
|
|
190
|
+
throw error;
|
|
191
|
+
}
|
|
192
|
+
finally {
|
|
193
|
+
if (connection) {
|
|
194
|
+
await connection.close();
|
|
195
|
+
console.log('π Database connection closed');
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Calculate score from grades lookup table
|
|
201
|
+
* If exact range not found, use the score of the largest minValue that is <= value
|
|
202
|
+
*/
|
|
203
|
+
function calculateScoreFromGrades(value, grades) {
|
|
204
|
+
// First try to find exact range match
|
|
205
|
+
for (const grade of grades) {
|
|
206
|
+
if (value >= grade.minValue && value <= grade.maxValue) {
|
|
207
|
+
return grade.score || 0;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
// If no exact match, find the grade with largest minValue that is <= value
|
|
211
|
+
let bestGrade = null;
|
|
212
|
+
let bestMinValue = -Infinity;
|
|
213
|
+
for (const grade of grades) {
|
|
214
|
+
if (grade.minValue <= value && grade.minValue > bestMinValue) {
|
|
215
|
+
bestGrade = grade;
|
|
216
|
+
bestMinValue = grade.minValue;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
if (bestGrade) {
|
|
220
|
+
return bestGrade.score || 0;
|
|
221
|
+
}
|
|
222
|
+
return null; // Value is smaller than all minValues in lookup table
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* List KPIs that have lookup tables (grades)
|
|
226
|
+
*/
|
|
227
|
+
async function listKpisWithLookupTables() {
|
|
228
|
+
// Set NODE_ENV if not set
|
|
229
|
+
if (!process.env.NODE_ENV) {
|
|
230
|
+
process.env.NODE_ENV = 'development';
|
|
231
|
+
}
|
|
232
|
+
// Initialize Things-Factory environment
|
|
233
|
+
const { config } = require('@things-factory/env');
|
|
234
|
+
const ormconfig = require('@things-factory/shell/dist-server/initializers/ormconfig.js');
|
|
235
|
+
const connectionConfig = config.get('ormconfig');
|
|
236
|
+
let connection;
|
|
237
|
+
try {
|
|
238
|
+
console.log('π Connecting to database...');
|
|
239
|
+
connection = await (0, typeorm_1.createConnection)(Object.assign(Object.assign(Object.assign({}, ormconfig), connectionConfig), { logging: false }));
|
|
240
|
+
const { addDataSource } = require('@things-factory/shell');
|
|
241
|
+
addDataSource('default', connection);
|
|
242
|
+
const { getRepository } = require('@things-factory/shell');
|
|
243
|
+
const { Kpi } = require('@things-factory/kpi');
|
|
244
|
+
const kpiRepository = getRepository(Kpi);
|
|
245
|
+
// Get KPIs with grades
|
|
246
|
+
const kpis = await kpiRepository
|
|
247
|
+
.createQueryBuilder('kpi')
|
|
248
|
+
.leftJoinAndSelect('kpi.domain', 'domain')
|
|
249
|
+
.where('kpi.grades IS NOT NULL')
|
|
250
|
+
.andWhere('domain.name = :domainName', { domainName: 'SYSTEM' })
|
|
251
|
+
.getMany();
|
|
252
|
+
console.log(`π KPIs with lookup tables (${kpis.length}):\n`);
|
|
253
|
+
if (kpis.length === 0) {
|
|
254
|
+
console.log(' No KPIs found with lookup tables.');
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
kpis.forEach((kpi, index) => {
|
|
258
|
+
const gradeCount = kpi.grades ? kpi.grades.length : 0;
|
|
259
|
+
console.log(` ${(index + 1).toString().padStart(2)}: ${kpi.name} (${gradeCount} grades)`);
|
|
260
|
+
});
|
|
261
|
+
console.log(`\nπ Total: ${kpis.length} KPIs with lookup tables`);
|
|
262
|
+
}
|
|
263
|
+
catch (error) {
|
|
264
|
+
console.error('β Error listing KPIs:', error);
|
|
265
|
+
}
|
|
266
|
+
finally {
|
|
267
|
+
if (connection) {
|
|
268
|
+
await connection.close();
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* CLI execution when called directly
|
|
274
|
+
*/
|
|
275
|
+
async function main() {
|
|
276
|
+
const args = process.argv.slice(2);
|
|
277
|
+
try {
|
|
278
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
279
|
+
console.log(`
|
|
280
|
+
π― KPI Score Calculator
|
|
281
|
+
|
|
282
|
+
Usage:
|
|
283
|
+
ts-node server/scripts/calculate-kpi-scores.ts [options] [kpiName]
|
|
284
|
+
|
|
285
|
+
Options:
|
|
286
|
+
--list, -l List KPIs that have lookup tables
|
|
287
|
+
--force, -f Force recalculate all scores (not just null/zero ones)
|
|
288
|
+
--help, -h Show this help
|
|
289
|
+
|
|
290
|
+
Examples:
|
|
291
|
+
ts-node server/scripts/calculate-kpi-scores.ts # Calculate scores for null/zero values only
|
|
292
|
+
ts-node server/scripts/calculate-kpi-scores.ts --force # Recalculate ALL scores
|
|
293
|
+
ts-node server/scripts/calculate-kpi-scores.ts "X11. μ°λ©΄μ λλΉ κ³΅μ¬κΈ°κ°" # Calculate for specific KPI
|
|
294
|
+
ts-node server/scripts/calculate-kpi-scores.ts --list # List KPIs with lookup tables
|
|
295
|
+
|
|
296
|
+
Note: By default, only processes kpi-values with null or zero scores.
|
|
297
|
+
Use --force to recalculate all scores.
|
|
298
|
+
`);
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
if (args.includes('--list') || args.includes('-l')) {
|
|
302
|
+
await listKpisWithLookupTables();
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
const forceRecalculate = args.includes('--force') || args.includes('-f');
|
|
306
|
+
const specificKpiName = args.find(arg => !arg.startsWith('--'));
|
|
307
|
+
if (specificKpiName) {
|
|
308
|
+
console.log(`π― Calculating scores for specific KPI: ${specificKpiName}`);
|
|
309
|
+
console.log(` Mode: ${forceRecalculate ? 'Force recalculate ALL' : 'Only null/zero scores'}`);
|
|
310
|
+
await calculateKpiScores(specificKpiName, forceRecalculate);
|
|
311
|
+
}
|
|
312
|
+
else {
|
|
313
|
+
console.log(`π― Calculating scores for all KPIs with lookup tables`);
|
|
314
|
+
console.log(` Mode: ${forceRecalculate ? 'Force recalculate ALL' : 'Only null/zero scores'}`);
|
|
315
|
+
await calculateKpiScores(undefined, forceRecalculate);
|
|
316
|
+
}
|
|
317
|
+
console.log('\n⨠Done!');
|
|
318
|
+
}
|
|
319
|
+
catch (error) {
|
|
320
|
+
console.error('\nβ Script failed:', error.message);
|
|
321
|
+
process.exit(1);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
// Handle uncaught errors
|
|
325
|
+
process.on('unhandledRejection', (error) => {
|
|
326
|
+
console.error('β Unhandled error:', error.message || error);
|
|
327
|
+
process.exit(1);
|
|
328
|
+
});
|
|
329
|
+
// Run if called directly
|
|
330
|
+
if (require.main === module) {
|
|
331
|
+
main();
|
|
332
|
+
}
|
|
333
|
+
//# sourceMappingURL=calculate-kpi-scores.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"calculate-kpi-scores.js","sourceRoot":"","sources":["../../server/scripts/calculate-kpi-scores.ts"],"names":[],"mappings":"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","sourcesContent":["#!/usr/bin/env ts-node\n\nimport { createConnection } from 'typeorm'\nimport * as fs from 'fs'\nimport * as path from 'path'\n\ninterface KpiGrade {\n name: string\n minValue: number\n maxValue: number\n score?: number\n color?: string\n description?: string\n}\n\ninterface Grade2DRow {\n progressRate: number\n boundary5to4: number\n boundary4to3: number\n boundary3to2: number\n boundary2to1: number\n}\n\ninterface Grade2DLookup {\n type: 'PROGRESS_DEVIATION_LOOKUP'\n rows: Grade2DRow[]\n}\n\ninterface KpiRecord {\n id: string\n name: string\n grades: KpiGrade[] | Grade2DLookup | any\n}\n\ninterface KpiValueRecord {\n id: string\n value: number\n score?: number\n group?: string\n kpi: KpiRecord\n}\n\nfunction isGrade2DLookup(grades: any): grades is Grade2DLookup {\n return grades && typeof grades === 'object' && !Array.isArray(grades) && grades.type === 'PROGRESS_DEVIATION_LOOKUP'\n}\n\n/**\n * 2D lookup tableμμ μ μ κ³μ° (X13: 곡μ λ₯ Γ νΈμ°¨ β μ μ)\n * @param deviationValue νΈμ°¨μ¨ (formula κ²°κ³Ό)\n * @param grades 2D lookup grades κ°μ²΄\n * @param progressRate 곡μ λ₯ (0~100)\n */\nfunction calculate2DScore(deviationValue: number, grades: Grade2DLookup, progressRate: number): number | null {\n if (!grades.rows || grades.rows.length === 0) return null\n\n const progressIndex = Math.min(99, Math.max(0, Math.floor(progressRate)))\n const row = grades.rows.find(r => r.progressRate === progressIndex)\n if (!row) return null\n\n if (deviationValue < row.boundary5to4) return 5\n if (deviationValue < row.boundary4to3) return 4\n if (deviationValue < row.boundary3to2) return 3\n if (deviationValue < row.boundary2to1) return 2\n return 1\n}\n\n/**\n * Calculate KPI scores based on lookup tables (grades)\n * Processes kpi-values and updates scores based on KPI grades\n */\nexport async function calculateKpiScores(specificKpiName?: string, forceRecalculate = false): Promise<void> {\n // Set NODE_ENV if not set\n if (!process.env.NODE_ENV) {\n process.env.NODE_ENV = 'development'\n }\n\n // Initialize Things-Factory environment\n const { config } = require('@things-factory/env')\n const ormconfig = require('@things-factory/shell/dist-server/initializers/ormconfig.js')\n const connectionConfig = config.get('ormconfig')\n\n let connection\n\n console.log('π Starting KPI Score Calculation...')\n\n try {\n // Create database connection using Things-Factory pattern\n console.log('π Connecting to database...')\n connection = await createConnection({\n ...ormconfig,\n ...connectionConfig,\n logging: false\n })\n\n // Register the connection with Things-Factory shell\n const { addDataSource } = require('@things-factory/shell')\n addDataSource('default', connection)\n\n console.log('β
Database connected')\n\n // Now we can use getRepository with the registered connection\n const { getRepository } = require('@things-factory/shell')\n const { Kpi } = require('@things-factory/kpi')\n const kpiRepository = getRepository(Kpi)\n\n // Get KPI-Value repository (assuming it exists)\n let kpiValueRepository\n try {\n const { KpiValue } = require('@things-factory/kpi')\n kpiValueRepository = getRepository(KpiValue)\n } catch (error) {\n console.error('β KpiValue entity not found. Please ensure it exists in @things-factory/kpi')\n return\n }\n\n // Get KPIs with grades (lookup tables)\n let kpisQuery = kpiRepository\n .createQueryBuilder('kpi')\n .leftJoinAndSelect('kpi.domain', 'domain')\n .where('kpi.grades IS NOT NULL')\n .andWhere('domain.name = :domainName', { domainName: 'SYSTEM' })\n\n if (specificKpiName) {\n kpisQuery = kpisQuery.andWhere('kpi.name = :name', { name: specificKpiName })\n console.log(`π― Processing specific KPI: ${specificKpiName}`)\n } else {\n console.log('π― Processing all KPIs with lookup tables')\n }\n\n const kpis = await kpisQuery.getMany()\n\n if (kpis.length === 0) {\n console.log('β οΈ No KPIs found with lookup tables (grades)')\n return\n }\n\n console.log(`π Found ${kpis.length} KPIs with lookup tables`)\n\n let totalProcessed = 0\n let totalUpdated = 0\n let errorCount = 0\n\n // 2D lookup KPI (X13)μ νμν Project entity μ€λΉ\n let projectRepository: any = null\n const progressRateCache = new Map<string, number>()\n\n try {\n const { Project } = require('@dssp/project')\n projectRepository = getRepository(Project)\n } catch {\n console.log('β οΈ @dssp/project not found β 2D lookup KPIs will use default progressRate')\n }\n\n for (const kpi of kpis) {\n try {\n console.log(`\\nπ Processing KPI: ${kpi.name}`)\n\n const is2D = isGrade2DLookup(kpi.grades)\n\n if (!is2D && (!kpi.grades || !Array.isArray(kpi.grades) || kpi.grades.length === 0)) {\n console.log(` β οΈ No grades found, skipping`)\n continue\n }\n\n if (is2D) {\n console.log(` π 2D Lookup table: ${kpi.grades.rows.length} rows`)\n } else {\n console.log(` π Lookup table: ${kpi.grades.length} grades`)\n }\n\n // Get KPI values for this KPI\n let kpiValuesQuery = kpiValueRepository\n .createQueryBuilder('kpiValue')\n .leftJoinAndSelect('kpiValue.kpi', 'kpi')\n .where('kpi.id = :kpiId', { kpiId: kpi.id })\n .andWhere('kpiValue.value IS NOT NULL')\n\n if (!forceRecalculate) {\n // Only process null or 0 scores by default\n kpiValuesQuery = kpiValuesQuery.andWhere('(kpiValue.score IS NULL OR kpiValue.score = 0)')\n }\n\n const kpiValues = await kpiValuesQuery.getMany()\n\n if (kpiValues.length === 0) {\n console.log(` β
No null/zero scores found (all values already calculated)`)\n continue\n }\n\n console.log(` π’ Processing ${kpiValues.length} null/zero scores`)\n\n let updatedCount = 0\n\n for (const kpiValue of kpiValues) {\n const value = kpiValue.value\n let calculatedScore: number | null\n\n if (is2D) {\n // 2D lookup: projectμ totalProgress μ‘°ν\n let progressRate = 50 // default\n const projectId = kpiValue.group\n if (projectId && projectRepository) {\n if (progressRateCache.has(projectId)) {\n progressRate = progressRateCache.get(projectId)!\n } else {\n const project = await projectRepository.findOne({ where: { id: projectId } })\n progressRate = project?.totalProgress ?? 50\n progressRateCache.set(projectId, progressRate)\n }\n }\n calculatedScore = calculate2DScore(value, kpi.grades as Grade2DLookup, progressRate)\n } else {\n calculatedScore = calculateScoreFromGrades(value, kpi.grades as KpiGrade[])\n }\n\n if (calculatedScore !== null) {\n // Only update if the score is actually different\n if (kpiValue.score !== calculatedScore) {\n const oldScore = kpiValue.score\n kpiValue.score = calculatedScore\n await kpiValueRepository.save(kpiValue)\n updatedCount++\n\n console.log(` π Value ${value} β Score ${calculatedScore} (was ${oldScore || 'null'})`)\n }\n } else {\n console.log(` β οΈ Value ${value} is below all ranges in lookup table`)\n }\n\n totalProcessed++\n }\n\n console.log(` β
Updated ${updatedCount}/${kpiValues.length} values`)\n totalUpdated += updatedCount\n\n } catch (kpiError) {\n console.log(` β Error processing KPI ${kpi.name}: ${kpiError.message}`)\n errorCount++\n }\n }\n\n console.log(`\\nπ KPI Score Calculation Complete!`)\n console.log(` π KPIs processed: ${kpis.length}`)\n console.log(` π’ Total values processed: ${totalProcessed}`)\n console.log(` β
Scores updated: ${totalUpdated}`)\n console.log(` β Errors: ${errorCount}`)\n\n if (errorCount > 0) {\n console.log(`\\nβ οΈ Some KPIs had errors. Check the logs above for details.`)\n }\n\n } catch (error) {\n console.error(`β Fatal error during score calculation:`, error)\n throw error\n } finally {\n if (connection) {\n await connection.close()\n console.log('π Database connection closed')\n }\n }\n}\n\n/**\n * Calculate score from grades lookup table\n * If exact range not found, use the score of the largest minValue that is <= value\n */\nfunction calculateScoreFromGrades(value: number, grades: KpiGrade[]): number | null {\n // First try to find exact range match\n for (const grade of grades) {\n if (value >= grade.minValue && value <= grade.maxValue) {\n return grade.score || 0\n }\n }\n \n // If no exact match, find the grade with largest minValue that is <= value\n let bestGrade: KpiGrade | null = null\n let bestMinValue = -Infinity\n \n for (const grade of grades) {\n if (grade.minValue <= value && grade.minValue > bestMinValue) {\n bestGrade = grade\n bestMinValue = grade.minValue\n }\n }\n \n if (bestGrade) {\n return bestGrade.score || 0\n }\n \n return null // Value is smaller than all minValues in lookup table\n}\n\n/**\n * List KPIs that have lookup tables (grades)\n */\nexport async function listKpisWithLookupTables(): Promise<void> {\n // Set NODE_ENV if not set\n if (!process.env.NODE_ENV) {\n process.env.NODE_ENV = 'development'\n }\n\n // Initialize Things-Factory environment\n const { config } = require('@things-factory/env')\n const ormconfig = require('@things-factory/shell/dist-server/initializers/ormconfig.js')\n const connectionConfig = config.get('ormconfig')\n\n let connection\n\n try {\n console.log('π Connecting to database...')\n connection = await createConnection({\n ...ormconfig,\n ...connectionConfig,\n logging: false\n })\n\n const { addDataSource } = require('@things-factory/shell')\n addDataSource('default', connection)\n\n const { getRepository } = require('@things-factory/shell')\n const { Kpi } = require('@things-factory/kpi')\n const kpiRepository = getRepository(Kpi)\n\n // Get KPIs with grades\n const kpis = await kpiRepository\n .createQueryBuilder('kpi')\n .leftJoinAndSelect('kpi.domain', 'domain')\n .where('kpi.grades IS NOT NULL')\n .andWhere('domain.name = :domainName', { domainName: 'SYSTEM' })\n .getMany()\n\n console.log(`π KPIs with lookup tables (${kpis.length}):\\n`)\n\n if (kpis.length === 0) {\n console.log(' No KPIs found with lookup tables.')\n return\n }\n\n kpis.forEach((kpi, index) => {\n const gradeCount = kpi.grades ? kpi.grades.length : 0\n console.log(` ${(index + 1).toString().padStart(2)}: ${kpi.name} (${gradeCount} grades)`)\n })\n\n console.log(`\\nπ Total: ${kpis.length} KPIs with lookup tables`)\n\n } catch (error) {\n console.error('β Error listing KPIs:', error)\n } finally {\n if (connection) {\n await connection.close()\n }\n }\n}\n\n/**\n * CLI execution when called directly\n */\nasync function main() {\n const args = process.argv.slice(2)\n\n try {\n if (args.includes('--help') || args.includes('-h')) {\n console.log(`\nπ― KPI Score Calculator\n\nUsage:\n ts-node server/scripts/calculate-kpi-scores.ts [options] [kpiName]\n\nOptions:\n --list, -l List KPIs that have lookup tables\n --force, -f Force recalculate all scores (not just null/zero ones)\n --help, -h Show this help\n\nExamples:\n ts-node server/scripts/calculate-kpi-scores.ts # Calculate scores for null/zero values only\n ts-node server/scripts/calculate-kpi-scores.ts --force # Recalculate ALL scores\n ts-node server/scripts/calculate-kpi-scores.ts \"X11. μ°λ©΄μ λλΉ κ³΅μ¬κΈ°κ°\" # Calculate for specific KPI\n ts-node server/scripts/calculate-kpi-scores.ts --list # List KPIs with lookup tables\n\nNote: By default, only processes kpi-values with null or zero scores.\n Use --force to recalculate all scores.\n `)\n return\n }\n\n if (args.includes('--list') || args.includes('-l')) {\n await listKpisWithLookupTables()\n return\n }\n\n const forceRecalculate = args.includes('--force') || args.includes('-f')\n const specificKpiName = args.find(arg => !arg.startsWith('--'))\n \n if (specificKpiName) {\n console.log(`π― Calculating scores for specific KPI: ${specificKpiName}`)\n console.log(` Mode: ${forceRecalculate ? 'Force recalculate ALL' : 'Only null/zero scores'}`)\n await calculateKpiScores(specificKpiName, forceRecalculate)\n } else {\n console.log(`π― Calculating scores for all KPIs with lookup tables`)\n console.log(` Mode: ${forceRecalculate ? 'Force recalculate ALL' : 'Only null/zero scores'}`)\n await calculateKpiScores(undefined, forceRecalculate)\n }\n\n console.log('\\nβ¨ Done!')\n \n } catch (error) {\n console.error('\\nβ Script failed:', error.message)\n process.exit(1)\n }\n}\n\n// Handle uncaught errors\nprocess.on('unhandledRejection', (error: any) => {\n console.error('β Unhandled error:', error.message || error)\n process.exit(1)\n})\n\n// Run if called directly\nif (require.main === module) {\n main()\n}"]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env ts-node
|
|
2
|
+
/**
|
|
3
|
+
* Load KPI grade data from JSON files - Migration Style
|
|
4
|
+
* This can be called directly from migrations or other server-side scripts
|
|
5
|
+
*/
|
|
6
|
+
export declare function loadKpiGradeData(specificFile?: string): Promise<void>;
|
|
7
|
+
/**
|
|
8
|
+
* X31/X32 KPIλ₯Ό λΉνμ±ν (active = false, grades = null)
|
|
9
|
+
*/
|
|
10
|
+
export declare function deactivateDeletedKpis(): Promise<void>;
|
|
11
|
+
/**
|
|
12
|
+
* List available grade data files
|
|
13
|
+
*/
|
|
14
|
+
export declare function listGradeDataFiles(): string[];
|