@things-factory/kpi 9.0.30 → 9.0.32

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.
Files changed (347) hide show
  1. package/README.md +1 -2
  2. package/client/charts/kpi-boxplot-chart.ts +182 -42
  3. package/client/charts/kpi-mini-trend-chart.ts +125 -0
  4. package/client/charts/kpi-radar-chart.ts +9 -9
  5. package/client/charts/kpi-trend-chart.ts +163 -0
  6. package/client/google-map/common-google-map.ts +45 -7
  7. package/client/google-map/google-map-loader.ts +1 -1
  8. package/client/pages/kpi/kpi-list-page.ts +196 -32
  9. package/client/pages/kpi/kpi-overview.ts +9 -11
  10. package/client/pages/kpi/kpi-tree-page.ts +409 -0
  11. package/client/pages/kpi/kpi-view.ts +187 -0
  12. package/client/pages/kpi-dashboard/cards/kpi-level1-card.ts +1 -1
  13. package/client/pages/kpi-dashboard/cards/kpi-level2-comparison.ts +1 -1
  14. package/client/pages/kpi-dashboard/cards/kpi-level3-comparison.ts +1 -1
  15. package/client/pages/kpi-dashboard/components/kpi-chart-toggle.ts +1 -2
  16. package/client/pages/kpi-dashboard/components/kpi-left-panel.ts +437 -0
  17. package/client/pages/kpi-dashboard/components/kpi-map-panel.ts +243 -30
  18. package/client/pages/kpi-dashboard/components/kpi-region-popup.ts +356 -0
  19. package/client/pages/kpi-dashboard/kpi-dashboard-map.ts +50 -592
  20. package/client/pages/kpi-dashboard/kpi-dashboard.ts +28 -30
  21. package/client/pages/kpi-history/kpi-history-list-page.ts +11 -11
  22. package/client/pages/kpi-metric/kpi-metric-list-page.ts +10 -2
  23. package/client/pages/kpi-metric-value/kpi-metric-value-editor-page.ts +7 -7
  24. package/client/pages/kpi-metric-value/kpi-metric-value-importer.ts +2 -2
  25. package/client/pages/kpi-metric-value/kpi-metric-value-list-page.ts +16 -8
  26. package/client/pages/kpi-metric-value/kpi-metric-value-manual-entry-form.ts +5 -5
  27. package/client/pages/kpi-statistic/kpi-statistic-editor-page.ts +1 -2
  28. package/client/pages/kpi-statistic/kpi-statistic-list-page.ts +10 -2
  29. package/client/pages/kpi-value/kpi-value-editor-page.ts +11 -7
  30. package/client/pages/kpi-value/kpi-value-list-page.ts +31 -7
  31. package/client/route.ts +2 -9
  32. package/design-entities.md +8 -12
  33. package/dist-client/charts/kpi-boxplot-chart.d.ts +2 -0
  34. package/dist-client/charts/kpi-boxplot-chart.js +168 -42
  35. package/dist-client/charts/kpi-boxplot-chart.js.map +1 -1
  36. package/dist-client/charts/kpi-mini-trend-chart.d.ts +14 -0
  37. package/dist-client/charts/kpi-mini-trend-chart.js +148 -0
  38. package/dist-client/charts/kpi-mini-trend-chart.js.map +1 -0
  39. package/dist-client/charts/kpi-radar-chart.js +9 -9
  40. package/dist-client/charts/kpi-radar-chart.js.map +1 -1
  41. package/dist-client/charts/kpi-trend-chart.d.ts +25 -0
  42. package/dist-client/charts/kpi-trend-chart.js +186 -0
  43. package/dist-client/charts/kpi-trend-chart.js.map +1 -0
  44. package/dist-client/google-map/common-google-map.js +40 -7
  45. package/dist-client/google-map/common-google-map.js.map +1 -1
  46. package/dist-client/google-map/google-map-loader.js +1 -1
  47. package/dist-client/google-map/google-map-loader.js.map +1 -1
  48. package/dist-client/pages/kpi/kpi-list-page.d.ts +19 -3
  49. package/dist-client/pages/kpi/kpi-list-page.js +188 -32
  50. package/dist-client/pages/kpi/kpi-list-page.js.map +1 -1
  51. package/dist-client/pages/kpi/kpi-overview.js +9 -11
  52. package/dist-client/pages/kpi/kpi-overview.js.map +1 -1
  53. package/dist-client/pages/kpi/kpi-tree-page.d.ts +59 -0
  54. package/dist-client/pages/kpi/kpi-tree-page.js +403 -0
  55. package/dist-client/pages/kpi/kpi-tree-page.js.map +1 -0
  56. package/dist-client/pages/kpi/kpi-view.d.ts +12 -0
  57. package/dist-client/pages/kpi/kpi-view.js +191 -0
  58. package/dist-client/pages/kpi/kpi-view.js.map +1 -0
  59. package/dist-client/pages/kpi-dashboard/cards/kpi-level1-card.js +1 -1
  60. package/dist-client/pages/kpi-dashboard/cards/kpi-level1-card.js.map +1 -1
  61. package/dist-client/pages/kpi-dashboard/cards/kpi-level2-comparison.js +1 -1
  62. package/dist-client/pages/kpi-dashboard/cards/kpi-level2-comparison.js.map +1 -1
  63. package/dist-client/pages/kpi-dashboard/cards/kpi-level3-comparison.js +1 -1
  64. package/dist-client/pages/kpi-dashboard/cards/kpi-level3-comparison.js.map +1 -1
  65. package/dist-client/pages/kpi-dashboard/components/kpi-chart-toggle.js +1 -2
  66. package/dist-client/pages/kpi-dashboard/components/kpi-chart-toggle.js.map +1 -1
  67. package/dist-client/pages/kpi-dashboard/components/kpi-left-panel.d.ts +24 -0
  68. package/dist-client/pages/kpi-dashboard/components/kpi-left-panel.js +440 -0
  69. package/dist-client/pages/kpi-dashboard/components/kpi-left-panel.js.map +1 -0
  70. package/dist-client/pages/kpi-dashboard/components/kpi-map-panel.d.ts +11 -1
  71. package/dist-client/pages/kpi-dashboard/components/kpi-map-panel.js +243 -22
  72. package/dist-client/pages/kpi-dashboard/components/kpi-map-panel.js.map +1 -1
  73. package/dist-client/pages/kpi-dashboard/components/kpi-region-popup.d.ts +23 -0
  74. package/dist-client/pages/kpi-dashboard/components/kpi-region-popup.js +369 -0
  75. package/dist-client/pages/kpi-dashboard/components/kpi-region-popup.js.map +1 -0
  76. package/dist-client/pages/kpi-dashboard/kpi-dashboard-map.d.ts +6 -15
  77. package/dist-client/pages/kpi-dashboard/kpi-dashboard-map.js +47 -588
  78. package/dist-client/pages/kpi-dashboard/kpi-dashboard-map.js.map +1 -1
  79. package/dist-client/pages/kpi-dashboard/kpi-dashboard.js +28 -30
  80. package/dist-client/pages/kpi-dashboard/kpi-dashboard.js.map +1 -1
  81. package/dist-client/pages/kpi-history/kpi-history-list-page.d.ts +6 -1
  82. package/dist-client/pages/kpi-history/kpi-history-list-page.js +11 -11
  83. package/dist-client/pages/kpi-history/kpi-history-list-page.js.map +1 -1
  84. package/dist-client/pages/kpi-metric/kpi-metric-list-page.d.ts +5 -0
  85. package/dist-client/pages/kpi-metric/kpi-metric-list-page.js +10 -2
  86. package/dist-client/pages/kpi-metric/kpi-metric-list-page.js.map +1 -1
  87. package/dist-client/pages/kpi-metric-value/kpi-metric-value-editor-page.d.ts +1 -1
  88. package/dist-client/pages/kpi-metric-value/kpi-metric-value-editor-page.js +8 -8
  89. package/dist-client/pages/kpi-metric-value/kpi-metric-value-editor-page.js.map +1 -1
  90. package/dist-client/pages/kpi-metric-value/kpi-metric-value-importer.js +2 -2
  91. package/dist-client/pages/kpi-metric-value/kpi-metric-value-importer.js.map +1 -1
  92. package/dist-client/pages/kpi-metric-value/kpi-metric-value-list-page.d.ts +5 -0
  93. package/dist-client/pages/kpi-metric-value/kpi-metric-value-list-page.js +16 -8
  94. package/dist-client/pages/kpi-metric-value/kpi-metric-value-list-page.js.map +1 -1
  95. package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-form.d.ts +1 -1
  96. package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-form.js +6 -6
  97. package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-form.js.map +1 -1
  98. package/dist-client/pages/kpi-statistic/kpi-statistic-editor-page.js +1 -2
  99. package/dist-client/pages/kpi-statistic/kpi-statistic-editor-page.js.map +1 -1
  100. package/dist-client/pages/kpi-statistic/kpi-statistic-list-page.d.ts +5 -0
  101. package/dist-client/pages/kpi-statistic/kpi-statistic-list-page.js +10 -2
  102. package/dist-client/pages/kpi-statistic/kpi-statistic-list-page.js.map +1 -1
  103. package/dist-client/pages/kpi-value/kpi-value-editor-page.d.ts +2 -1
  104. package/dist-client/pages/kpi-value/kpi-value-editor-page.js +16 -8
  105. package/dist-client/pages/kpi-value/kpi-value-editor-page.js.map +1 -1
  106. package/dist-client/pages/kpi-value/kpi-value-list-page.d.ts +5 -0
  107. package/dist-client/pages/kpi-value/kpi-value-list-page.js +31 -7
  108. package/dist-client/pages/kpi-value/kpi-value-list-page.js.map +1 -1
  109. package/dist-client/route.d.ts +1 -1
  110. package/dist-client/route.js +2 -8
  111. package/dist-client/route.js.map +1 -1
  112. package/dist-client/tsconfig.tsbuildinfo +1 -1
  113. package/dist-server/controllers/kpi-metric-value-provider.d.ts +1 -1
  114. package/dist-server/controllers/kpi-metric-value-provider.js +4 -4
  115. package/dist-server/controllers/kpi-metric-value-provider.js.map +1 -1
  116. package/dist-server/controllers/kpi-value-provider.d.ts +1 -1
  117. package/dist-server/controllers/kpi-value-provider.js +3 -3
  118. package/dist-server/controllers/kpi-value-provider.js.map +1 -1
  119. package/dist-server/migrations/1752190849680-seed-kpi-metrics.d.ts +6 -0
  120. package/dist-server/migrations/1752190849680-seed-kpi-metrics.js +101 -0
  121. package/dist-server/migrations/1752190849680-seed-kpi-metrics.js.map +1 -0
  122. package/dist-server/migrations/1752190849681-seed-kpi.d.ts +5 -0
  123. package/dist-server/migrations/1752190849681-seed-kpi.js +315 -0
  124. package/dist-server/migrations/1752190849681-seed-kpi.js.map +1 -0
  125. package/dist-server/migrations/1752192090123-add-grades-to-kpi.d.ts +7 -0
  126. package/dist-server/migrations/1752192090123-add-grades-to-kpi.js +51 -0
  127. package/dist-server/migrations/1752192090123-add-grades-to-kpi.js.map +1 -0
  128. package/dist-server/migrations/1752192090124-add-kpi-statistics.d.ts +5 -0
  129. package/dist-server/migrations/1752192090124-add-kpi-statistics.js +710 -0
  130. package/dist-server/migrations/1752192090124-add-kpi-statistics.js.map +1 -0
  131. package/dist-server/migrations/1752192090128-seed-kpi-org-scope.d.ts +6 -0
  132. package/dist-server/migrations/1752192090128-seed-kpi-org-scope.js +111 -0
  133. package/dist-server/migrations/1752192090128-seed-kpi-org-scope.js.map +1 -0
  134. package/dist-server/migrations/1752192090129-seed-kpi-values.d.ts +6 -0
  135. package/dist-server/migrations/1752192090129-seed-kpi-values.js +187 -0
  136. package/dist-server/migrations/1752192090129-seed-kpi-values.js.map +1 -0
  137. package/dist-server/migrations/grade-data/x11-performance-table.json +962 -0
  138. package/dist-server/migrations/grade-data/x12-performance-table.json +611 -0
  139. package/dist-server/migrations/grade-data/x14-performance-table.json +42 -0
  140. package/dist-server/migrations/grade-data/x21-performance-table.json +889 -0
  141. package/dist-server/migrations/grade-data/x22-performance-table.json +1064 -0
  142. package/dist-server/migrations/grade-data/x23-performance-table.json +42 -0
  143. package/dist-server/migrations/grade-data/x31-performance-table.json +644 -0
  144. package/dist-server/migrations/grade-data/x32-performance-table.json +993 -0
  145. package/dist-server/migrations/grade-data/x33-performance-table.json +195 -0
  146. package/dist-server/migrations/grade-data/x34-performance-table.json +12 -0
  147. package/dist-server/migrations/grade-data/x35-performance-table.json +42 -0
  148. package/dist-server/migrations/grade-data/x41-performance-table.json +825 -0
  149. package/dist-server/migrations/grade-data/x42-performance-table.json +786 -0
  150. package/dist-server/migrations/grade-data/x43-performance-table.json +12 -0
  151. package/dist-server/migrations/grade-data/x44-performance-table.json +42 -0
  152. package/dist-server/migrations/grade-data/x51-performance-table.json +924 -0
  153. package/dist-server/migrations/grade-data/x52-performance-table.json +42 -0
  154. package/dist-server/migrations/grade-data/x61-performance-table.json +261 -0
  155. package/dist-server/migrations/grade-data/x62-performance-table.json +42 -0
  156. package/dist-server/migrations/seed-data/kpi-metrics-seed.json +454 -0
  157. package/dist-server/migrations/seed-data/kpi-org-scope-seed.json +1676 -0
  158. package/dist-server/migrations/seed-data/kpi-values-seed.json +402 -0
  159. package/dist-server/migrations/seed-data/kpis-seed.json +488 -0
  160. package/dist-server/service/index.d.ts +3 -7
  161. package/dist-server/service/index.js +5 -12
  162. package/dist-server/service/index.js.map +1 -1
  163. package/dist-server/service/kpi/aggregate-kpi.js +30 -13
  164. package/dist-server/service/kpi/aggregate-kpi.js.map +1 -1
  165. package/dist-server/service/kpi/kpi-formula.service.d.ts +15 -0
  166. package/dist-server/service/kpi/kpi-formula.service.js +90 -0
  167. package/dist-server/service/kpi/kpi-formula.service.js.map +1 -1
  168. package/dist-server/service/kpi/kpi-history.d.ts +0 -3
  169. package/dist-server/service/kpi/kpi-history.js +0 -10
  170. package/dist-server/service/kpi/kpi-history.js.map +1 -1
  171. package/dist-server/service/kpi/kpi-mutation.d.ts +1 -1
  172. package/dist-server/service/kpi/kpi-mutation.js +57 -20
  173. package/dist-server/service/kpi/kpi-mutation.js.map +1 -1
  174. package/dist-server/service/kpi/kpi-query.d.ts +7 -3
  175. package/dist-server/service/kpi/kpi-query.js +126 -10
  176. package/dist-server/service/kpi/kpi-query.js.map +1 -1
  177. package/dist-server/service/kpi/kpi-type.d.ts +4 -2
  178. package/dist-server/service/kpi/kpi-type.js +12 -4
  179. package/dist-server/service/kpi/kpi-type.js.map +1 -1
  180. package/dist-server/service/kpi/kpi.d.ts +4 -3
  181. package/dist-server/service/kpi/kpi.js +20 -8
  182. package/dist-server/service/kpi/kpi.js.map +1 -1
  183. package/dist-server/service/kpi-metric/aggregate-kpi-metric.js +46 -11
  184. package/dist-server/service/kpi-metric/aggregate-kpi-metric.js.map +1 -1
  185. package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.d.ts +1 -1
  186. package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.js +6 -6
  187. package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.js.map +1 -1
  188. package/dist-server/service/kpi-metric-value/kpi-metric-value-type.d.ts +2 -2
  189. package/dist-server/service/kpi-metric-value/kpi-metric-value-type.js +4 -4
  190. package/dist-server/service/kpi-metric-value/kpi-metric-value-type.js.map +1 -1
  191. package/dist-server/service/kpi-metric-value/kpi-metric-value.d.ts +1 -1
  192. package/dist-server/service/kpi-metric-value/kpi-metric-value.js +3 -3
  193. package/dist-server/service/kpi-metric-value/kpi-metric-value.js.map +1 -1
  194. package/dist-server/service/kpi-org-scope/index.d.ts +9 -0
  195. package/dist-server/service/kpi-org-scope/index.js +14 -0
  196. package/dist-server/service/kpi-org-scope/index.js.map +1 -0
  197. package/dist-server/service/kpi-org-scope/kpi-org-scope-mutation.d.ts +8 -0
  198. package/dist-server/service/kpi-org-scope/kpi-org-scope-mutation.js +170 -0
  199. package/dist-server/service/kpi-org-scope/kpi-org-scope-mutation.js.map +1 -0
  200. package/dist-server/service/kpi-org-scope/kpi-org-scope-query.d.ts +14 -0
  201. package/dist-server/service/kpi-org-scope/kpi-org-scope-query.js +152 -0
  202. package/dist-server/service/kpi-org-scope/kpi-org-scope-query.js.map +1 -0
  203. package/dist-server/service/kpi-org-scope/kpi-org-scope-type.d.ts +26 -0
  204. package/dist-server/service/kpi-org-scope/kpi-org-scope-type.js +101 -0
  205. package/dist-server/service/kpi-org-scope/kpi-org-scope-type.js.map +1 -0
  206. package/dist-server/service/kpi-org-scope/kpi-org-scope.d.ts +26 -0
  207. package/dist-server/service/kpi-org-scope/kpi-org-scope.js +135 -0
  208. package/dist-server/service/kpi-org-scope/kpi-org-scope.js.map +1 -0
  209. package/dist-server/service/kpi-statistic/kpi-statistic.d.ts +1 -0
  210. package/dist-server/service/kpi-statistic/kpi-statistic.js +11 -0
  211. package/dist-server/service/kpi-statistic/kpi-statistic.js.map +1 -1
  212. package/dist-server/service/kpi-value/kpi-value-mutation.js +71 -7
  213. package/dist-server/service/kpi-value/kpi-value-mutation.js.map +1 -1
  214. package/dist-server/service/kpi-value/kpi-value-type.d.ts +4 -2
  215. package/dist-server/service/kpi-value/kpi-value-type.js +12 -4
  216. package/dist-server/service/kpi-value/kpi-value-type.js.map +1 -1
  217. package/dist-server/service/kpi-value/kpi-value.d.ts +3 -1
  218. package/dist-server/service/kpi-value/kpi-value.js +11 -5
  219. package/dist-server/service/kpi-value/kpi-value.js.map +1 -1
  220. package/dist-server/service/utils/value-date-util.d.ts +1 -0
  221. package/dist-server/service/utils/value-date-util.js +41 -0
  222. package/dist-server/service/utils/value-date-util.js.map +1 -1
  223. package/dist-server/tsconfig.json +10 -0
  224. package/dist-server/tsconfig.tsbuildinfo +1 -1
  225. package/package.json +7 -6
  226. package/server/@types/index.d.ts +11 -0
  227. package/server/controllers/kpi-metric-value-provider.ts +5 -5
  228. package/server/controllers/kpi-value-provider.ts +4 -4
  229. package/server/migrations/1752190849680-seed-kpi-metrics.ts +124 -0
  230. package/server/migrations/1752190849681-seed-kpi.ts +356 -0
  231. package/server/migrations/1752192090123-add-grades-to-kpi.ts +67 -0
  232. package/server/migrations/1752192090124-add-kpi-statistics.ts +719 -0
  233. package/server/migrations/1752192090128-seed-kpi-org-scope.ts +132 -0
  234. package/server/migrations/1752192090129-seed-kpi-values.ts +207 -0
  235. package/server/migrations/grade-data/x11-performance-table.json +962 -0
  236. package/server/migrations/grade-data/x12-performance-table.json +611 -0
  237. package/server/migrations/grade-data/x14-performance-table.json +42 -0
  238. package/server/migrations/grade-data/x21-performance-table.json +889 -0
  239. package/server/migrations/grade-data/x22-performance-table.json +1064 -0
  240. package/server/migrations/grade-data/x23-performance-table.json +42 -0
  241. package/server/migrations/grade-data/x31-performance-table.json +644 -0
  242. package/server/migrations/grade-data/x32-performance-table.json +993 -0
  243. package/server/migrations/grade-data/x33-performance-table.json +195 -0
  244. package/server/migrations/grade-data/x34-performance-table.json +12 -0
  245. package/server/migrations/grade-data/x35-performance-table.json +42 -0
  246. package/server/migrations/grade-data/x41-performance-table.json +825 -0
  247. package/server/migrations/grade-data/x42-performance-table.json +786 -0
  248. package/server/migrations/grade-data/x43-performance-table.json +12 -0
  249. package/server/migrations/grade-data/x44-performance-table.json +42 -0
  250. package/server/migrations/grade-data/x51-performance-table.json +924 -0
  251. package/server/migrations/grade-data/x52-performance-table.json +42 -0
  252. package/server/migrations/grade-data/x61-performance-table.json +261 -0
  253. package/server/migrations/grade-data/x62-performance-table.json +42 -0
  254. package/server/migrations/seed-data/kpi-metrics-seed.json +454 -0
  255. package/server/migrations/seed-data/kpi-org-scope-seed.json +1676 -0
  256. package/server/migrations/seed-data/kpi-values-seed.json +402 -0
  257. package/server/migrations/seed-data/kpis-seed.json +488 -0
  258. package/server/service/index.ts +5 -12
  259. package/server/service/kpi/aggregate-kpi.ts +31 -13
  260. package/server/service/kpi/kpi-formula.service.ts +101 -0
  261. package/server/service/kpi/kpi-history.ts +0 -8
  262. package/server/service/kpi/kpi-mutation.ts +59 -19
  263. package/server/service/kpi/kpi-query.ts +118 -8
  264. package/server/service/kpi/kpi-type.ts +10 -4
  265. package/server/service/kpi/kpi.ts +17 -7
  266. package/server/service/kpi-metric/aggregate-kpi-metric.ts +55 -11
  267. package/server/service/kpi-metric-value/kpi-metric-value-mutation.ts +6 -6
  268. package/server/service/kpi-metric-value/kpi-metric-value-type.ts +4 -4
  269. package/server/service/kpi-metric-value/kpi-metric-value.ts +3 -3
  270. package/server/service/kpi-org-scope/index.ts +11 -0
  271. package/server/service/kpi-org-scope/kpi-org-scope-mutation.ts +173 -0
  272. package/server/service/kpi-org-scope/kpi-org-scope-query.ts +127 -0
  273. package/server/service/kpi-org-scope/kpi-org-scope-type.ts +68 -0
  274. package/server/service/kpi-org-scope/kpi-org-scope.ts +123 -0
  275. package/server/service/kpi-statistic/kpi-statistic.ts +10 -0
  276. package/server/service/kpi-value/kpi-value-mutation.ts +73 -7
  277. package/server/service/kpi-value/kpi-value-type.ts +10 -4
  278. package/server/service/kpi-value/kpi-value.ts +10 -5
  279. package/server/service/utils/value-date-util.ts +47 -0
  280. package/server/types/global.d.ts +8 -0
  281. package/things-factory.config.js +1 -0
  282. package/translations/en.json +15 -3
  283. package/translations/ja.json +13 -3
  284. package/translations/ko.json +15 -3
  285. package/translations/ms.json +13 -3
  286. package/translations/zh.json +13 -3
  287. package/client/google-map/script-loader.ts +0 -173
  288. package/client/pages/kpi-category/kpi-category-importer.ts +0 -90
  289. package/client/pages/kpi-category/kpi-category-list-page.ts +0 -537
  290. package/client/pages/kpi-category/kpi-category-value-calculator.ts +0 -233
  291. package/client/pages/kpi-category-value/kpi-category-value-list-page.ts +0 -404
  292. package/dist-client/google-map/script-loader.d.ts +0 -3
  293. package/dist-client/google-map/script-loader.js +0 -144
  294. package/dist-client/google-map/script-loader.js.map +0 -1
  295. package/dist-client/pages/kpi-category/kpi-category-importer.d.ts +0 -23
  296. package/dist-client/pages/kpi-category/kpi-category-importer.js +0 -92
  297. package/dist-client/pages/kpi-category/kpi-category-importer.js.map +0 -1
  298. package/dist-client/pages/kpi-category/kpi-category-list-page.d.ts +0 -74
  299. package/dist-client/pages/kpi-category/kpi-category-list-page.js +0 -517
  300. package/dist-client/pages/kpi-category/kpi-category-list-page.js.map +0 -1
  301. package/dist-client/pages/kpi-category/kpi-category-value-calculator.d.ts +0 -13
  302. package/dist-client/pages/kpi-category/kpi-category-value-calculator.js +0 -256
  303. package/dist-client/pages/kpi-category/kpi-category-value-calculator.js.map +0 -1
  304. package/dist-client/pages/kpi-category-value/kpi-category-value-list-page.d.ts +0 -63
  305. package/dist-client/pages/kpi-category-value/kpi-category-value-list-page.js +0 -393
  306. package/dist-client/pages/kpi-category-value/kpi-category-value-list-page.js.map +0 -1
  307. package/dist-server/service/kpi-category/index.d.ts +0 -6
  308. package/dist-server/service/kpi-category/index.js +0 -10
  309. package/dist-server/service/kpi-category/index.js.map +0 -1
  310. package/dist-server/service/kpi-category/kpi-category-mutation.d.ts +0 -9
  311. package/dist-server/service/kpi-category/kpi-category-mutation.js +0 -221
  312. package/dist-server/service/kpi-category/kpi-category-mutation.js.map +0 -1
  313. package/dist-server/service/kpi-category/kpi-category-query.d.ts +0 -18
  314. package/dist-server/service/kpi-category/kpi-category-query.js +0 -115
  315. package/dist-server/service/kpi-category/kpi-category-query.js.map +0 -1
  316. package/dist-server/service/kpi-category/kpi-category-type.d.ts +0 -24
  317. package/dist-server/service/kpi-category/kpi-category-type.js +0 -100
  318. package/dist-server/service/kpi-category/kpi-category-type.js.map +0 -1
  319. package/dist-server/service/kpi-category/kpi-category.d.ts +0 -22
  320. package/dist-server/service/kpi-category/kpi-category.js +0 -106
  321. package/dist-server/service/kpi-category/kpi-category.js.map +0 -1
  322. package/dist-server/service/kpi-category-value/index.d.ts +0 -6
  323. package/dist-server/service/kpi-category-value/index.js +0 -10
  324. package/dist-server/service/kpi-category-value/index.js.map +0 -1
  325. package/dist-server/service/kpi-category-value/kpi-category-value-mutation.d.ts +0 -8
  326. package/dist-server/service/kpi-category-value/kpi-category-value-mutation.js +0 -102
  327. package/dist-server/service/kpi-category-value/kpi-category-value-mutation.js.map +0 -1
  328. package/dist-server/service/kpi-category-value/kpi-category-value-query.d.ts +0 -13
  329. package/dist-server/service/kpi-category-value/kpi-category-value-query.js +0 -91
  330. package/dist-server/service/kpi-category-value/kpi-category-value-query.js.map +0 -1
  331. package/dist-server/service/kpi-category-value/kpi-category-value-type.d.ts +0 -19
  332. package/dist-server/service/kpi-category-value/kpi-category-value-type.js +0 -73
  333. package/dist-server/service/kpi-category-value/kpi-category-value-type.js.map +0 -1
  334. package/dist-server/service/kpi-category-value/kpi-category-value.d.ts +0 -19
  335. package/dist-server/service/kpi-category-value/kpi-category-value.js +0 -91
  336. package/dist-server/service/kpi-category-value/kpi-category-value.js.map +0 -1
  337. package/helps/kpi/kpi-category.md +0 -160
  338. package/server/service/kpi-category/index.ts +0 -7
  339. package/server/service/kpi-category/kpi-category-mutation.ts +0 -217
  340. package/server/service/kpi-category/kpi-category-query.ts +0 -87
  341. package/server/service/kpi-category/kpi-category-type.ts +0 -73
  342. package/server/service/kpi-category/kpi-category.ts +0 -95
  343. package/server/service/kpi-category-value/index.ts +0 -7
  344. package/server/service/kpi-category-value/kpi-category-value-mutation.ts +0 -88
  345. package/server/service/kpi-category-value/kpi-category-value-query.ts +0 -62
  346. package/server/service/kpi-category-value/kpi-category-value-type.ts +0 -48
  347. package/server/service/kpi-category-value/kpi-category-value.ts +0 -79
@@ -1 +1 @@
1
- {"version":3,"file":"aggregate-kpi.js","sourceRoot":"","sources":["../../../server/service/kpi/aggregate-kpi.ts"],"names":[],"mappings":";;AAeA,8CAqEC;AApFD,iDAAqD;AACrD,+BAA2B;AAC3B,yDAAoD;AACpD,sDAAoE;AACpE,+DAAyD;AACzD,6EAA4E;AAC5E,kFAA2E;AAE3E;;;;;;GAMG;AACI,KAAK,UAAU,iBAAiB,CAAC,KAAa,EAAE,QAAgB,EAAE,OAAwB;IAC/F,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,EAAE,EAAE,IAAI,IAAA,qBAAa,EAAC,SAAG,CAAC,CAAC,OAAO,CAAA;IAC1D,MAAM,YAAY,GAAG,IAAI,8CAAoB,EAAE,CAAA;IAE/C,eAAe;IACf,MAAM,GAAG,GAAG,MAAM,IAAA,qBAAa,EAAC,SAAG,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAA;IAChG,IAAI,CAAC,GAAG;QAAE,MAAM,IAAI,KAAK,CAAC,WAAW,CAAC,CAAA;IACtC,IAAI,CAAC,GAAG,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,WAAW,CAAC,CAAA;IAC7C,IAAI,CAAC,GAAG,CAAC,OAAO;QAAE,MAAM,IAAI,KAAK,CAAC,gBAAgB,CAAC,CAAA;IAEnD,oCAAoC;IACpC,MAAM,cAAc,GAAG,IAAI,uCAAiB,EAAE,CAAA;IAC9C,MAAM,WAAW,GAAG,cAAc,CAAC,kBAAkB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;IAClE,MAAM,YAAY,GAA0B,EAAE,CAAA;IAC9C,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;QAC/B,kBAAkB;QAClB,MAAM,MAAM,GAAG,MAAM,IAAA,qBAAa,EAAC,sBAAS,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAA;QAC1G,IAAI,CAAC,MAAM;YAAE,MAAM,IAAI,KAAK,CAAC,uBAAuB,IAAI,aAAa,CAAC,CAAA;QACtE,YAAY,CAAC,IAAI,CAAC,GAAG,MAAM,IAAA,8CAAuB,EAAC,MAAM,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAA;IAClF,CAAC;IACD,mDAAmD;IACnD,MAAM,QAAQ,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IAC3D,MAAM,QAAQ,GAAwB,EAAE,CAAA;IACxC,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;QAC/B,KAAK,MAAM,CAAC,IAAI,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC;YACnC,MAAM,GAAG,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAA;YACvB,QAAQ,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAA;YACtD,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,CAAA;QACvC,CAAC;IACH,CAAC;IACD,uBAAuB;IACvB,MAAM,WAAW,GAAG,EAAE,CAAA;IACtB,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC3B,MAAM,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,CAAA;QACjC,IAAI,KAAK,GAAG,IAAI,CAAA;QAChB,IAAI,CAAC;YACH,KAAK,GAAG,QAAQ,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,WAAW,GAAG,CAAC,OAAO,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAA;QACzF,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,KAAK,GAAG,IAAI,CAAA;QACd,CAAC;QACD,MAAM,SAAS,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,CAAA;QACpC,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,KAAK,CAAA;QACjC,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,IAAI,CAAC,CAAA;QAChC,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,CAAC,KAAK,CAAC;YAAE,SAAQ;QAC3C,oDAAoD;QACpD,MAAM,IAAI,GAAG,IAAA,qBAAa,EAAC,oBAAQ,EAAE,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAA;QACvD,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC;YAClC,KAAK,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE;SACpF,CAAC,CAAA;QACF,IAAI,MAAM,GAAG,QAAQ,IAAI,IAAI,CAAC,MAAM,EAAE,CAAA;QACtC,MAAM,CAAC,GAAG,GAAG,GAAG,CAAA;QAChB,MAAM,CAAC,KAAK,GAAG,GAAG,CAAC,EAAE,CAAA;QACrB,MAAM,CAAC,OAAO,GAAG,OAAO,CAAA;QACxB,MAAM,CAAC,SAAS,GAAG,SAAS,CAAA;QAC5B,MAAM,CAAC,KAAK,GAAG,KAAK,CAAA;QACpB,MAAM,CAAC,KAAK,GAAG,KAAK,CAAA;QACpB,MAAM,CAAC,SAAS,GAAG,6BAAiB,CAAC,IAAI,CAAA;QACzC,MAAM,CAAC,MAAM,GAAG,MAAM,CAAA;QACtB,MAAM,CAAC,MAAM,GAAG,GAAG,CAAC,MAAM,CAAA;QAC1B,MAAM,CAAC,OAAO,GAAG,OAAO,CAAC,KAAK,EAAE,IAAI,CAAA;QACpC,MAAM,CAAC,OAAO,GAAG,OAAO,CAAC,KAAK,EAAE,IAAI,CAAA;QAEpC,mBAAmB;QACnB,MAAM,YAAY,CAAC,qBAAqB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;QAErD,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;QAChC,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;IAC1B,CAAC;IACD,OAAO,WAAW,CAAA;AACpB,CAAC","sourcesContent":["import { getRepository } from '@things-factory/shell'\nimport { Kpi } from './kpi'\nimport { KpiMetric } from '../kpi-metric/kpi-metric'\nimport { KpiValue, KpiValueInputType } from '../kpi-value/kpi-value'\nimport { KpiFormulaService } from './kpi-formula.service'\nimport { aggregateKpiMetricValue } from '../kpi-metric/aggregate-kpi-metric'\nimport { KpiValueScoreService } from '../kpi-value/kpi-value-score.service'\n\n/**\n * KPI 단위 집계/산식 자동화 함수\n * @param kpiId KPI ID\n * @param domainId 도메인 ID\n * @param context ResolverContext\n * @returns 저장된 KPI Value 배열\n */\nexport async function aggregateKpiValue(kpiId: string, domainId: string, context: ResolverContext) {\n const tx = context.state?.tx || getRepository(Kpi).manager\n const scoreService = new KpiValueScoreService()\n\n // 1. KPI 정보 조회\n const kpi = await getRepository(Kpi).findOne({ where: { id: kpiId, domain: { id: domainId } } })\n if (!kpi) throw new Error('KPI 정보 없음')\n if (!kpi.active) throw new Error('비활성화된 KPI')\n if (!kpi.formula) throw new Error('KPI formula 없음')\n\n // 2. formula 파싱 및 metric code별 값 집계\n const formulaService = new KpiFormulaService()\n const metricCodes = formulaService.extractMetricCodes(kpi.formula)\n const codeValueMap: Record<string, any[]> = {}\n for (const code of metricCodes) {\n // code로 metric 찾기\n const metric = await getRepository(KpiMetric).findOne({ where: { name: code, domain: { id: domainId } } })\n if (!metric) throw new Error(`KPI formula metric '${code}' not found`)\n codeValueMap[code] = await aggregateKpiMetricValue(metric.id, domainId, context)\n }\n // group/date/period별로 값 매핑(가장 최근 기준, group key 조합)\n const groupKey = v => [v.date, v.period, v.group].join('|')\n const groupMap: Record<string, any> = {}\n for (const code of metricCodes) {\n for (const v of codeValueMap[code]) {\n const key = groupKey(v)\n groupMap[key] = groupMap[key] || { ...v, _values: {} }\n groupMap[key]._values[code] = v.value\n }\n }\n // formula 계산 (js eval)\n const savedValues = []\n for (const key in groupMap) {\n const ctx = groupMap[key]._values\n let value = null\n try {\n value = Function(...Object.keys(ctx), `return (${kpi.formula})`)(...Object.values(ctx))\n } catch (e) {\n value = null\n }\n const valueDate = groupMap[key].date\n const group = groupMap[key].group\n const version = kpi.version || 1\n if (value == null || isNaN(value)) continue\n // upsert(동일 KPI, valueDate, group, version) 기준으로 저장\n const repo = getRepository(KpiValue, context.state?.tx)\n const existing = await repo.findOne({\n where: { kpi: { id: kpi.id }, valueDate, group, version, domain: { id: domainId } }\n })\n let entity = existing || repo.create()\n entity.kpi = kpi\n entity.kpiId = kpi.id\n entity.version = version\n entity.valueDate = valueDate\n entity.value = value\n entity.group = group\n entity.inputType = KpiValueInputType.AUTO\n entity.source = 'AUTO'\n entity.domain = kpi.domain\n entity.creator = context.state?.user\n entity.updater = context.state?.user\n\n // 성과 점수 자동 계산 및 저장\n await scoreService.calculateAndSaveScore(entity, kpi)\n\n entity = await repo.save(entity)\n savedValues.push(entity)\n }\n return savedValues\n}\n"]}
1
+ {"version":3,"file":"aggregate-kpi.js","sourceRoot":"","sources":["../../../server/service/kpi/aggregate-kpi.ts"],"names":[],"mappings":"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","sourcesContent":["import { getRepository } from '@things-factory/shell'\nimport { Kpi } from './kpi'\nimport { KpiMetric } from '../kpi-metric/kpi-metric'\nimport { KpiValue, KpiValueInputType } from '../kpi-value/kpi-value'\nimport { KpiOrgScope } from '../kpi-org-scope/kpi-org-scope'\nimport { KpiFormulaService } from './kpi-formula.service'\nimport { aggregateKpiMetricValue } from '../kpi-metric/aggregate-kpi-metric'\nimport { KpiValueScoreService } from '../kpi-value/kpi-value-score.service'\n\n/**\n * KPI 단위 집계/산식 자동화 함수\n * @param kpiId KPI ID\n * @param domainId 도메인 ID\n * @param context ResolverContext\n * @returns 저장된 KPI Value 배열\n */\nexport async function aggregateKpiValue(kpiId: string, domainId: string, context: ResolverContext) {\n const tx = context.state?.tx || getRepository(Kpi).manager\n const scoreService = new KpiValueScoreService()\n\n // 1. KPI 정보 조회\n const kpi = await getRepository(Kpi).findOne({ where: { id: kpiId, domain: { id: domainId } } })\n if (!kpi) throw new Error('KPI 정보 없음')\n if (!kpi.active) throw new Error('비활성화된 KPI')\n if (!kpi.formula) throw new Error('KPI formula 없음')\n\n // 2. formula 파싱 및 metric code별 값 집계\n const formulaService = new KpiFormulaService()\n const metricCodes = formulaService.extractMetricCodes(kpi.formula)\n const codeValueMap: Record<string, any[]> = {}\n for (const code of metricCodes) {\n // code로 metric 찾기\n const metric = await getRepository(KpiMetric).findOne({ where: { name: code, domain: { id: domainId } } })\n if (!metric) throw new Error(`KPI formula metric '${code}' not found`)\n codeValueMap[code] = await aggregateKpiMetricValue(metric.id, domainId, context)\n }\n // org/date/period별로 값 매핑(가장 최근 기준, org key 조합)\n const orgKey = v => [v.date, v.period, v.org].join('|')\n const orgMap: Record<string, any> = {}\n for (const code of metricCodes) {\n for (const v of codeValueMap[code]) {\n const key = orgKey(v)\n orgMap[key] = orgMap[key] || { ...v, _values: {} }\n orgMap[key]._values[code] = v.value\n }\n }\n // formula 계산 (js eval)\n const savedValues = []\n for (const key in orgMap) {\n const ctx = orgMap[key]._values\n let value = null\n try {\n value = Function(...Object.keys(ctx), `return (${kpi.formula})`)(...Object.values(ctx))\n } catch (e) {\n value = null\n }\n const valueDate = orgMap[key].date\n const org = orgMap[key].org\n const version = kpi.version || 1\n if (value == null || isNaN(value)) continue\n // KpiOrgScope 처리 (org 문자열로 찾기 또는 생성)\n const kpiOrgScopeRepo = getRepository(KpiOrgScope, context.state?.tx)\n let kpiOrgScope = await kpiOrgScopeRepo.findOne({\n where: { org: org, domain: { id: domainId } }\n })\n if (!kpiOrgScope) {\n // 새 KpiOrgScope 생성\n kpiOrgScope = await kpiOrgScopeRepo.save({\n entityType: 'AutoAggregate',\n entityId: `auto-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,\n entityName: org,\n org: org,\n domain: kpi.domain\n })\n }\n\n // upsert(동일 KPI, valueDate, kpiOrgScope, version) 기준으로 저장\n const repo = getRepository(KpiValue, context.state?.tx)\n const existing = await repo.findOne({\n where: { kpi: { id: kpi.id }, valueDate, kpiOrgScope: { id: kpiOrgScope.id }, version, domain: { id: domainId } }\n })\n let entity = existing || repo.create()\n entity.kpi = kpi\n entity.kpiId = kpi.id\n entity.version = version\n entity.valueDate = valueDate\n entity.value = value\n entity.kpiOrgScope = kpiOrgScope\n entity.kpiOrgScopeId = kpiOrgScope.id\n entity.inputType = KpiValueInputType.AUTO\n entity.source = 'AUTO'\n entity.domain = kpi.domain\n entity.creator = context.state?.user\n entity.updater = context.state?.user\n\n // 성과 점수 자동 계산 및 저장\n await scoreService.calculateAndSaveScore(entity, kpi)\n\n entity = await repo.save(entity)\n savedValues.push(entity)\n }\n return savedValues\n}\n"]}
@@ -21,4 +21,19 @@ export declare class KpiFormulaService {
21
21
  valid: boolean;
22
22
  errors: string[];
23
23
  }>;
24
+ /**
25
+ * 계층 구조 KPI의 값을 자식 KPI들로부터 집계 계산
26
+ * @param kpiId 부모 KPI ID
27
+ * @param valueDate 계산 대상 날짜
28
+ * @param org 조직 단위
29
+ * @returns Promise<number | null> 집계된 값
30
+ */
31
+ calculateHierarchicalValue(kpiId: string, valueDate: string, org?: string): Promise<number | null>;
32
+ /**
33
+ * KPI가 순환 참조를 생성하는지 확인
34
+ * @param kpiId KPI ID
35
+ * @param parentId 설정하려는 부모 KPI ID
36
+ * @returns Promise<boolean> 순환 참조 여부
37
+ */
38
+ hasCircularReference(kpiId: string, parentId: string): Promise<boolean>;
24
39
  }
@@ -3,6 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.KpiFormulaService = void 0;
4
4
  const shell_1 = require("@things-factory/shell");
5
5
  const kpi_metric_1 = require("../kpi-metric/kpi-metric");
6
+ const kpi_1 = require("./kpi");
7
+ const kpi_value_1 = require("../kpi-value/kpi-value");
8
+ const kpi_org_scope_1 = require("../kpi-org-scope/kpi-org-scope");
6
9
  /**
7
10
  * KPI formula 파싱/검증/매핑 유효성 검사 서비스
8
11
  * - formula에서 Metric 코드(변수명) 추출
@@ -59,6 +62,93 @@ class KpiFormulaService {
59
62
  // ...
60
63
  return { valid: errors.length === 0, errors };
61
64
  }
65
+ /**
66
+ * 계층 구조 KPI의 값을 자식 KPI들로부터 집계 계산
67
+ * @param kpiId 부모 KPI ID
68
+ * @param valueDate 계산 대상 날짜
69
+ * @param org 조직 단위
70
+ * @returns Promise<number | null> 집계된 값
71
+ */
72
+ async calculateHierarchicalValue(kpiId, valueDate, org) {
73
+ const kpiRepo = (0, shell_1.getRepository)(kpi_1.Kpi);
74
+ const kpi = await kpiRepo.findOne({
75
+ where: { id: kpiId },
76
+ relations: ['children']
77
+ });
78
+ if (!kpi || !kpi.children || kpi.children.length === 0) {
79
+ return null;
80
+ }
81
+ const childValues = [];
82
+ const childWeights = [];
83
+ for (const child of kpi.children) {
84
+ let childValue = null;
85
+ if (child.isLeaf) {
86
+ // Leaf KPI인 경우 KpiValue에서 실제 값을 가져옴
87
+ const kpiValueRepo = (0, shell_1.getRepository)(kpi_value_1.KpiValue);
88
+ let kpiValue = null;
89
+ if (org) {
90
+ const kpiOrgScope = await (0, shell_1.getRepository)(kpi_org_scope_1.KpiOrgScope).findOne({
91
+ where: { org: org, domain: { id: child.domain?.id } }
92
+ });
93
+ if (kpiOrgScope) {
94
+ kpiValue = await kpiValueRepo.findOne({
95
+ where: {
96
+ kpi: { id: child.id },
97
+ valueDate,
98
+ kpiOrgScope: { id: kpiOrgScope.id }
99
+ }
100
+ });
101
+ }
102
+ }
103
+ else {
104
+ // org가 없는 경우 kpiOrgScope 없이 조회
105
+ kpiValue = await kpiValueRepo.findOne({
106
+ where: {
107
+ kpi: { id: child.id },
108
+ valueDate,
109
+ kpiOrgScope: null
110
+ }
111
+ });
112
+ }
113
+ childValue = kpiValue?.value || null;
114
+ }
115
+ else {
116
+ // 중간 노드인 경우 재귀적으로 계산
117
+ childValue = await this.calculateHierarchicalValue(child.id, valueDate, org);
118
+ }
119
+ if (childValue !== null) {
120
+ childValues.push(childValue);
121
+ childWeights.push(child.weight || 1);
122
+ }
123
+ }
124
+ if (childValues.length === 0) {
125
+ return null;
126
+ }
127
+ // 가중 평균 계산
128
+ const totalWeight = childWeights.reduce((sum, weight) => sum + weight, 0);
129
+ const weightedSum = childValues.reduce((sum, value, index) => sum + value * childWeights[index], 0);
130
+ return totalWeight > 0 ? weightedSum / totalWeight : null;
131
+ }
132
+ /**
133
+ * KPI가 순환 참조를 생성하는지 확인
134
+ * @param kpiId KPI ID
135
+ * @param parentId 설정하려는 부모 KPI ID
136
+ * @returns Promise<boolean> 순환 참조 여부
137
+ */
138
+ async hasCircularReference(kpiId, parentId) {
139
+ if (kpiId === parentId) {
140
+ return true;
141
+ }
142
+ const kpiRepo = (0, shell_1.getRepository)(kpi_1.Kpi);
143
+ const parent = await kpiRepo.findOne({
144
+ where: { id: parentId },
145
+ relations: ['parent']
146
+ });
147
+ if (!parent || !parent.parent) {
148
+ return false;
149
+ }
150
+ return await this.hasCircularReference(kpiId, parent.parent.id);
151
+ }
62
152
  }
63
153
  exports.KpiFormulaService = KpiFormulaService;
64
154
  //# sourceMappingURL=kpi-formula.service.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"kpi-formula.service.js","sourceRoot":"","sources":["../../../server/service/kpi/kpi-formula.service.ts"],"names":[],"mappings":";;;AAAA,iDAAqD;AACrD,yDAAoD;AAEpD;;;;;GAKG;AACH,MAAa,iBAAiB;IAC5B;;;;OAIG;IACH,kBAAkB,CAAC,OAAe;QAChC,sCAAsC;QACtC,MAAM,KAAK,GAAG,yBAAyB,CAAA;QACvC,wBAAwB;QACxB,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;QACnE,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAA;IACrH,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,eAAe,CACnB,OAAe,EACf,UAAuB,IAAI,GAAG,EAAE;QAEhC,MAAM,MAAM,GAAa,EAAE,CAAA;QAC3B,MAAM,WAAW,GAAG,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAA;QACpD,MAAM,UAAU,GAAG,IAAA,qBAAa,EAAC,sBAAS,CAAC,CAAA;QAC3C,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;YAC/B,IAAI,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;gBACtB,MAAM,CAAC,IAAI,CAAC,YAAY,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,EAAE,CAAC,CAAA;gBACpE,SAAQ;YACV,CAAC;YACD,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;YACjB,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC,CAAA;YAClE,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,MAAM,CAAC,IAAI,CAAC,WAAW,IAAI,mBAAmB,CAAC,CAAA;gBAC/C,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;gBACpB,SAAQ;YACV,CAAC;YACD,IAAI,CAAC,MAAM,CAAC,SAAS,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;gBAC3C,MAAM,CAAC,IAAI,CAAC,WAAW,IAAI,qCAAqC,CAAC,CAAA;YACnE,CAAC;YACD,yCAAyC;YACzC,IAAK,MAAc,CAAC,OAAO,EAAE,CAAC;gBAC5B,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,eAAe,CAAE,MAAc,CAAC,OAAO,EAAE,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAA;gBACvF,IAAI,CAAC,SAAS,CAAC,KAAK;oBAAE,MAAM,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,MAAM,CAAC,CAAA;YACxD,CAAC;YACD,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;QACtB,CAAC;QACD,wCAAwC;QACxC,MAAM;QACN,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;IAC/C,CAAC;CACF;AArDD,8CAqDC","sourcesContent":["import { getRepository } from '@things-factory/shell'\nimport { KpiMetric } from '../kpi-metric/kpi-metric'\n\n/**\n * KPI formula 파싱/검증/매핑 유효성 검사 서비스\n * - formula에서 Metric 코드(변수명) 추출\n * - 각 Metric의 존재/매핑 유효성 검사\n * - 구문 오류, 미정의 Metric, 매핑 오류 등 에러 리포팅\n */\nexport class KpiFormulaService {\n /**\n * formula 문자열에서 Metric 코드(변수명) 추출\n * @param formula KPI formula (예: 'defect_count / total_count * 100')\n * @returns string[] 추출된 Metric 코드 리스트\n */\n extractMetricCodes(formula: string): string[] {\n // 변수명: 알파벳/언더스코어로 시작, 숫자/알파벳/언더스코어 포함\n const regex = /[a-zA-Z_][a-zA-Z0-9_]*/g\n // 숫자/예약어/연산자 제외(후처리 필요)\n const reserved = new Set(['if', 'else', 'return', 'true', 'false'])\n return Array.from(new Set((formula.match(regex) || []).filter(code => isNaN(Number(code)) && !reserved.has(code))))\n }\n\n /**\n * formula 내 Metric 코드의 존재/매핑 유효성 검사 + 순환참조 검출\n * @param formula KPI formula\n * @param visited 순환참조 검출용 Set (재귀 호출 시 사용)\n * @returns { valid: boolean, errors: string[] }\n */\n async validateFormula(\n formula: string,\n visited: Set<string> = new Set()\n ): Promise<{ valid: boolean; errors: string[] }> {\n const errors: string[] = []\n const metricCodes = this.extractMetricCodes(formula)\n const metricRepo = getRepository(KpiMetric)\n for (const code of metricCodes) {\n if (visited.has(code)) {\n errors.push(`순환참조 감지: ${Array.from(visited).join(' → ')} → ${code}`)\n continue\n }\n visited.add(code)\n const metric = await metricRepo.findOne({ where: { name: code } })\n if (!metric) {\n errors.push(`Metric '${code}' is not defined.`)\n visited.delete(code)\n continue\n }\n if (!metric.dataSetId || !metric.fieldName) {\n errors.push(`Metric '${code}' is not mapped to a dataset field.`)\n }\n // metric이 formula를 가지고 있다면 재귀적으로 순환참조 검증\n if ((metric as any).formula) {\n const subResult = await this.validateFormula((metric as any).formula, new Set(visited))\n if (!subResult.valid) errors.push(...subResult.errors)\n }\n visited.delete(code)\n }\n // (선택) formula 구문 오류, 괄호 불일치 등 추가 검사 가능\n // ...\n return { valid: errors.length === 0, errors }\n }\n}\n"]}
1
+ {"version":3,"file":"kpi-formula.service.js","sourceRoot":"","sources":["../../../server/service/kpi/kpi-formula.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { getRepository } from '@things-factory/shell'\nimport { KpiMetric } from '../kpi-metric/kpi-metric'\nimport { Kpi } from './kpi'\nimport { KpiValue } from '../kpi-value/kpi-value'\nimport { KpiOrgScope } from '../kpi-org-scope/kpi-org-scope'\n\n/**\n * KPI formula 파싱/검증/매핑 유효성 검사 서비스\n * - formula에서 Metric 코드(변수명) 추출\n * - 각 Metric의 존재/매핑 유효성 검사\n * - 구문 오류, 미정의 Metric, 매핑 오류 등 에러 리포팅\n */\nexport class KpiFormulaService {\n /**\n * formula 문자열에서 Metric 코드(변수명) 추출\n * @param formula KPI formula (예: 'defect_count / total_count * 100')\n * @returns string[] 추출된 Metric 코드 리스트\n */\n extractMetricCodes(formula: string): string[] {\n // 변수명: 알파벳/언더스코어로 시작, 숫자/알파벳/언더스코어 포함\n const regex = /[a-zA-Z_][a-zA-Z0-9_]*/g\n // 숫자/예약어/연산자 제외(후처리 필요)\n const reserved = new Set(['if', 'else', 'return', 'true', 'false'])\n return Array.from(new Set((formula.match(regex) || []).filter(code => isNaN(Number(code)) && !reserved.has(code))))\n }\n\n /**\n * formula 내 Metric 코드의 존재/매핑 유효성 검사 + 순환참조 검출\n * @param formula KPI formula\n * @param visited 순환참조 검출용 Set (재귀 호출 시 사용)\n * @returns { valid: boolean, errors: string[] }\n */\n async validateFormula(\n formula: string,\n visited: Set<string> = new Set()\n ): Promise<{ valid: boolean; errors: string[] }> {\n const errors: string[] = []\n const metricCodes = this.extractMetricCodes(formula)\n const metricRepo = getRepository(KpiMetric)\n for (const code of metricCodes) {\n if (visited.has(code)) {\n errors.push(`순환참조 감지: ${Array.from(visited).join(' → ')} → ${code}`)\n continue\n }\n visited.add(code)\n const metric = await metricRepo.findOne({ where: { name: code } })\n if (!metric) {\n errors.push(`Metric '${code}' is not defined.`)\n visited.delete(code)\n continue\n }\n if (!metric.dataSetId || !metric.fieldName) {\n errors.push(`Metric '${code}' is not mapped to a dataset field.`)\n }\n // metric이 formula를 가지고 있다면 재귀적으로 순환참조 검증\n if ((metric as any).formula) {\n const subResult = await this.validateFormula((metric as any).formula, new Set(visited))\n if (!subResult.valid) errors.push(...subResult.errors)\n }\n visited.delete(code)\n }\n // (선택) formula 구문 오류, 괄호 불일치 등 추가 검사 가능\n // ...\n return { valid: errors.length === 0, errors }\n }\n\n /**\n * 계층 구조 KPI의 값을 자식 KPI들로부터 집계 계산\n * @param kpiId 부모 KPI ID\n * @param valueDate 계산 대상 날짜\n * @param org 조직 단위\n * @returns Promise<number | null> 집계된 값\n */\n async calculateHierarchicalValue(kpiId: string, valueDate: string, org?: string): Promise<number | null> {\n const kpiRepo = getRepository(Kpi)\n const kpi = await kpiRepo.findOne({\n where: { id: kpiId },\n relations: ['children']\n })\n\n if (!kpi || !kpi.children || kpi.children.length === 0) {\n return null\n }\n\n const childValues: number[] = []\n const childWeights: number[] = []\n\n for (const child of kpi.children) {\n let childValue: number | null = null\n \n if (child.isLeaf) {\n // Leaf KPI인 경우 KpiValue에서 실제 값을 가져옴\n const kpiValueRepo = getRepository(KpiValue)\n let kpiValue: KpiValue | null = null\n if (org) {\n const kpiOrgScope = await getRepository(KpiOrgScope).findOne({\n where: { org: org, domain: { id: child.domain?.id } }\n })\n if (kpiOrgScope) {\n kpiValue = await kpiValueRepo.findOne({ \n where: { \n kpi: { id: child.id }, \n valueDate,\n kpiOrgScope: { id: kpiOrgScope.id }\n }\n })\n }\n } else {\n // org가 없는 경우 kpiOrgScope 없이 조회 \n kpiValue = await kpiValueRepo.findOne({ \n where: { \n kpi: { id: child.id }, \n valueDate,\n kpiOrgScope: null\n }\n })\n }\n childValue = kpiValue?.value || null\n } else {\n // 중간 노드인 경우 재귀적으로 계산\n childValue = await this.calculateHierarchicalValue(child.id, valueDate, org)\n }\n\n if (childValue !== null) {\n childValues.push(childValue)\n childWeights.push(child.weight || 1)\n }\n }\n\n if (childValues.length === 0) {\n return null\n }\n\n // 가중 평균 계산\n const totalWeight = childWeights.reduce((sum, weight) => sum + weight, 0)\n const weightedSum = childValues.reduce((sum, value, index) => sum + value * childWeights[index], 0)\n \n return totalWeight > 0 ? weightedSum / totalWeight : null\n }\n\n /**\n * KPI가 순환 참조를 생성하는지 확인\n * @param kpiId KPI ID\n * @param parentId 설정하려는 부모 KPI ID\n * @returns Promise<boolean> 순환 참조 여부\n */\n async hasCircularReference(kpiId: string, parentId: string): Promise<boolean> {\n if (kpiId === parentId) {\n return true\n }\n\n const kpiRepo = getRepository(Kpi)\n const parent = await kpiRepo.findOne({\n where: { id: parentId },\n relations: ['parent']\n })\n\n if (!parent || !parent.parent) {\n return false\n }\n\n return await this.hasCircularReference(kpiId, parent.parent.id)\n }\n}\n"]}
@@ -2,7 +2,6 @@ import { HistoryActionType, HistoryEntityInterface } from '@operato/typeorm-hist
2
2
  import { User } from '@things-factory/auth-base';
3
3
  import { Domain } from '@things-factory/shell';
4
4
  import { Kpi, KpiStatus, KpiPeriodType } from './kpi';
5
- import { KpiCategory } from '../kpi-category/kpi-category';
6
5
  import { KpiScores } from './kpi-grade.types';
7
6
  export declare class KpiHistory implements HistoryEntityInterface<Kpi> {
8
7
  readonly id: string;
@@ -11,8 +10,6 @@ export declare class KpiHistory implements HistoryEntityInterface<Kpi> {
11
10
  domainId?: string;
12
11
  name: string;
13
12
  description?: string;
14
- category?: KpiCategory;
15
- categoryId?: string;
16
13
  formula?: string;
17
14
  active?: boolean;
18
15
  state?: KpiStatus;
@@ -9,7 +9,6 @@ const auth_base_1 = require("@things-factory/auth-base");
9
9
  const env_1 = require("@things-factory/env");
10
10
  const shell_1 = require("@things-factory/shell");
11
11
  const kpi_1 = require("./kpi");
12
- const kpi_category_1 = require("../kpi-category/kpi-category");
13
12
  const ORMCONFIG = env_1.config.get('ormconfig', {});
14
13
  const DATABASE_TYPE = ORMCONFIG.type;
15
14
  let KpiHistory = class KpiHistory {
@@ -47,15 +46,6 @@ tslib_1.__decorate([
47
46
  (0, type_graphql_1.Field)({ nullable: true }),
48
47
  tslib_1.__metadata("design:type", String)
49
48
  ], KpiHistory.prototype, "description", void 0);
50
- tslib_1.__decorate([
51
- (0, typeorm_1.ManyToOne)(() => kpi_category_1.KpiCategory, { nullable: true }),
52
- (0, type_graphql_1.Field)(type => kpi_category_1.KpiCategory, { nullable: true, description: 'Category to which this KPI belongs.' }),
53
- tslib_1.__metadata("design:type", kpi_category_1.KpiCategory)
54
- ], KpiHistory.prototype, "category", void 0);
55
- tslib_1.__decorate([
56
- (0, typeorm_1.RelationId)((kpi) => kpi.category),
57
- tslib_1.__metadata("design:type", String)
58
- ], KpiHistory.prototype, "categoryId", void 0);
59
49
  tslib_1.__decorate([
60
50
  (0, typeorm_1.Column)({ nullable: true }),
61
51
  (0, type_graphql_1.Field)({ nullable: true, description: 'Calculation formula for the KPI.' }),
@@ -1 +1 @@
1
- {"version":3,"file":"kpi-history.js","sourceRoot":"","sources":["../../../server/service/kpi/kpi-history.ts"],"names":[],"mappings":"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","sourcesContent":["import { Field, ID, ObjectType } from 'type-graphql'\nimport { Column, Entity, Index, ManyToOne, PrimaryGeneratedColumn, RelationId, JoinColumn } from 'typeorm'\n\nimport {\n HistoryActionColumn,\n HistoryActionType,\n HistoryEntityInterface,\n HistoryOriginalIdColumn\n} from '@operato/typeorm-history'\nimport { Role, User } from '@things-factory/auth-base'\nimport { config } from '@things-factory/env'\nimport { Domain, ScalarObject } from '@things-factory/shell'\n\nimport { Kpi, KpiStatus, KpiPeriodType } from './kpi'\nimport { KpiCategory } from '../kpi-category/kpi-category'\nimport { KpiScores } from './kpi-grade.types'\n\nconst ORMCONFIG = config.get('ormconfig', {})\nconst DATABASE_TYPE = ORMCONFIG.type\n\n@Entity()\n@Index('ix_kpi_history_0', (kpiHistory: KpiHistory) => [kpiHistory.originalId, kpiHistory.version], { unique: true })\n@Index('ix_kpi_history_1', (kpiHistory: KpiHistory) => [kpiHistory.domain, kpiHistory.originalId, kpiHistory.version], {\n unique: true\n})\n@ObjectType({ description: 'History Entity of Kpi' })\nexport class KpiHistory implements HistoryEntityInterface<Kpi> {\n @PrimaryGeneratedColumn('uuid')\n @Field(type => ID)\n readonly id: string\n\n @Column({ nullable: true, default: 1 })\n @Field({ nullable: true })\n version?: number = 1\n\n @ManyToOne(type => Domain)\n @Field({ nullable: true })\n domain?: Domain\n\n @RelationId((kpi: Kpi) => kpi.domain)\n domainId?: string\n\n @Column()\n @Field()\n name: string\n\n @Column({ nullable: true })\n @Field({ nullable: true })\n description?: string\n\n @ManyToOne(() => KpiCategory, { nullable: true })\n @Field(type => KpiCategory, { nullable: true, description: 'Category to which this KPI belongs.' })\n category?: KpiCategory\n\n @RelationId((kpi: KpiHistory) => kpi.category)\n categoryId?: string\n\n @Column({ nullable: true })\n @Field({ nullable: true, description: 'Calculation formula for the KPI.' })\n formula?: string\n\n @Column({ nullable: false, default: false })\n @Field({ nullable: true, description: 'Whether this KPI is active (usable) or not.' })\n active?: boolean\n\n @Column({ nullable: true })\n @Field({ nullable: true, description: 'Current state of the KPI (DRAFT, RELEASED, ARCHIVED).' })\n state?: KpiStatus\n\n @Field(type => String, { nullable: true, description: 'Thumbnail image or file path for this KPI.' })\n thumbnail?: string\n\n @Column({ type: 'simple-json', nullable: true })\n @Field(type => ScalarObject, {\n nullable: true,\n description: 'Grade configuration for this KPI version'\n })\n grades?: KpiScores\n\n @Column({ type: 'float', nullable: true, default: 1 })\n @Field({ nullable: true, description: 'Weight for aggregation in parent category.' })\n weight?: number\n\n @Column({ default: 'DAY' })\n @Field(type => KpiPeriodType, { nullable: true })\n periodType: KpiPeriodType\n\n @Column({ nullable: true })\n @Field({ nullable: true })\n createdAt?: Date\n\n @Column({ nullable: true })\n @Field({ nullable: true })\n updatedAt?: Date\n\n @Column({ nullable: true })\n @Field({ nullable: true })\n deletedAt?: Date\n\n @ManyToOne(type => User, { nullable: true })\n @Field(type => User, { nullable: true })\n creator?: User\n\n @RelationId((kpi: Kpi) => kpi.creator)\n creatorId?: string\n\n @ManyToOne(type => User, { nullable: true })\n @Field(type => User, { nullable: true })\n updater?: User\n\n @RelationId((kpi: Kpi) => kpi.updater)\n updaterId?: string\n\n @HistoryOriginalIdColumn()\n public originalId!: string\n\n @HistoryActionColumn({\n nullable: false,\n type:\n DATABASE_TYPE == 'postgres' || DATABASE_TYPE == 'mysql' || DATABASE_TYPE == 'mariadb'\n ? 'enum'\n : DATABASE_TYPE == 'oracle'\n ? 'varchar2'\n : DATABASE_TYPE == 'mssql'\n ? 'nvarchar'\n : 'varchar',\n enum:\n DATABASE_TYPE == 'postgres' || DATABASE_TYPE == 'mysql' || DATABASE_TYPE == 'mariadb'\n ? HistoryActionType\n : undefined,\n length: DATABASE_TYPE == 'postgres' || DATABASE_TYPE == 'mysql' || DATABASE_TYPE == 'mariadb' ? undefined : 32\n })\n public action!: HistoryActionType\n}\n"]}
1
+ {"version":3,"file":"kpi-history.js","sourceRoot":"","sources":["../../../server/service/kpi/kpi-history.ts"],"names":[],"mappings":"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","sourcesContent":["import { Field, ID, ObjectType } from 'type-graphql'\nimport { Column, Entity, Index, ManyToOne, PrimaryGeneratedColumn, RelationId, JoinColumn } from 'typeorm'\n\nimport {\n HistoryActionColumn,\n HistoryActionType,\n HistoryEntityInterface,\n HistoryOriginalIdColumn\n} from '@operato/typeorm-history'\nimport { Role, User } from '@things-factory/auth-base'\nimport { config } from '@things-factory/env'\nimport { Domain, ScalarObject } from '@things-factory/shell'\n\nimport { Kpi, KpiStatus, KpiPeriodType } from './kpi'\nimport { KpiScores } from './kpi-grade.types'\n\nconst ORMCONFIG = config.get('ormconfig', {})\nconst DATABASE_TYPE = ORMCONFIG.type\n\n@Entity()\n@Index('ix_kpi_history_0', (kpiHistory: KpiHistory) => [kpiHistory.originalId, kpiHistory.version], { unique: true })\n@Index('ix_kpi_history_1', (kpiHistory: KpiHistory) => [kpiHistory.domain, kpiHistory.originalId, kpiHistory.version], {\n unique: true\n})\n@ObjectType({ description: 'History Entity of Kpi' })\nexport class KpiHistory implements HistoryEntityInterface<Kpi> {\n @PrimaryGeneratedColumn('uuid')\n @Field(type => ID)\n readonly id: string\n\n @Column({ nullable: true, default: 1 })\n @Field({ nullable: true })\n version?: number = 1\n\n @ManyToOne(type => Domain)\n @Field({ nullable: true })\n domain?: Domain\n\n @RelationId((kpi: Kpi) => kpi.domain)\n domainId?: string\n\n @Column()\n @Field()\n name: string\n\n @Column({ nullable: true })\n @Field({ nullable: true })\n description?: string\n\n @Column({ nullable: true })\n @Field({ nullable: true, description: 'Calculation formula for the KPI.' })\n formula?: string\n\n @Column({ nullable: false, default: false })\n @Field({ nullable: true, description: 'Whether this KPI is active (usable) or not.' })\n active?: boolean\n\n @Column({ nullable: true })\n @Field({ nullable: true, description: 'Current state of the KPI (DRAFT, RELEASED, ARCHIVED).' })\n state?: KpiStatus\n\n @Field(type => String, { nullable: true, description: 'Thumbnail image or file path for this KPI.' })\n thumbnail?: string\n\n @Column({ type: 'simple-json', nullable: true })\n @Field(type => ScalarObject, {\n nullable: true,\n description: 'Grade configuration for this KPI version'\n })\n grades?: KpiScores\n\n @Column({ type: 'float', nullable: true, default: 1 })\n @Field({ nullable: true, description: 'Weight for aggregation in parent category.' })\n weight?: number\n\n @Column({ default: 'DAY' })\n @Field(type => KpiPeriodType, { nullable: true })\n periodType: KpiPeriodType\n\n @Column({ nullable: true })\n @Field({ nullable: true })\n createdAt?: Date\n\n @Column({ nullable: true })\n @Field({ nullable: true })\n updatedAt?: Date\n\n @Column({ nullable: true })\n @Field({ nullable: true })\n deletedAt?: Date\n\n @ManyToOne(type => User, { nullable: true })\n @Field(type => User, { nullable: true })\n creator?: User\n\n @RelationId((kpi: Kpi) => kpi.creator)\n creatorId?: string\n\n @ManyToOne(type => User, { nullable: true })\n @Field(type => User, { nullable: true })\n updater?: User\n\n @RelationId((kpi: Kpi) => kpi.updater)\n updaterId?: string\n\n @HistoryOriginalIdColumn()\n public originalId!: string\n\n @HistoryActionColumn({\n nullable: false,\n type:\n DATABASE_TYPE == 'postgres' || DATABASE_TYPE == 'mysql' || DATABASE_TYPE == 'mariadb'\n ? 'enum'\n : DATABASE_TYPE == 'oracle'\n ? 'varchar2'\n : DATABASE_TYPE == 'mssql'\n ? 'nvarchar'\n : 'varchar',\n enum:\n DATABASE_TYPE == 'postgres' || DATABASE_TYPE == 'mysql' || DATABASE_TYPE == 'mariadb'\n ? HistoryActionType\n : undefined,\n length: DATABASE_TYPE == 'postgres' || DATABASE_TYPE == 'mysql' || DATABASE_TYPE == 'mariadb' ? undefined : 32\n })\n public action!: HistoryActionType\n}\n"]}
@@ -10,5 +10,5 @@ export declare class KpiMutation {
10
10
  importKpis(kpis: KpiPatch[], context: ResolverContext): Promise<boolean>;
11
11
  releaseKpi(id: string, context: ResolverContext): Promise<Kpi>;
12
12
  revertKpiVersion(id: string, version: number, context: ResolverContext): Promise<Kpi>;
13
- calculateKpiValue(kpiId: string, valueDate: string, group: string, context: ResolverContext): Promise<KpiValue>;
13
+ calculateKpiValue(kpiId: string, valueDate: string, org: string, context: ResolverContext): Promise<KpiValue>;
14
14
  }
@@ -8,11 +8,11 @@ const shell_1 = require("@things-factory/shell");
8
8
  const attachment_base_1 = require("@things-factory/attachment-base");
9
9
  const kpi_1 = require("./kpi");
10
10
  const kpi_type_1 = require("./kpi-type");
11
- const kpi_category_1 = require("../kpi-category/kpi-category");
12
11
  const kpi_history_1 = require("./kpi-history");
13
12
  const kpi_formula_service_1 = require("./kpi-formula.service");
14
13
  const scheduler_client_1 = require("@things-factory/scheduler-client");
15
14
  const kpi_value_1 = require("../kpi-value/kpi-value");
15
+ const kpi_org_scope_1 = require("../kpi-org-scope/kpi-org-scope");
16
16
  const typeorm_2 = require("typeorm");
17
17
  const parser_1 = require("../../calculator/parser");
18
18
  const evaluator_1 = require("../../calculator/evaluator");
@@ -21,12 +21,20 @@ const kpi_metric_value_provider_1 = require("../../controllers/kpi-metric-value-
21
21
  let KpiMutation = class KpiMutation {
22
22
  async createKpi(kpi, context) {
23
23
  const { domain, user, tx } = context.state;
24
- let category = kpi.category
25
- ? await (0, shell_1.getRepository)(kpi_category_1.KpiCategory).findOne({ where: { id: kpi.category.id } })
24
+ let parent = kpi.parent
25
+ ? await (0, shell_1.getRepository)(kpi_1.Kpi).findOne({ where: { id: kpi.parent.id, domain: { id: domain.id } } })
26
26
  : undefined;
27
+ // 순환 참조 검사
28
+ if (parent) {
29
+ const formulaService = new kpi_formula_service_1.KpiFormulaService();
30
+ const hasCircular = await formulaService.hasCircularReference(parent.id, parent.id);
31
+ if (hasCircular) {
32
+ throw new Error('Circular reference detected in KPI hierarchy');
33
+ }
34
+ }
27
35
  const result = await (0, shell_1.getRepository)(kpi_1.Kpi, tx).save({
28
36
  ...kpi,
29
- category,
37
+ parent,
30
38
  domain,
31
39
  creator: user,
32
40
  updater: user
@@ -91,13 +99,21 @@ let KpiMutation = class KpiMutation {
91
99
  const kpi = await repository.findOne({
92
100
  where: { domain: { id: domain.id }, id }
93
101
  });
94
- let category = patch.category
95
- ? await (0, shell_1.getRepository)(kpi_category_1.KpiCategory).findOne({ where: { id: patch.category.id } })
96
- : kpi.category;
102
+ let parent = patch.parent
103
+ ? await (0, shell_1.getRepository)(kpi_1.Kpi).findOne({ where: { id: patch.parent.id, domain: { id: domain.id } } })
104
+ : patch.parent === null ? null : kpi.parent;
105
+ // 순환 참조 검사 (parent가 변경되는 경우)
106
+ if (parent && parent.id !== kpi.parentId) {
107
+ const formulaService = new kpi_formula_service_1.KpiFormulaService();
108
+ const hasCircular = await formulaService.hasCircularReference(kpi.id, parent.id);
109
+ if (hasCircular) {
110
+ throw new Error('Circular reference detected in KPI hierarchy');
111
+ }
112
+ }
97
113
  const result = await repository.save({
98
114
  ...kpi,
99
115
  ...patch,
100
- category,
116
+ parent,
101
117
  updater: user
102
118
  });
103
119
  if (patch.thumbnail) {
@@ -288,8 +304,6 @@ let KpiMutation = class KpiMutation {
288
304
  ...kpi,
289
305
  name: kpiHistory.name,
290
306
  description: kpiHistory.description,
291
- category: kpiHistory.category,
292
- categoryId: kpiHistory.categoryId,
293
307
  formula: kpiHistory.formula,
294
308
  active: kpiHistory.active,
295
309
  state: 'DRAFT',
@@ -298,7 +312,7 @@ let KpiMutation = class KpiMutation {
298
312
  });
299
313
  return updated;
300
314
  }
301
- async calculateKpiValue(kpiId, valueDate, group, context) {
315
+ async calculateKpiValue(kpiId, valueDate, org, context) {
302
316
  const { domain, user, tx } = context.state;
303
317
  const kpiRepo = (0, shell_1.getRepository)(kpi_1.Kpi, tx);
304
318
  const metricRepo = (0, shell_1.getRepository)(require('../kpi-metric/kpi-metric').KpiMetric, tx);
@@ -334,7 +348,7 @@ let KpiMutation = class KpiMutation {
334
348
  metric: { id: metric.id },
335
349
  valueDate: valueDateToUse,
336
350
  periodType,
337
- group: group ?? '',
351
+ org: org ?? '',
338
352
  domain: { id: domain.id }
339
353
  }
340
354
  });
@@ -350,7 +364,7 @@ let KpiMutation = class KpiMutation {
350
364
  metric: { id: metric.id },
351
365
  valueDate: (0, typeorm_2.Between)(startDate, endDate),
352
366
  periodType: metric.periodType,
353
- group: group ?? '',
367
+ org: org ?? '',
354
368
  domain: { id: domain.id }
355
369
  }
356
370
  });
@@ -368,18 +382,37 @@ let KpiMutation = class KpiMutation {
368
382
  const ast = (0, parser_1.parseFormula)(kpi.formula);
369
383
  const provider = new kpi_metric_value_provider_1.KpiMetricValueProvider({
370
384
  valueDate: valueDateToUse,
371
- group,
385
+ org,
372
386
  domainId: domain.id,
373
387
  tx
374
388
  });
375
389
  const evalContext = { functions: functions_1.builtinFunctions, provider };
376
390
  const kpiValueResult = await (0, evaluator_1.evaluateFormula)(ast, evalContext);
377
- // 5. KPI Value upsert
391
+ // 5. KpiOrgScope 처리
392
+ let kpiOrgScope = null;
393
+ if (org) {
394
+ kpiOrgScope = await (0, shell_1.getRepository)(kpi_org_scope_1.KpiOrgScope, tx).findOne({
395
+ where: { org: org, domain: { id: domain.id } }
396
+ });
397
+ if (!kpiOrgScope) {
398
+ // 새 KpiOrgScope 생성
399
+ kpiOrgScope = await (0, shell_1.getRepository)(kpi_org_scope_1.KpiOrgScope, tx).save({
400
+ entityType: 'KpiCalculation',
401
+ entityId: `calc-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
402
+ entityName: org,
403
+ org: org,
404
+ domain,
405
+ creator: user,
406
+ updater: user
407
+ });
408
+ }
409
+ }
410
+ // 6. KPI Value upsert
378
411
  let kpiValue = await kpiValueRepo.findOne({
379
412
  where: {
380
413
  kpi: { id: kpi.id },
381
414
  valueDate: valueDateToUse,
382
- group: group ?? '',
415
+ kpiOrgScope: kpiOrgScope ? { id: kpiOrgScope.id } : null,
383
416
  version: kpi.version,
384
417
  domain: { id: domain.id }
385
418
  }
@@ -389,17 +422,21 @@ let KpiMutation = class KpiMutation {
389
422
  kpiValue.updater = user;
390
423
  }
391
424
  else {
392
- kpiValue = kpiValueRepo.create({
425
+ const createData = {
393
426
  kpi,
394
427
  kpiId: kpi.id,
395
428
  version: kpi.version,
396
429
  valueDate: valueDateToUse,
397
430
  value: kpiValueResult,
398
- group: group ?? '',
399
431
  domain,
400
432
  creator: user,
401
433
  updater: user
402
- });
434
+ };
435
+ if (kpiOrgScope) {
436
+ createData.kpiOrgScope = kpiOrgScope;
437
+ createData.kpiOrgScopeId = kpiOrgScope.id;
438
+ }
439
+ kpiValue = Object.assign(new kpi_value_1.KpiValue(), createData);
403
440
  }
404
441
  return await kpiValueRepo.save(kpiValue);
405
442
  }
@@ -493,7 +530,7 @@ tslib_1.__decorate([
493
530
  (0, type_graphql_1.Mutation)(returns => kpi_value_1.KpiValue, { description: 'KPI 기준으로 formula 계산 및 KPI Value upsert' }),
494
531
  tslib_1.__param(0, (0, type_graphql_1.Arg)('kpiId')),
495
532
  tslib_1.__param(1, (0, type_graphql_1.Arg)('valueDate', { nullable: true })),
496
- tslib_1.__param(2, (0, type_graphql_1.Arg)('group', { nullable: true })),
533
+ tslib_1.__param(2, (0, type_graphql_1.Arg)('org', { nullable: true })),
497
534
  tslib_1.__param(3, (0, type_graphql_1.Ctx)()),
498
535
  tslib_1.__metadata("design:type", Function),
499
536
  tslib_1.__metadata("design:paramtypes", [String, String, String, Object]),