@dssp/dkpi 1.0.0-alpha.84 → 1.0.0-alpha.86
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/dist-client/components/kpi-2d-lookup-chart.d.ts +7 -0
- package/dist-client/components/kpi-2d-lookup-chart.js +26 -16
- package/dist-client/components/kpi-2d-lookup-chart.js.map +1 -1
- package/dist-client/components/kpi-lookup-chart.d.ts +5 -0
- package/dist-client/components/kpi-lookup-chart.js +13 -1
- package/dist-client/components/kpi-lookup-chart.js.map +1 -1
- package/dist-client/pages/project-complete-tabs/pc-tab1-plan.js +2 -2
- package/dist-client/pages/project-complete-tabs/pc-tab1-plan.js.map +1 -1
- package/dist-client/pages/sv-project-detail.d.ts +11 -0
- package/dist-client/pages/sv-project-detail.js +95 -49
- package/dist-client/pages/sv-project-detail.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.d.ts +5 -0
- package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.js +30 -9
- package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.js.map +1 -1
- package/dist-server/service/kpi-value/kpi-value-query.js +21 -7
- package/dist-server/service/kpi-value/kpi-value-query.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/schema.graphql +27 -2
|
@@ -135,6 +135,11 @@ export declare class KpiMetricValueMutation {
|
|
|
135
135
|
private calculateScoreFromLookup;
|
|
136
136
|
/**
|
|
137
137
|
* 2D lookup table에서 점수 계산 (X13: 공정률 × 편차 → 점수 1~5)
|
|
138
|
+
*
|
|
139
|
+
* 단위 정합:
|
|
140
|
+
* - deviationValue (= KpiMetric '일정 이탈 수준' value): % 단위 (예: 2.5 = 2.5%).
|
|
141
|
+
* - row.boundary*: ratio 단위 (예: 0.025 = 2.5%).
|
|
142
|
+
* - 비교 전 deviationValue 를 /100 해서 ratio 로 변환.
|
|
138
143
|
*/
|
|
139
144
|
private calculateScoreFrom2DLookup;
|
|
140
145
|
/**
|
|
@@ -560,15 +560,30 @@ let KpiMetricValueMutation = class KpiMetricValueMutation {
|
|
|
560
560
|
kpiValue.updater = user;
|
|
561
561
|
// 성과 점수 자동 계산 및 저장
|
|
562
562
|
try {
|
|
563
|
-
// 2D lookup KPI (X13 등)
|
|
563
|
+
// 2D lookup KPI (X13 등) 의 progressRate — KpiMetric '실적공정율' latest value 우선.
|
|
564
|
+
// 없으면 project.totalProgress fallback. client kpi-2d-lookup-chart 와 동일 source.
|
|
564
565
|
let scoreContext;
|
|
565
566
|
const gradesData = kpi.grades;
|
|
566
567
|
if (gradesData && !Array.isArray(gradesData) && gradesData.type === 'PROGRESS_DEVIATION_LOOKUP') {
|
|
567
568
|
const projectId = kpiValue.group || org;
|
|
568
|
-
|
|
569
|
-
const
|
|
570
|
-
|
|
571
|
-
|
|
569
|
+
let progressRate = null;
|
|
570
|
+
const progressMetric = await (0, shell_1.getRepository)(kpi_1.KpiMetric, tx).findOne({
|
|
571
|
+
where: { name: '실적공정율' }
|
|
572
|
+
});
|
|
573
|
+
if (progressMetric) {
|
|
574
|
+
const latest = await (0, shell_1.getRepository)(kpi_1.KpiMetricValue, tx).findOne({
|
|
575
|
+
where: { metric: { id: progressMetric.id }, org: projectId },
|
|
576
|
+
order: { valueDate: 'DESC' }
|
|
577
|
+
});
|
|
578
|
+
if ((latest === null || latest === void 0 ? void 0 : latest.value) != null)
|
|
579
|
+
progressRate = latest.value;
|
|
580
|
+
}
|
|
581
|
+
if (progressRate === null) {
|
|
582
|
+
const project = await (0, shell_1.getRepository)(project_1.Project, tx).findOne({ where: { id: projectId } });
|
|
583
|
+
progressRate = (_a = project === null || project === void 0 ? void 0 : project.totalProgress) !== null && _a !== void 0 ? _a : 50;
|
|
584
|
+
}
|
|
585
|
+
scoreContext = { progressRate };
|
|
586
|
+
console.log(`2D lookup KPI ${kpi.name}: progressRate=${scoreContext.progressRate}% (실적공정율 metric latest 우선)`);
|
|
572
587
|
}
|
|
573
588
|
await this.calculateAndSaveScore(kpiValue, kpi, scoreContext);
|
|
574
589
|
console.log(`Successfully calculated score for KPI value ${kpiValue.id}`);
|
|
@@ -638,6 +653,11 @@ let KpiMetricValueMutation = class KpiMetricValueMutation {
|
|
|
638
653
|
}
|
|
639
654
|
/**
|
|
640
655
|
* 2D lookup table에서 점수 계산 (X13: 공정률 × 편차 → 점수 1~5)
|
|
656
|
+
*
|
|
657
|
+
* 단위 정합:
|
|
658
|
+
* - deviationValue (= KpiMetric '일정 이탈 수준' value): % 단위 (예: 2.5 = 2.5%).
|
|
659
|
+
* - row.boundary*: ratio 단위 (예: 0.025 = 2.5%).
|
|
660
|
+
* - 비교 전 deviationValue 를 /100 해서 ratio 로 변환.
|
|
641
661
|
*/
|
|
642
662
|
calculateScoreFrom2DLookup(deviationValue, grades, progressRate) {
|
|
643
663
|
if (!grades.rows || !Array.isArray(grades.rows))
|
|
@@ -647,17 +667,18 @@ let KpiMetricValueMutation = class KpiMetricValueMutation {
|
|
|
647
667
|
const row = grades.rows.find((r) => r.progressRate === progressIndex);
|
|
648
668
|
if (!row)
|
|
649
669
|
return null;
|
|
670
|
+
const devRatio = deviationValue / 100;
|
|
650
671
|
let score;
|
|
651
|
-
if (
|
|
672
|
+
if (devRatio < row.boundary5to4) {
|
|
652
673
|
score = 5;
|
|
653
674
|
}
|
|
654
|
-
else if (
|
|
675
|
+
else if (devRatio < row.boundary4to3) {
|
|
655
676
|
score = 4;
|
|
656
677
|
}
|
|
657
|
-
else if (
|
|
678
|
+
else if (devRatio < row.boundary3to2) {
|
|
658
679
|
score = 3;
|
|
659
680
|
}
|
|
660
|
-
else if (
|
|
681
|
+
else if (devRatio < row.boundary2to1) {
|
|
661
682
|
score = 2;
|
|
662
683
|
}
|
|
663
684
|
else {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kpi-metric-value-mutation.js","sourceRoot":"","sources":["../../../server/service/kpi-metric-value/kpi-metric-value-mutation.ts"],"names":[],"mappings":"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","sourcesContent":["import { Resolver, Mutation, Arg, Ctx, Directive, ObjectType, Field } from 'type-graphql'\nimport { getRepository, ScalarObject, EnvVar, Domain } from '@things-factory/shell'\nimport { runScenario } from '@things-factory/integration-base'\nimport { In } from 'typeorm'\nimport {\n KpiPeriodType,\n KpiMetric,\n KpiMetricValue,\n KpiMetricValuePatch,\n Kpi,\n KpiValue,\n parseFormula,\n evaluateFormula,\n builtinFunctions,\n KpiMetricValueProvider\n} from '@things-factory/kpi'\nimport { Attachment, NewAttachment, createAttachment } from '@things-factory/attachment-base'\nimport { Project, ProjectState } from '@dssp/project'\nimport moment from 'moment-timezone'\nimport FormData from 'form-data'\nimport fetch from 'node-fetch'\nimport https from 'https'\nimport http from 'http'\n\n/**\n * 외부 시스템 데이터 수집 결과 — 시스템별 한 row.\n * UI \"자동 수집\" 버튼이 시나리오 호출 후 시스템별 성공·오류 표시에 사용.\n */\n@ObjectType({ description: '외부 시스템(세움터/올바로/키스콘) 데이터 수집 시나리오 호출 결과' })\nclass ExternalDataCollectionResult {\n @Field({ description: '소스 키: saeumteo | allbaro | kiscon' })\n source!: string\n\n @Field({ description: '표시 라벨 (세움터/올바로/키스콘)' })\n label!: string\n\n @Field({ description: '시나리오 실행 성공 여부' })\n ok!: boolean\n\n @Field({ description: '성공 시 \"완료\", 실패 시 에러 메시지' })\n message!: string\n\n @Field(type => ScalarObject, {\n nullable: true,\n description:\n '시나리오 result 객체 — projectKey: value 맵. ' +\n '세움터={area, floorAreaRatio, upperFloorCount, lowerFloorCount, structureType, siteType}, ' +\n '올바로={totalConstructionWasteAmount}, ' +\n '키스콘={constructionPeriod, constructionCost}. ' +\n 'siteType (건축물 용도, 예 APARTMENT_COMPLEX) / structureType (구조형태) 는 ' +\n 'BuildingComplex 의 시설유형/구조유형 속성 후보. KISCON 의 \"공사유형(신설/증축)\" 은 ' +\n 'DSSP SiteType (용도분류) 와 다른 도메인이라 매핑 대상 아님.'\n })\n data?: any\n}\n\n@Resolver(KpiMetricValue)\nexport class KpiMetricValueMutation {\n /* 프로젝트 수행과정 중에 (시간, 비용, 발생 건수 등) 누적된 값을 반영하여 KPI Metric Value 값을 수정 - 예를 들면, 총 설계 변경 건수, 총 건설 폐기물 발생량, 공사비, 공사기간, 재해 건수 등 */\n @Directive('@transaction')\n @Directive('@privilege(category: \"kpi\", privilege: \"input\", domainOwnerGranted: true, superUserGranted: true)')\n @Mutation(returns => [KpiMetricValue], { description: \"To modify multiple cumulative KpiMetricValues' value\" })\n async updateKpiMetricValuesCumulative(\n @Arg('patches', type => [KpiMetricValuePatch]) patches: KpiMetricValuePatch[],\n @Ctx() context: ResolverContext\n ): Promise<KpiMetricValue[]> {\n return await this.upsertKpiMetricValues(patches, context)\n }\n\n /* 전문 감리사에 의해서 평가된 별점을 반영하여 KPI Metric Value 값을 수정 */\n @Directive('@transaction')\n @Directive('@privilege(category: \"kpi\", privilege: \"assessment\", domainOwnerGranted: true, superUserGranted: true)')\n @Mutation(returns => [KpiMetricValue], { description: \"To modify multiple assessment KpiMetricValues' value\" })\n async updateKpiMetricValuesAssessment(\n @Arg('patches', type => [KpiMetricValuePatch]) patches: KpiMetricValuePatch[],\n @Ctx() context: ResolverContext\n ): Promise<KpiMetricValue[]> {\n return await this.upsertKpiMetricValues(patches, context)\n }\n\n /**\n * KpiMetricValue 의 unique 조합 (domain, metric, valueDate, org) 기준 진짜 upsert.\n *\n * 기존 mutation 의 `repo.save({...patch})` 는 patch.id 만 보고 update/insert 결정해\n * 같은 metric × 같은 valueDate × 같은 org 인데 patch.id 가 새 UUID 인 경우 unique\n * 인덱스 (ix_kpi_metric_value_latest) 위반 에러 또는 row 누적 위험. 정확한 upsert\n * 동작을 보장하기 위해 조합 lookup → 기존 id 사용 → save.\n *\n * 월별 metric (periodType=MONTH, valueDate=YYYY-MM-01) 의 단일 row 정책을 자연 충족.\n *\n * **도메인 컨텍스트 스위치**: caller (운영자) 가 system 도메인일 수 있어 patch.org\n * (= projectId) 로 프로젝트 테넌트 도메인을 lookup 해 그 컨텍스트로 저장. 모든\n * patch 가 같은 projectId 라 가정 (한 번의 mutation = 한 프로젝트의 값들).\n */\n private async upsertKpiMetricValues(\n patches: KpiMetricValuePatch[],\n context: ResolverContext\n ): Promise<KpiMetricValue[]> {\n if (patches.length === 0) return []\n // 첫 patch.org 의 projectId 로 도메인 스위치. patch.org 가 없으면 caller context 그대로.\n const projectId = (patches[0] as any).org\n const ctx = projectId ? await this.switchToProjectDomain(projectId, context) : context\n const { domain, user, tx } = ctx.state\n const metricValueRepo = getRepository(KpiMetricValue, tx)\n const metricRepo = getRepository(KpiMetric, tx)\n\n const results: KpiMetricValue[] = []\n for (const patch of patches) {\n const metric = await metricRepo.findOne({ where: { id: patch.metricId } })\n if (!metric) {\n throw new Error(`Metric not found: ${patch.metricId}`)\n }\n // unique 조합 기준 기존 row lookup. 있으면 그 id 로 save → update.\n const existing = await metricValueRepo.findOne({\n where: {\n domain: { id: domain.id },\n metric: { id: patch.metricId },\n valueDate: patch.valueDate,\n org: patch.org\n } as any\n })\n const result = await metricValueRepo.save({\n domain,\n ...patch,\n id: existing?.id ?? patch.id,\n metric,\n updater: user\n } as any)\n results.push(result)\n }\n return results\n }\n\n /* 전문 감리사에 의 감리 최종 평가서의 긍부정을 텍스트 분석하는 감정 분석 기반 평가값을 수정 */\n @Directive('@transaction')\n @Directive('@privilege(category: \"kpi\", privilege: \"sentiment\", domainOwnerGranted: true, superUserGranted: true)')\n @Mutation(returns => Attachment, { nullable: true, description: \"To modify multiple sentiment KpiMetricValues' value\" })\n async updateKpiMetricValuesSentiment(\n @Arg('attachment', type => NewAttachment) attachment: NewAttachment,\n @Ctx() context: ResolverContext\n ): Promise<Attachment | null> {\n const { domain, user, tx } = context.state\n const projectRepo = getRepository(Project, tx)\n const projectId = attachment.refBy\n const attachmentRepo = getRepository(Attachment, tx)\n const metricValueRepo = getRepository(KpiMetricValue, tx)\n const metricRepo = getRepository(KpiMetric, tx)\n\n // 1. 기존 파일 삭제\n projectRepo.update(projectId, { completeReport: null })\n await attachmentRepo.delete({ refBy: projectId, refType: attachment.refType })\n\n // 2. 새 파일 없으면 끝\n if (!attachment.file) {\n return null\n }\n\n // 3. 먼저 파일을 버퍼로 읽기 (스트림은 한 번만 읽을 수 있으므로)\n const uploadedFile = await attachment.file\n const { filename } = uploadedFile\n const fileBuffer = await this.readFileToBuffer(uploadedFile)\n\n console.log(`Processing PDF file: ${filename}, size: ${fileBuffer.length} bytes`)\n\n // 4. 새 파일 저장 (버퍼를 사용하여 attachment 생성)\n const recreatedFile = this.createFileUploadFromBuffer(fileBuffer, filename, 'application/pdf')\n const { id: resultId } = await createAttachment(null, { attachment: { ...attachment, file: recreatedFile } }, context)\n const result = await attachmentRepo.findOne({ where: { id: resultId } })\n projectRepo.update(projectId, { completeReport: result })\n\n // 5. pdf 파일을 operator-runner 서비스에 업로드하여 분석\n let safetyScore = 0\n let qualityScore = 0\n\n try {\n const operatorRunnerUrl = process.env.OPERATOR_RUNNER_URL || 'https://hatiolab-korea-uni.ettisoft.com'\n\n // sl-pa-safety 서비스 호출\n safetyScore = await this.callOperatorRunnerServiceWithBuffer(operatorRunnerUrl, 'sl-pa-safety', fileBuffer, filename)\n\n // sl-pa-quality 서비스 호출\n qualityScore = await this.callOperatorRunnerServiceWithBuffer(operatorRunnerUrl, 'sl-pa-quality', fileBuffer, filename)\n } catch (error) {\n console.error('Failed to analyze PDF with operator-runner:', error)\n }\n\n // 5. 메트릭 점수 저장\n await this.saveMetricValue(metricValueRepo, metricRepo, projectId, 'SL-PA 안전 평가', safetyScore, domain, user)\n await this.saveMetricValue(metricValueRepo, metricRepo, projectId, 'SL-PA 품질 평가', qualityScore, domain, user)\n\n return result\n }\n\n /**\n * FileUpload 스트림을 버퍼로 읽기\n */\n private async readFileToBuffer(fileUpload: any): Promise<Buffer> {\n const { createReadStream } = fileUpload\n const chunks: Buffer[] = []\n\n return new Promise((resolve, reject) => {\n const stream = createReadStream()\n stream.on('data', (chunk: Buffer) => chunks.push(chunk))\n stream.on('end', () => resolve(Buffer.concat(chunks)))\n stream.on('error', (error: Error) => reject(error))\n })\n }\n\n /**\n * Buffer로부터 FileUpload 객체 생성\n */\n private createFileUploadFromBuffer(buffer: Buffer, filename: string, mimetype: string): any {\n const { Readable } = require('stream')\n return {\n filename,\n mimetype,\n encoding: '7bit',\n createReadStream: () => {\n const readable = new Readable()\n readable.push(buffer)\n readable.push(null)\n return readable\n }\n }\n }\n\n /**\n * operator-runner 서비스 호출 (Buffer 사용)\n */\n private async callOperatorRunnerServiceWithBuffer(\n baseUrl: string,\n serviceName: string,\n fileBuffer: Buffer,\n filename: string\n ): Promise<number> {\n console.log(`Calling operator-runner service: ${serviceName}`)\n console.log(`Base URL: ${baseUrl}`)\n console.log(`Filename: ${filename}`)\n console.log(`Buffer size: ${fileBuffer.length} bytes`)\n\n const formData = new FormData()\n\n // Buffer를 스트림으로 변환하여 추가\n const { Readable } = require('stream')\n const bufferStream = Readable.from(fileBuffer)\n\n formData.append('files', bufferStream, {\n filename,\n contentType: 'application/pdf'\n })\n\n const url = `${baseUrl}/api/run/${serviceName}`\n console.log(`Request URL: ${url}`)\n\n // HTTP/HTTPS agent 설정\n const isHttps = url.startsWith('https')\n const agent = isHttps\n ? new https.Agent({\n keepAlive: false,\n timeout: 120000,\n rejectUnauthorized: false\n })\n : new http.Agent({\n keepAlive: false,\n timeout: 120000\n })\n\n try {\n const response = await fetch(url, {\n method: 'POST',\n body: formData as any,\n headers: {\n ...formData.getHeaders(),\n Authorization: `Basic ${Buffer.from('admin:admin1234').toString('base64')}`\n },\n agent,\n timeout: 120000\n })\n\n console.log(`Response status: ${response.status}`)\n\n if (!response.ok) {\n const errorText = await response.text()\n console.error(`Service ${serviceName} error response:`, errorText)\n throw new Error(`Service ${serviceName} failed (${response.status}): ${errorText}`)\n }\n\n const data = await response.json()\n console.log(`Service ${serviceName} response:`, JSON.stringify(data))\n\n const score = data?.result?.score || data?.score || 0\n console.log(`Extracted score: ${score}`)\n\n return score\n } catch (error) {\n console.error(`Error calling ${serviceName}:`, error)\n throw error\n }\n }\n\n /**\n * 메트릭 값 저장\n */\n private async saveMetricValue(\n metricValueRepo: any,\n metricRepo: any,\n projectId: string,\n metricName: string,\n value: number,\n domain: any,\n user: any\n ): Promise<void> {\n const metricValue = await metricValueRepo.findOne({\n where: { org: projectId, metric: { name: metricName } }\n })\n\n if (metricValue) {\n await metricValueRepo.save({\n ...metricValue,\n value,\n updater: user\n })\n } else {\n const originMetric = await metricRepo.findOne({ where: { name: metricName } })\n if (originMetric) {\n await metricValueRepo.save({\n metric: { id: originMetric.id },\n unit: originMetric.unit || '',\n org: projectId,\n periodType: originMetric.periodType,\n valueDate: moment().tz('Asia/Seoul').format('YYYY-MM-DD'),\n value,\n domain,\n updater: user\n })\n }\n }\n }\n\n @Directive('@transaction')\n @Directive('@privilege(category: \"kpi\", privilege: \"finalize\", domainOwnerGranted: true, superUserGranted: true)')\n @Mutation(returns => Boolean, { description: 'To finalize project with KPI recalculation' })\n async finalizeProjectWithKpiRecalculation(\n @Arg('projectId') projectId: string,\n @Ctx() context: ResolverContext\n ): Promise<boolean> {\n const { domain, user, tx } = context.state\n const projectRepo = getRepository(Project, tx)\n\n const project = await projectRepo.findOne({ where: { id: projectId } })\n\n console.log('project :', project)\n\n if (!project) {\n throw new Error(`Project not found: ${projectId}`)\n }\n\n // KPI value 계산은 프로젝트(테넌트) 도메인 기준이라 컨텍스트 스위치.\n // 외부 시스템 데이터 수집은 별도 mutation (collectProjectExternalData) 로 분리 —\n // 사용자가 UI \"자동 수집\" 버튼으로 명시 실행. finalize/recalculate 흐름에서는\n // 외부 연동을 끌어들이지 않음 (DB 에 이미 저장된 KpiMetricValue 만 가지고 계산).\n const projectContext = await this.switchToProjectDomain(projectId, context)\n\n await this.recalculateProjectKpiValues(projectId, projectContext)\n\n projectRepo.save({\n ...project,\n state: ProjectState.COMPLETED\n })\n\n return true\n }\n\n /**\n * 완공 처리 없이 KPI 만 재계산 — 진행 중 프로젝트의 중간 결과 산정 용도.\n * DB 에 이미 저장된 KpiMetricValue 만 가지고 formula 평가. 외부 시나리오 (juso/\n * allbaro/kiscon) 자동 수집은 의도적으로 호출하지 않음 — 외부 수집은 사용자가\n * \"자동 수집\" 버튼 (`collectProjectExternalData`) 으로 명시적으로 실행하는 흐름.\n * 권한은 `kpi:recalculate` 로 분리해 finalize 보다 가볍게 부여 가능.\n */\n @Directive('@transaction')\n @Directive('@privilege(category: \"kpi\", privilege: \"recalculate\", domainOwnerGranted: true, superUserGranted: true)')\n @Mutation(returns => Boolean, { description: 'Recalculate project KPI without finalizing (interim).' })\n async recalculateProjectKpi(\n @Arg('projectId') projectId: string,\n @Ctx() context: ResolverContext\n ): Promise<boolean> {\n const { tx } = context.state\n const project = await getRepository(Project, tx).findOne({ where: { id: projectId } })\n if (!project) {\n throw new Error(`Project not found: ${projectId}`)\n }\n\n const projectContext = await this.switchToProjectDomain(projectId, context)\n await this.recalculateProjectKpiValues(projectId, projectContext)\n\n return true\n }\n\n /**\n * UI \"자동 수집\" 버튼 전용 mutation. 외부 시스템 3종 시나리오를 순차 호출하고\n * 시스템별 성공/실패 + 메시지를 반환. UI 는 결과를 보고 카드별 상태 (성공·오류) 를 표시.\n *\n * 시나리오는 도메인 EnvVar (주소·자격증명·서비스키 등) 만으로 동작하므로 파라미터 X.\n * 한 시스템 실패가 다른 시스템 수집을 막지 않도록 try/catch 로 격리.\n *\n * 운영 현실: 키스콘·올바로는 시공사 ID/PW 가 자주 미확보 → 오류 흔함. 세움터는 공공\n * 데이터 서비스키만으로 동작 가능. UI 는 시스템별로 명확한 오류 메시지 노출.\n */\n @Directive('@privilege(category: \"kpi\", privilege: \"auto-collect\", domainOwnerGranted: true, superUserGranted: true)')\n @Mutation(returns => [ExternalDataCollectionResult], {\n description: 'Run external data collection scenarios per system, returning per-system result.'\n })\n async collectProjectExternalData(\n @Arg('projectId') projectId: string,\n @Ctx() context: ResolverContext\n ): Promise<ExternalDataCollectionResult[]> {\n const projectContext = await this.switchToProjectDomain(projectId, context)\n return await this.runExternalDataScenariosWithResults(projectContext)\n }\n\n /**\n * 프로젝트 정보 수정 화면의 \"정보 연동\" 버튼 전용 — 세움터 단일 시나리오만 호출.\n * BuildingComplex 기본 속성 (area / floorAreaRatio / siteType / structureType /\n * coverageRatio / householdCount 등) 자동 채움 목적.\n *\n * address 인자가 있으면 시나리오 실행 전에 EnvVar `Step::건축물관리대장조회::address::query`\n * 를 그 값으로 upsert — 운영자가 폼에서 방금 입력한 주소를 시나리오가 곧바로 사용.\n * (도메인의 기존 EnvVar 와 다를 수 있어 명시적 갱신.)\n *\n * **도메인 스위치**: mutation 호출은 system / 운영자 도메인에서 일어나지만 시나리오·\n * EnvVar 는 **프로젝트가 속한 도메인** 에 있어야 자연. project.domain 으로 컨텍스트\n * 스위치 후 그 도메인에서 EnvVar upsert + 시나리오 실행.\n */\n @Directive('@transaction')\n @Directive('@privilege(category: \"kpi\", privilege: \"basic-info\", domainOwnerGranted: true, superUserGranted: true)')\n @Mutation(returns => ExternalDataCollectionResult, {\n description: 'Run only 건축물관리대장조회 scenario for project basic info collection.'\n })\n async collectProjectBasicInfo(\n @Arg('projectId') projectId: string,\n @Arg('address', { nullable: true }) address: string,\n @Ctx() context: ResolverContext\n ): Promise<ExternalDataCollectionResult> {\n const projectContext = await this.switchToProjectDomain(projectId, context)\n if (address && address.trim()) {\n await this.upsertEnvVar('Step::건축물관리대장조회::address::query', address.trim(), projectContext)\n }\n return await this.runSingleScenario(\n { source: 'saeumteo', label: '세움터', name: '건축물관리대장조회' },\n projectContext\n )\n }\n\n /**\n * mutation 호출이 system / 운영자 도메인에서 일어나도 시나리오·EnvVar 는 **프로젝트\n * 테넌트 도메인** 에서 동작해야 자연. project.code 로 자식 (테넌트) 도메인을 찾아\n * 컨텍스트 사본 만들어 반환.\n *\n * 테넌트 도메인 매핑: Domain.subdomain = project.code AND Domain.extType = 'project'\n * (promoteProjectToTenant mutation 이 그렇게 생성). project.domain 자체는 부모\n * 도메인이라 외부 연동 EnvVar 가 거기 있을 일이 없어 사용 부적합.\n *\n * 테넌트 도메인이 없거나 (= 아직 승격 안 됨) project.code 가 비어있으면 원본\n * 컨텍스트 그대로 반환 (방어). project 자체가 없으면 throw.\n */\n private async switchToProjectDomain(\n projectId: string,\n context: ResolverContext\n ): Promise<ResolverContext> {\n const { tx } = context.state\n const project = await getRepository(Project, tx).findOne({ where: { id: projectId } })\n if (!project) {\n throw new Error(`Project not found: ${projectId}`)\n }\n if (!project.code) {\n console.warn(`[collect] project ${projectId} 는 아직 테넌트 승격되지 않음 (no code) — caller domain 그대로 사용`)\n return context\n }\n const tenantDomain = await getRepository(Domain, tx).findOne({\n where: { subdomain: project.code, extType: 'project' } as any\n })\n if (!tenantDomain) {\n console.warn(\n `[collect] project ${projectId} (code=${project.code}) 의 테넌트 도메인을 찾지 못함 — caller domain 그대로 사용`\n )\n return context\n }\n return {\n ...context,\n state: { ...context.state, domain: tenantDomain }\n } as ResolverContext\n }\n\n /**\n * 컨텍스트의 도메인에 EnvVar 1개 upsert. 시나리오가 도메인 EnvVar 를 우선 참조하는\n * 정책이라, 폼에서 입력한 주소를 시나리오 입력으로 흘리는 다리 역할.\n */\n private async upsertEnvVar(name: string, value: string, context: ResolverContext): Promise<void> {\n const { domain, user, tx } = context.state\n const repo = getRepository(EnvVar, tx)\n const existing = await repo.findOne({ where: { domain: { id: domain.id }, name } as any })\n if (existing) {\n existing.value = value\n existing.active = true\n ;(existing as any).updater = user\n await repo.save(existing)\n } else {\n await repo.save(\n repo.create({\n name,\n value,\n active: true,\n domain,\n description: 'Project basic info 자동 연동용 (project-update 정보연동 버튼)',\n creator: user,\n updater: user\n } as any)\n )\n }\n }\n\n /**\n * 단일 시나리오 호출 + result unwrap + 실패 판정 — collectProjectExternalData 의\n * loop 본체와 같은 로직을 1건짜리로 분리.\n */\n private async runSingleScenario(\n s: { source: string; label: string; name: string },\n context: ResolverContext\n ): Promise<ExternalDataCollectionResult> {\n const { domain } = context.state\n const instanceName = `collect-${s.name}-${Date.now()}`\n try {\n const runResult: any = await runScenario(instanceName, s.name, {}, context)\n if (!runResult) {\n console.warn(`[collect] '${s.name}' no result on domain '${domain.subdomain}'`)\n throw new Error('업데이트할 정보가 없습니다')\n }\n if (runResult.state === 'HALTED') {\n console.warn(\n `[collect] '${s.name}' HALTED on domain '${domain.subdomain}': ${runResult.message || '(no message)'}`\n )\n throw new Error('업데이트할 정보가 없습니다')\n }\n\n let data = runResult.result ?? runResult.data ?? {}\n if (data && typeof data === 'object' && !Array.isArray(data)) {\n const wrapKeys = Object.keys(data)\n if (\n wrapKeys.length === 1 &&\n data[wrapKeys[0]] &&\n typeof data[wrapKeys[0]] === 'object' &&\n !Array.isArray(data[wrapKeys[0]])\n ) {\n data = data[wrapKeys[0]]\n }\n }\n console.log(`[collect] '${s.name}' OK on '${domain.subdomain}' keys=${Object.keys(data || {}).join(',')}`)\n return { source: s.source, label: s.label, ok: true, message: '완료', data }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n console.warn(`[collect] '${s.name}' failed on '${domain.subdomain}': ${msg}`)\n return { source: s.source, label: s.label, ok: false, message: msg }\n }\n }\n\n /**\n * 외부 시스템 3종 시나리오 순차 실행 + 시스템별 결과 수집.\n */\n private async runExternalDataScenariosWithResults(context: ResolverContext): Promise<ExternalDataCollectionResult[]> {\n const { domain } = context.state\n const SCENARIOS: Array<{ source: string; label: string; name: string }> = [\n { source: 'saeumteo', label: '세움터', name: '건축물관리대장조회' },\n { source: 'allbaro', label: '올바로', name: '건설폐기물정보조회' },\n { source: 'kiscon', label: '키스콘', name: '건설공사정보조회' }\n ]\n\n const results: ExternalDataCollectionResult[] = []\n for (const s of SCENARIOS) {\n results.push(await this.runSingleScenario(s, context))\n }\n return results\n }\n\n /**\n * finalize 흐름용 시나리오 호출. 결과 형태 없이 진행만 — finalize 의 KPI 재계산이 곧\n * 이어지므로 시스템별 결과를 클라이언트에 돌려줄 필요 없음. 실패는 warning 만.\n */\n private async runExternalDataScenarios(context: ResolverContext): Promise<void> {\n await this.runExternalDataScenariosWithResults(context)\n }\n\n /**\n * 프로젝트의 모든 KPI Value들을 계층적으로 재계산합니다.\n * 1. 기존 KPI Value 삭제 (중복 방지)\n * 2. Leaf KPIs (자식이 없는 KPI): formula 기반 계산\n * 3. Parent KPIs (자식이 있는 KPI): 자식 KPI scores의 weighted average 계산\n */\n private async recalculateProjectKpiValues(projectId: string, context: ResolverContext): Promise<void> {\n const { domain, user, tx } = context.state\n const kpiValueRepo = getRepository(KpiValue, tx)\n const kpiRepo = getRepository(Kpi, tx)\n\n try {\n // 1. 기존 KPI Value 삭제 (재계산으로 인한 중복 방지)\n const existingKpiValues = await kpiValueRepo.find({\n where: {\n group: projectId,\n domain: { id: domain.id }\n }\n })\n\n if (existingKpiValues.length > 0) {\n await kpiValueRepo.remove(existingKpiValues)\n console.log(`Deleted ${existingKpiValues.length} existing KPI values for project ${projectId}`)\n }\n\n // 2. 활성 KPI 만 조회 (계층 구조 포함). 비활성 (active=false) KPI 는 재계산\n // 흐름에서 완전 제외 — 미사용 metric 참조 → formula evaluation 실패 회피.\n const allKpisRaw = await kpiRepo.find({\n relations: ['parent', 'children']\n })\n const allKpis = allKpisRaw.filter(kpi => kpi.active !== false)\n\n console.log(`Found ${allKpis.length} active KPIs (of ${allKpisRaw.length} total) for domain`)\n\n // 3. Leaf KPIs (자식이 없는 KPI)와 Parent KPIs 구분. children 중에서도 비활성은 제외.\n const leafKpis = allKpis.filter(\n kpi => kpi.isLeaf || !kpi.children || kpi.children.filter(c => c.active !== false).length === 0\n )\n const parentKpis = allKpis.filter(\n kpi => !kpi.isLeaf && kpi.children && kpi.children.filter(c => c.active !== false).length > 0\n )\n\n console.log(`Processing ${leafKpis.length} leaf KPIs and ${parentKpis.length} parent KPIs`)\n\n // 4. 먼저 Leaf KPIs를 formula로 계산\n for (const leafKpi of leafKpis) {\n try {\n await this.recalculateLeafKpiValue(leafKpi, projectId, context)\n console.log(`Successfully calculated leaf KPI: ${leafKpi.name}`)\n } catch (error) {\n console.error(`Failed to calculate leaf KPI ${leafKpi.name}:`, error.message)\n // 개별 KPI 계산 실패는 전체 프로세스를 중단하지 않음\n }\n }\n\n // 5. Parent KPIs를 계층 레벨순으로 정렬 (깊은 레벨부터)\n const sortedParentKpis = this.sortKpisByLevel(parentKpis, allKpis)\n\n // 6. Parent KPIs를 weighted average로 계산\n for (const parentKpi of sortedParentKpis) {\n try {\n await this.recalculateParentKpiValue(parentKpi, projectId, allKpis, context)\n console.log(`Successfully calculated parent KPI: ${parentKpi.name}`)\n } catch (error) {\n console.error(`Failed to calculate parent KPI ${parentKpi.name}:`, error.message)\n }\n }\n } catch (error) {\n console.error(`Error recalculating KPI values for project ${projectId}:`, error)\n throw error\n }\n }\n\n /**\n * 개별 KPI Value를 재계산합니다.\n * 항상 최신 버전의 KPI를 사용하여 계산합니다.\n */\n private async recalculateKpiValue(kpiValue: KpiValue, context: ResolverContext): Promise<KpiValue> {\n const { domain, user, tx } = context.state\n const kpiValueRepo = getRepository(KpiValue, tx)\n const kpiRepo = getRepository(Kpi, tx)\n const metricRepo = getRepository(KpiMetric, tx)\n const metricValueRepo = getRepository(KpiMetricValue, tx)\n\n // 항상 최신 버전의 KPI를 조회하여 사용\n // kpiValue.kpi가 이미 로드되어 있으면 사용하고, 없으면 DB에서 최신 버전 조회\n const kpi =\n kpiValue.kpi ||\n (await kpiRepo.findOne({\n where: { id: kpiValue.kpiId },\n order: { version: 'DESC' }\n }))\n if (!kpi) throw new Error('KPI 정보 없음')\n if (!kpi.formula) {\n console.log(`KPI ${kpi.name} has no formula, skipping recalculation`)\n return kpiValue\n }\n\n const periodType = kpi.periodType || KpiPeriodType.DAY\n const valueDate = null // kpiValue.valueDate\n const org = kpiValue.group || 'unknown' // project ID를 org로 사용\n\n // things-factory calculator 기반 formula 계산\n let kpiValueResult: number\n try {\n const ast = parseFormula(kpi.formula)\n const provider = new KpiMetricValueProvider({\n valueDate,\n org,\n domainId: domain.id,\n tx\n })\n const evalContext = { functions: builtinFunctions, provider }\n kpiValueResult = await evaluateFormula(ast, evalContext)\n\n if (kpiValueResult == null || isNaN(kpiValueResult)) {\n throw new Error('KPI formula 결과값 없음')\n }\n } catch (error) {\n console.error(`Formula evaluation failed for KPI ${kpi.name}: ${kpi.formula}`, error)\n return kpiValue // 계산 실패시 기존 값 유지\n }\n\n // KPI Value 업데이트 (최신 버전으로)\n kpiValue.value = kpiValueResult\n kpiValue.version = kpi.version || 1\n kpiValue.updater = user\n\n // 성과 점수 자동 계산 및 저장\n try {\n // 2D lookup KPI (X13 등)인 경우 project의 totalProgress 조회\n let scoreContext: { progressRate?: number } | undefined\n const gradesData = kpi.grades as any\n if (gradesData && !Array.isArray(gradesData) && gradesData.type === 'PROGRESS_DEVIATION_LOOKUP') {\n const projectId = kpiValue.group || org\n const projectRepo = getRepository(Project, tx)\n const project = await projectRepo.findOne({ where: { id: projectId } })\n scoreContext = { progressRate: project?.totalProgress ?? 50 }\n console.log(`2D lookup KPI ${kpi.name}: progressRate=${scoreContext.progressRate}%`)\n }\n\n await this.calculateAndSaveScore(kpiValue, kpi, scoreContext)\n console.log(`Successfully calculated score for KPI value ${kpiValue.id}`)\n } catch (scoreError) {\n console.error(`Failed to calculate score for KPI value ${kpiValue.id}:`, scoreError.message)\n // 성과 점수 계산 실패는 KPI Value 저장을 막지 않음\n }\n\n return await kpiValueRepo.save(kpiValue)\n }\n\n /**\n * scoreFormula를 사용한 성과 점수 계산\n */\n private async calculateScoreFromFormula(kpi: Kpi, value: number): Promise<{ score: number; calculationMethod: string } | null> {\n if (!kpi.scoreFormula) {\n return null\n }\n\n try {\n const ast = parseFormula(kpi.scoreFormula)\n const provider = {\n get: async (name: string) => {\n if (name === 'value') return value\n return null\n }\n }\n const evalContext = { functions: builtinFunctions, provider }\n const result = await evaluateFormula(ast, evalContext)\n\n if (result !== null && result !== undefined && !isNaN(result)) {\n const performanceScore = Number(result)\n\n return {\n score: performanceScore,\n calculationMethod: 'formula'\n }\n }\n } catch (error) {\n console.error(`Score formula evaluation for '${kpi.name}: ${kpi.scoreFormula}' error:`, error)\n }\n\n return null\n }\n\n /**\n * KPI의 grades lookup table을 이용한 성과 점수 변환\n * 1D (기존 배열) 및 2D (X13 공정률×편차) lookup 모두 지원\n */\n private calculateScoreFromLookup(\n kpi: Kpi,\n value: number,\n context?: { progressRate?: number }\n ): { score: number; calculationMethod: string } | null {\n if (!kpi.grades) {\n return null\n }\n\n // 2D lookup table 처리 (X13: 공정률 × 편차 → 점수)\n const grades = kpi.grades as any\n if (!Array.isArray(grades) && grades.type === 'PROGRESS_DEVIATION_LOOKUP') {\n return this.calculateScoreFrom2DLookup(value, grades, context?.progressRate)\n }\n\n // 1D lookup table 처리 (기존)\n if (!Array.isArray(grades) || grades.length === 0) {\n return null\n }\n\n const grade = grades.find((g: any) => value >= g.minValue && value <= g.maxValue)\n if (!grade) {\n return null\n }\n\n return {\n score: grade.score,\n calculationMethod: 'lookup'\n }\n }\n\n /**\n * 2D lookup table에서 점수 계산 (X13: 공정률 × 편차 → 점수 1~5)\n */\n private calculateScoreFrom2DLookup(\n deviationValue: number,\n grades: any,\n progressRate?: number\n ): { score: number; calculationMethod: string } | null {\n if (!grades.rows || !Array.isArray(grades.rows)) return null\n\n const progress = progressRate ?? 50\n const progressIndex = Math.min(99, Math.max(0, Math.floor(progress)))\n const row = grades.rows.find((r: any) => r.progressRate === progressIndex)\n if (!row) return null\n\n let score: number\n if (deviationValue < row.boundary5to4) {\n score = 5\n } else if (deviationValue < row.boundary4to3) {\n score = 4\n } else if (deviationValue < row.boundary3to2) {\n score = 3\n } else if (deviationValue < row.boundary2to1) {\n score = 2\n } else {\n score = 1\n }\n\n return { score, calculationMethod: 'PROGRESS_DEVIATION_LOOKUP' }\n }\n\n /**\n * KpiValue의 성과 점수 계산 및 저장\n * @param context.progressRate X13 등 2D lookup KPI에 필요한 공정률 (0~100)\n */\n private async calculateAndSaveScore(\n kpiValue: KpiValue,\n kpi: Kpi,\n context?: { progressRate?: number }\n ): Promise<void> {\n // 1. scoreFormula 우선 시도\n let scoreResult = await this.calculateScoreFromFormula(kpi, kpiValue.value)\n\n // 2. scoreFormula가 없거나 실패하면 grades lookup table 사용\n if (!scoreResult) {\n scoreResult = this.calculateScoreFromLookup(kpi, kpiValue.value, context)\n }\n\n if (scoreResult) {\n // KpiValue의 score 필드에 성과 점수 저장\n kpiValue.score = scoreResult.score\n console.log(`Calculated score ${scoreResult.score} for KPI ${kpi.name} with method ${scoreResult.calculationMethod}`)\n } else {\n console.log(`No score calculation method available for KPI ${kpi.name}`)\n }\n }\n\n /**\n * Leaf KPI Value를 formula로 계산합니다.\n * 참고: recalculateProjectKpiValues에서 호출 시 기존 값이 이미 삭제되었으므로 항상 새로 생성됩니다.\n */\n private async recalculateLeafKpiValue(kpi: Kpi, projectId: string, context: ResolverContext): Promise<void> {\n const { domain, user, tx } = context.state\n const kpiValueRepo = getRepository(KpiValue, tx)\n\n // 기존 KPI Value 조회 또는 생성 — 좌표별 latest version 매칭.\n let kpiValue = await kpiValueRepo.findOne({\n where: {\n kpi: { id: kpi.id },\n group: projectId,\n domain: { id: domain.id }\n },\n order: { version: 'DESC' }\n })\n\n if (!kpiValue) {\n // 새 KPI Value 생성\n kpiValue = kpiValueRepo.create({\n kpi,\n version: kpi.version || 1,\n group: projectId,\n domain,\n valueDate: new Date().toISOString().slice(0, 10),\n value: 0,\n score: 0,\n updater: user\n })\n }\n\n // formula 기반 계산\n await this.recalculateKpiValue(kpiValue, context)\n }\n\n /**\n * Parent KPI Value를 계산합니다.\n * 1. formula가 있으면 자식 KPI 값들을 변수로 사용하여 formula 계산\n * 2. formula가 없으면 자식 KPI scores의 weighted average로 계산\n * 참고: recalculateProjectKpiValues에서 호출 시 기존 값이 이미 삭제되었으므로 항상 새로 생성됩니다.\n */\n private async recalculateParentKpiValue(\n parentKpi: Kpi,\n projectId: string,\n allKpis: Kpi[],\n context: ResolverContext\n ): Promise<void> {\n const { domain, user, tx } = context.state\n const kpiValueRepo = getRepository(KpiValue, tx)\n\n // 자식 KPIs 조회\n const childKpis = allKpis.filter(kpi => kpi.parent?.id === parentKpi.id)\n\n if (childKpis.length === 0) {\n console.log(`No child KPIs found for parent KPI: ${parentKpi.name}`)\n return\n }\n\n // 자식 KPI Values 조회 — 같은 (kpi, group, domain) 좌표에 여러 version 가능.\n // version DESC 정렬 후 좌표별 latest 만 통과.\n const childKpiIds = childKpis.map(kpi => kpi.id)\n const allChildKpiValues = await kpiValueRepo.find({\n where: {\n kpi: { id: In(childKpiIds) },\n group: projectId,\n domain: { id: domain.id }\n },\n relations: ['kpi'],\n order: { version: 'DESC' }\n })\n const childLatestByKpi = new Map<string, KpiValue>()\n for (const kv of allChildKpiValues) {\n if (!childLatestByKpi.has(kv.kpi.id)) childLatestByKpi.set(kv.kpi.id, kv)\n }\n const childKpiValues = Array.from(childLatestByKpi.values())\n\n if (childKpiValues.length === 0) {\n console.log(`No child KPI values found for parent KPI: ${parentKpi.name}`)\n return\n }\n\n let calculatedValue: number\n let calculatedScore: number\n\n // 1. formula가 있으면 formula로 계산\n if (parentKpi.formula) {\n try {\n const ast = parseFormula(parentKpi.formula)\n\n // 자식 KPI 이름 -> score 값 매핑을 위한 provider\n const childKpiScoreMap: Record<string, number> = {}\n childKpiValues.forEach(kpiValue => {\n const childKpi = childKpis.find(k => k.id === kpiValue.kpi.id)\n if (childKpi) {\n childKpiScoreMap[childKpi.name] = kpiValue.score ?? 0\n }\n })\n\n const provider = {\n get: async (name: string) => {\n const value = childKpiScoreMap[name]\n if (value === undefined) {\n throw new Error(`Child KPI '${name}' not found in parent KPI formula`)\n }\n return value\n }\n }\n\n const evalContext = { functions: builtinFunctions, provider }\n const result = await evaluateFormula(ast, evalContext)\n\n calculatedValue = result\n calculatedScore = result\n\n console.log(`Calculated parent KPI ${parentKpi.name} using formula: value=${calculatedValue.toFixed(4)}`)\n } catch (error) {\n console.error(`Failed to evaluate formula for parent KPI ${parentKpi.name}:`, error)\n // formula 계산 실패 시 가중치 평균으로 대체\n const { weightedValue, weightedScore } = this.calculateWeightedAverage(childKpiValues, childKpis)\n calculatedValue = weightedValue\n calculatedScore = weightedScore\n console.log(`Fallback to weighted average for parent KPI ${parentKpi.name}`)\n }\n } else {\n // 2. formula가 없으면 가중치 평균 계산\n const { weightedValue, weightedScore } = this.calculateWeightedAverage(childKpiValues, childKpis)\n calculatedValue = weightedValue\n calculatedScore = weightedScore\n console.log(`Calculated parent KPI ${parentKpi.name} using weighted average`)\n }\n\n // 기존 Parent KPI Value 조회 또는 생성 (프로젝트 재계산 시에는 이미 삭제되어 항상 새로 생성됨)\n let parentKpiValue = await kpiValueRepo.findOne({\n where: {\n kpi: { id: parentKpi.id },\n group: projectId,\n domain: { id: domain.id }\n }\n })\n\n if (parentKpiValue) {\n // 기존 값 업데이트 (최신 버전으로)\n parentKpiValue.value = calculatedValue\n parentKpiValue.score = calculatedScore\n parentKpiValue.version = parentKpi.version || 1\n parentKpiValue.updater = user\n } else {\n // 새 값 생성\n parentKpiValue = kpiValueRepo.create({\n kpi: parentKpi,\n group: projectId,\n version: parentKpi.version || 1,\n domain,\n valueDate: new Date().toISOString().slice(0, 10),\n value: calculatedValue,\n score: calculatedScore,\n updater: user\n })\n }\n\n await kpiValueRepo.save(parentKpiValue)\n console.log(`Updated parent KPI ${parentKpi.name}: value=${calculatedValue.toFixed(4)}, score=${calculatedScore.toFixed(4)}`)\n }\n\n /**\n * KPIs를 계층 레벨순으로 정렬합니다 (깊은 레벨부터)\n */\n private sortKpisByLevel(parentKpis: Kpi[], allKpis: Kpi[]): Kpi[] {\n const kpiLevels = new Map<string, number>()\n\n const calculateLevel = (kpi: Kpi): number => {\n if (kpiLevels.has(kpi.id)) {\n return kpiLevels.get(kpi.id)!\n }\n\n if (!kpi.parent) {\n kpiLevels.set(kpi.id, 0)\n return 0\n }\n\n const parentKpi = allKpis.find(k => k.id === kpi.parent?.id)\n if (!parentKpi) {\n kpiLevels.set(kpi.id, 1)\n return 1\n }\n\n const level = calculateLevel(parentKpi) + 1\n kpiLevels.set(kpi.id, level)\n return level\n }\n\n // 각 parent KPI의 레벨 계산\n parentKpis.forEach(kpi => calculateLevel(kpi))\n\n // 레벨 순으로 정렬 (깊은 레벨부터)\n return parentKpis.sort((a, b) => (kpiLevels.get(b.id) || 0) - (kpiLevels.get(a.id) || 0))\n }\n\n /**\n * 자식 KPI values의 weighted average를 계산합니다.\n */\n private calculateWeightedAverage(childValues: any[], childKpis: Kpi[]): { weightedValue: number; weightedScore: number } {\n let totalWeightedValue = 0\n let totalWeightedScore = 0\n let totalWeight = 0\n\n for (const value of childValues) {\n const childKpi = childKpis.find(kpi => kpi.id === value.kpi.id)\n const weight = childKpi?.weight || 1\n\n totalWeightedValue += value.score * weight /* value.score 가 value 역할을 value.value 가 아니라 value.score 가 맞다. */\n totalWeightedScore += value.score * weight\n totalWeight += weight\n }\n\n if (totalWeight === 0) {\n return { weightedValue: 0, weightedScore: 0 }\n }\n\n return {\n weightedValue: totalWeightedValue / totalWeight,\n weightedScore: totalWeightedScore / totalWeight\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"kpi-metric-value-mutation.js","sourceRoot":"","sources":["../../../server/service/kpi-metric-value/kpi-metric-value-mutation.ts"],"names":[],"mappings":"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","sourcesContent":["import { Resolver, Mutation, Arg, Ctx, Directive, ObjectType, Field } from 'type-graphql'\nimport { getRepository, ScalarObject, EnvVar, Domain } from '@things-factory/shell'\nimport { runScenario } from '@things-factory/integration-base'\nimport { In } from 'typeorm'\nimport {\n KpiPeriodType,\n KpiMetric,\n KpiMetricValue,\n KpiMetricValuePatch,\n Kpi,\n KpiValue,\n parseFormula,\n evaluateFormula,\n builtinFunctions,\n KpiMetricValueProvider\n} from '@things-factory/kpi'\nimport { Attachment, NewAttachment, createAttachment } from '@things-factory/attachment-base'\nimport { Project, ProjectState } from '@dssp/project'\nimport moment from 'moment-timezone'\nimport FormData from 'form-data'\nimport fetch from 'node-fetch'\nimport https from 'https'\nimport http from 'http'\n\n/**\n * 외부 시스템 데이터 수집 결과 — 시스템별 한 row.\n * UI \"자동 수집\" 버튼이 시나리오 호출 후 시스템별 성공·오류 표시에 사용.\n */\n@ObjectType({ description: '외부 시스템(세움터/올바로/키스콘) 데이터 수집 시나리오 호출 결과' })\nclass ExternalDataCollectionResult {\n @Field({ description: '소스 키: saeumteo | allbaro | kiscon' })\n source!: string\n\n @Field({ description: '표시 라벨 (세움터/올바로/키스콘)' })\n label!: string\n\n @Field({ description: '시나리오 실행 성공 여부' })\n ok!: boolean\n\n @Field({ description: '성공 시 \"완료\", 실패 시 에러 메시지' })\n message!: string\n\n @Field(type => ScalarObject, {\n nullable: true,\n description:\n '시나리오 result 객체 — projectKey: value 맵. ' +\n '세움터={area, floorAreaRatio, upperFloorCount, lowerFloorCount, structureType, siteType}, ' +\n '올바로={totalConstructionWasteAmount}, ' +\n '키스콘={constructionPeriod, constructionCost}. ' +\n 'siteType (건축물 용도, 예 APARTMENT_COMPLEX) / structureType (구조형태) 는 ' +\n 'BuildingComplex 의 시설유형/구조유형 속성 후보. KISCON 의 \"공사유형(신설/증축)\" 은 ' +\n 'DSSP SiteType (용도분류) 와 다른 도메인이라 매핑 대상 아님.'\n })\n data?: any\n}\n\n@Resolver(KpiMetricValue)\nexport class KpiMetricValueMutation {\n /* 프로젝트 수행과정 중에 (시간, 비용, 발생 건수 등) 누적된 값을 반영하여 KPI Metric Value 값을 수정 - 예를 들면, 총 설계 변경 건수, 총 건설 폐기물 발생량, 공사비, 공사기간, 재해 건수 등 */\n @Directive('@transaction')\n @Directive('@privilege(category: \"kpi\", privilege: \"input\", domainOwnerGranted: true, superUserGranted: true)')\n @Mutation(returns => [KpiMetricValue], { description: \"To modify multiple cumulative KpiMetricValues' value\" })\n async updateKpiMetricValuesCumulative(\n @Arg('patches', type => [KpiMetricValuePatch]) patches: KpiMetricValuePatch[],\n @Ctx() context: ResolverContext\n ): Promise<KpiMetricValue[]> {\n return await this.upsertKpiMetricValues(patches, context)\n }\n\n /* 전문 감리사에 의해서 평가된 별점을 반영하여 KPI Metric Value 값을 수정 */\n @Directive('@transaction')\n @Directive('@privilege(category: \"kpi\", privilege: \"assessment\", domainOwnerGranted: true, superUserGranted: true)')\n @Mutation(returns => [KpiMetricValue], { description: \"To modify multiple assessment KpiMetricValues' value\" })\n async updateKpiMetricValuesAssessment(\n @Arg('patches', type => [KpiMetricValuePatch]) patches: KpiMetricValuePatch[],\n @Ctx() context: ResolverContext\n ): Promise<KpiMetricValue[]> {\n return await this.upsertKpiMetricValues(patches, context)\n }\n\n /**\n * KpiMetricValue 의 unique 조합 (domain, metric, valueDate, org) 기준 진짜 upsert.\n *\n * 기존 mutation 의 `repo.save({...patch})` 는 patch.id 만 보고 update/insert 결정해\n * 같은 metric × 같은 valueDate × 같은 org 인데 patch.id 가 새 UUID 인 경우 unique\n * 인덱스 (ix_kpi_metric_value_latest) 위반 에러 또는 row 누적 위험. 정확한 upsert\n * 동작을 보장하기 위해 조합 lookup → 기존 id 사용 → save.\n *\n * 월별 metric (periodType=MONTH, valueDate=YYYY-MM-01) 의 단일 row 정책을 자연 충족.\n *\n * **도메인 컨텍스트 스위치**: caller (운영자) 가 system 도메인일 수 있어 patch.org\n * (= projectId) 로 프로젝트 테넌트 도메인을 lookup 해 그 컨텍스트로 저장. 모든\n * patch 가 같은 projectId 라 가정 (한 번의 mutation = 한 프로젝트의 값들).\n */\n private async upsertKpiMetricValues(\n patches: KpiMetricValuePatch[],\n context: ResolverContext\n ): Promise<KpiMetricValue[]> {\n if (patches.length === 0) return []\n // 첫 patch.org 의 projectId 로 도메인 스위치. patch.org 가 없으면 caller context 그대로.\n const projectId = (patches[0] as any).org\n const ctx = projectId ? await this.switchToProjectDomain(projectId, context) : context\n const { domain, user, tx } = ctx.state\n const metricValueRepo = getRepository(KpiMetricValue, tx)\n const metricRepo = getRepository(KpiMetric, tx)\n\n const results: KpiMetricValue[] = []\n for (const patch of patches) {\n const metric = await metricRepo.findOne({ where: { id: patch.metricId } })\n if (!metric) {\n throw new Error(`Metric not found: ${patch.metricId}`)\n }\n // unique 조합 기준 기존 row lookup. 있으면 그 id 로 save → update.\n const existing = await metricValueRepo.findOne({\n where: {\n domain: { id: domain.id },\n metric: { id: patch.metricId },\n valueDate: patch.valueDate,\n org: patch.org\n } as any\n })\n const result = await metricValueRepo.save({\n domain,\n ...patch,\n id: existing?.id ?? patch.id,\n metric,\n updater: user\n } as any)\n results.push(result)\n }\n return results\n }\n\n /* 전문 감리사에 의 감리 최종 평가서의 긍부정을 텍스트 분석하는 감정 분석 기반 평가값을 수정 */\n @Directive('@transaction')\n @Directive('@privilege(category: \"kpi\", privilege: \"sentiment\", domainOwnerGranted: true, superUserGranted: true)')\n @Mutation(returns => Attachment, { nullable: true, description: \"To modify multiple sentiment KpiMetricValues' value\" })\n async updateKpiMetricValuesSentiment(\n @Arg('attachment', type => NewAttachment) attachment: NewAttachment,\n @Ctx() context: ResolverContext\n ): Promise<Attachment | null> {\n const { domain, user, tx } = context.state\n const projectRepo = getRepository(Project, tx)\n const projectId = attachment.refBy\n const attachmentRepo = getRepository(Attachment, tx)\n const metricValueRepo = getRepository(KpiMetricValue, tx)\n const metricRepo = getRepository(KpiMetric, tx)\n\n // 1. 기존 파일 삭제\n projectRepo.update(projectId, { completeReport: null })\n await attachmentRepo.delete({ refBy: projectId, refType: attachment.refType })\n\n // 2. 새 파일 없으면 끝\n if (!attachment.file) {\n return null\n }\n\n // 3. 먼저 파일을 버퍼로 읽기 (스트림은 한 번만 읽을 수 있으므로)\n const uploadedFile = await attachment.file\n const { filename } = uploadedFile\n const fileBuffer = await this.readFileToBuffer(uploadedFile)\n\n console.log(`Processing PDF file: ${filename}, size: ${fileBuffer.length} bytes`)\n\n // 4. 새 파일 저장 (버퍼를 사용하여 attachment 생성)\n const recreatedFile = this.createFileUploadFromBuffer(fileBuffer, filename, 'application/pdf')\n const { id: resultId } = await createAttachment(null, { attachment: { ...attachment, file: recreatedFile } }, context)\n const result = await attachmentRepo.findOne({ where: { id: resultId } })\n projectRepo.update(projectId, { completeReport: result })\n\n // 5. pdf 파일을 operator-runner 서비스에 업로드하여 분석\n let safetyScore = 0\n let qualityScore = 0\n\n try {\n const operatorRunnerUrl = process.env.OPERATOR_RUNNER_URL || 'https://hatiolab-korea-uni.ettisoft.com'\n\n // sl-pa-safety 서비스 호출\n safetyScore = await this.callOperatorRunnerServiceWithBuffer(operatorRunnerUrl, 'sl-pa-safety', fileBuffer, filename)\n\n // sl-pa-quality 서비스 호출\n qualityScore = await this.callOperatorRunnerServiceWithBuffer(operatorRunnerUrl, 'sl-pa-quality', fileBuffer, filename)\n } catch (error) {\n console.error('Failed to analyze PDF with operator-runner:', error)\n }\n\n // 5. 메트릭 점수 저장\n await this.saveMetricValue(metricValueRepo, metricRepo, projectId, 'SL-PA 안전 평가', safetyScore, domain, user)\n await this.saveMetricValue(metricValueRepo, metricRepo, projectId, 'SL-PA 품질 평가', qualityScore, domain, user)\n\n return result\n }\n\n /**\n * FileUpload 스트림을 버퍼로 읽기\n */\n private async readFileToBuffer(fileUpload: any): Promise<Buffer> {\n const { createReadStream } = fileUpload\n const chunks: Buffer[] = []\n\n return new Promise((resolve, reject) => {\n const stream = createReadStream()\n stream.on('data', (chunk: Buffer) => chunks.push(chunk))\n stream.on('end', () => resolve(Buffer.concat(chunks)))\n stream.on('error', (error: Error) => reject(error))\n })\n }\n\n /**\n * Buffer로부터 FileUpload 객체 생성\n */\n private createFileUploadFromBuffer(buffer: Buffer, filename: string, mimetype: string): any {\n const { Readable } = require('stream')\n return {\n filename,\n mimetype,\n encoding: '7bit',\n createReadStream: () => {\n const readable = new Readable()\n readable.push(buffer)\n readable.push(null)\n return readable\n }\n }\n }\n\n /**\n * operator-runner 서비스 호출 (Buffer 사용)\n */\n private async callOperatorRunnerServiceWithBuffer(\n baseUrl: string,\n serviceName: string,\n fileBuffer: Buffer,\n filename: string\n ): Promise<number> {\n console.log(`Calling operator-runner service: ${serviceName}`)\n console.log(`Base URL: ${baseUrl}`)\n console.log(`Filename: ${filename}`)\n console.log(`Buffer size: ${fileBuffer.length} bytes`)\n\n const formData = new FormData()\n\n // Buffer를 스트림으로 변환하여 추가\n const { Readable } = require('stream')\n const bufferStream = Readable.from(fileBuffer)\n\n formData.append('files', bufferStream, {\n filename,\n contentType: 'application/pdf'\n })\n\n const url = `${baseUrl}/api/run/${serviceName}`\n console.log(`Request URL: ${url}`)\n\n // HTTP/HTTPS agent 설정\n const isHttps = url.startsWith('https')\n const agent = isHttps\n ? new https.Agent({\n keepAlive: false,\n timeout: 120000,\n rejectUnauthorized: false\n })\n : new http.Agent({\n keepAlive: false,\n timeout: 120000\n })\n\n try {\n const response = await fetch(url, {\n method: 'POST',\n body: formData as any,\n headers: {\n ...formData.getHeaders(),\n Authorization: `Basic ${Buffer.from('admin:admin1234').toString('base64')}`\n },\n agent,\n timeout: 120000\n })\n\n console.log(`Response status: ${response.status}`)\n\n if (!response.ok) {\n const errorText = await response.text()\n console.error(`Service ${serviceName} error response:`, errorText)\n throw new Error(`Service ${serviceName} failed (${response.status}): ${errorText}`)\n }\n\n const data = await response.json()\n console.log(`Service ${serviceName} response:`, JSON.stringify(data))\n\n const score = data?.result?.score || data?.score || 0\n console.log(`Extracted score: ${score}`)\n\n return score\n } catch (error) {\n console.error(`Error calling ${serviceName}:`, error)\n throw error\n }\n }\n\n /**\n * 메트릭 값 저장\n */\n private async saveMetricValue(\n metricValueRepo: any,\n metricRepo: any,\n projectId: string,\n metricName: string,\n value: number,\n domain: any,\n user: any\n ): Promise<void> {\n const metricValue = await metricValueRepo.findOne({\n where: { org: projectId, metric: { name: metricName } }\n })\n\n if (metricValue) {\n await metricValueRepo.save({\n ...metricValue,\n value,\n updater: user\n })\n } else {\n const originMetric = await metricRepo.findOne({ where: { name: metricName } })\n if (originMetric) {\n await metricValueRepo.save({\n metric: { id: originMetric.id },\n unit: originMetric.unit || '',\n org: projectId,\n periodType: originMetric.periodType,\n valueDate: moment().tz('Asia/Seoul').format('YYYY-MM-DD'),\n value,\n domain,\n updater: user\n })\n }\n }\n }\n\n @Directive('@transaction')\n @Directive('@privilege(category: \"kpi\", privilege: \"finalize\", domainOwnerGranted: true, superUserGranted: true)')\n @Mutation(returns => Boolean, { description: 'To finalize project with KPI recalculation' })\n async finalizeProjectWithKpiRecalculation(\n @Arg('projectId') projectId: string,\n @Ctx() context: ResolverContext\n ): Promise<boolean> {\n const { domain, user, tx } = context.state\n const projectRepo = getRepository(Project, tx)\n\n const project = await projectRepo.findOne({ where: { id: projectId } })\n\n console.log('project :', project)\n\n if (!project) {\n throw new Error(`Project not found: ${projectId}`)\n }\n\n // KPI value 계산은 프로젝트(테넌트) 도메인 기준이라 컨텍스트 스위치.\n // 외부 시스템 데이터 수집은 별도 mutation (collectProjectExternalData) 로 분리 —\n // 사용자가 UI \"자동 수집\" 버튼으로 명시 실행. finalize/recalculate 흐름에서는\n // 외부 연동을 끌어들이지 않음 (DB 에 이미 저장된 KpiMetricValue 만 가지고 계산).\n const projectContext = await this.switchToProjectDomain(projectId, context)\n\n await this.recalculateProjectKpiValues(projectId, projectContext)\n\n projectRepo.save({\n ...project,\n state: ProjectState.COMPLETED\n })\n\n return true\n }\n\n /**\n * 완공 처리 없이 KPI 만 재계산 — 진행 중 프로젝트의 중간 결과 산정 용도.\n * DB 에 이미 저장된 KpiMetricValue 만 가지고 formula 평가. 외부 시나리오 (juso/\n * allbaro/kiscon) 자동 수집은 의도적으로 호출하지 않음 — 외부 수집은 사용자가\n * \"자동 수집\" 버튼 (`collectProjectExternalData`) 으로 명시적으로 실행하는 흐름.\n * 권한은 `kpi:recalculate` 로 분리해 finalize 보다 가볍게 부여 가능.\n */\n @Directive('@transaction')\n @Directive('@privilege(category: \"kpi\", privilege: \"recalculate\", domainOwnerGranted: true, superUserGranted: true)')\n @Mutation(returns => Boolean, { description: 'Recalculate project KPI without finalizing (interim).' })\n async recalculateProjectKpi(\n @Arg('projectId') projectId: string,\n @Ctx() context: ResolverContext\n ): Promise<boolean> {\n const { tx } = context.state\n const project = await getRepository(Project, tx).findOne({ where: { id: projectId } })\n if (!project) {\n throw new Error(`Project not found: ${projectId}`)\n }\n\n const projectContext = await this.switchToProjectDomain(projectId, context)\n await this.recalculateProjectKpiValues(projectId, projectContext)\n\n return true\n }\n\n /**\n * UI \"자동 수집\" 버튼 전용 mutation. 외부 시스템 3종 시나리오를 순차 호출하고\n * 시스템별 성공/실패 + 메시지를 반환. UI 는 결과를 보고 카드별 상태 (성공·오류) 를 표시.\n *\n * 시나리오는 도메인 EnvVar (주소·자격증명·서비스키 등) 만으로 동작하므로 파라미터 X.\n * 한 시스템 실패가 다른 시스템 수집을 막지 않도록 try/catch 로 격리.\n *\n * 운영 현실: 키스콘·올바로는 시공사 ID/PW 가 자주 미확보 → 오류 흔함. 세움터는 공공\n * 데이터 서비스키만으로 동작 가능. UI 는 시스템별로 명확한 오류 메시지 노출.\n */\n @Directive('@privilege(category: \"kpi\", privilege: \"auto-collect\", domainOwnerGranted: true, superUserGranted: true)')\n @Mutation(returns => [ExternalDataCollectionResult], {\n description: 'Run external data collection scenarios per system, returning per-system result.'\n })\n async collectProjectExternalData(\n @Arg('projectId') projectId: string,\n @Ctx() context: ResolverContext\n ): Promise<ExternalDataCollectionResult[]> {\n const projectContext = await this.switchToProjectDomain(projectId, context)\n return await this.runExternalDataScenariosWithResults(projectContext)\n }\n\n /**\n * 프로젝트 정보 수정 화면의 \"정보 연동\" 버튼 전용 — 세움터 단일 시나리오만 호출.\n * BuildingComplex 기본 속성 (area / floorAreaRatio / siteType / structureType /\n * coverageRatio / householdCount 등) 자동 채움 목적.\n *\n * address 인자가 있으면 시나리오 실행 전에 EnvVar `Step::건축물관리대장조회::address::query`\n * 를 그 값으로 upsert — 운영자가 폼에서 방금 입력한 주소를 시나리오가 곧바로 사용.\n * (도메인의 기존 EnvVar 와 다를 수 있어 명시적 갱신.)\n *\n * **도메인 스위치**: mutation 호출은 system / 운영자 도메인에서 일어나지만 시나리오·\n * EnvVar 는 **프로젝트가 속한 도메인** 에 있어야 자연. project.domain 으로 컨텍스트\n * 스위치 후 그 도메인에서 EnvVar upsert + 시나리오 실행.\n */\n @Directive('@transaction')\n @Directive('@privilege(category: \"kpi\", privilege: \"basic-info\", domainOwnerGranted: true, superUserGranted: true)')\n @Mutation(returns => ExternalDataCollectionResult, {\n description: 'Run only 건축물관리대장조회 scenario for project basic info collection.'\n })\n async collectProjectBasicInfo(\n @Arg('projectId') projectId: string,\n @Arg('address', { nullable: true }) address: string,\n @Ctx() context: ResolverContext\n ): Promise<ExternalDataCollectionResult> {\n const projectContext = await this.switchToProjectDomain(projectId, context)\n if (address && address.trim()) {\n await this.upsertEnvVar('Step::건축물관리대장조회::address::query', address.trim(), projectContext)\n }\n return await this.runSingleScenario(\n { source: 'saeumteo', label: '세움터', name: '건축물관리대장조회' },\n projectContext\n )\n }\n\n /**\n * mutation 호출이 system / 운영자 도메인에서 일어나도 시나리오·EnvVar 는 **프로젝트\n * 테넌트 도메인** 에서 동작해야 자연. project.code 로 자식 (테넌트) 도메인을 찾아\n * 컨텍스트 사본 만들어 반환.\n *\n * 테넌트 도메인 매핑: Domain.subdomain = project.code AND Domain.extType = 'project'\n * (promoteProjectToTenant mutation 이 그렇게 생성). project.domain 자체는 부모\n * 도메인이라 외부 연동 EnvVar 가 거기 있을 일이 없어 사용 부적합.\n *\n * 테넌트 도메인이 없거나 (= 아직 승격 안 됨) project.code 가 비어있으면 원본\n * 컨텍스트 그대로 반환 (방어). project 자체가 없으면 throw.\n */\n private async switchToProjectDomain(\n projectId: string,\n context: ResolverContext\n ): Promise<ResolverContext> {\n const { tx } = context.state\n const project = await getRepository(Project, tx).findOne({ where: { id: projectId } })\n if (!project) {\n throw new Error(`Project not found: ${projectId}`)\n }\n if (!project.code) {\n console.warn(`[collect] project ${projectId} 는 아직 테넌트 승격되지 않음 (no code) — caller domain 그대로 사용`)\n return context\n }\n const tenantDomain = await getRepository(Domain, tx).findOne({\n where: { subdomain: project.code, extType: 'project' } as any\n })\n if (!tenantDomain) {\n console.warn(\n `[collect] project ${projectId} (code=${project.code}) 의 테넌트 도메인을 찾지 못함 — caller domain 그대로 사용`\n )\n return context\n }\n return {\n ...context,\n state: { ...context.state, domain: tenantDomain }\n } as ResolverContext\n }\n\n /**\n * 컨텍스트의 도메인에 EnvVar 1개 upsert. 시나리오가 도메인 EnvVar 를 우선 참조하는\n * 정책이라, 폼에서 입력한 주소를 시나리오 입력으로 흘리는 다리 역할.\n */\n private async upsertEnvVar(name: string, value: string, context: ResolverContext): Promise<void> {\n const { domain, user, tx } = context.state\n const repo = getRepository(EnvVar, tx)\n const existing = await repo.findOne({ where: { domain: { id: domain.id }, name } as any })\n if (existing) {\n existing.value = value\n existing.active = true\n ;(existing as any).updater = user\n await repo.save(existing)\n } else {\n await repo.save(\n repo.create({\n name,\n value,\n active: true,\n domain,\n description: 'Project basic info 자동 연동용 (project-update 정보연동 버튼)',\n creator: user,\n updater: user\n } as any)\n )\n }\n }\n\n /**\n * 단일 시나리오 호출 + result unwrap + 실패 판정 — collectProjectExternalData 의\n * loop 본체와 같은 로직을 1건짜리로 분리.\n */\n private async runSingleScenario(\n s: { source: string; label: string; name: string },\n context: ResolverContext\n ): Promise<ExternalDataCollectionResult> {\n const { domain } = context.state\n const instanceName = `collect-${s.name}-${Date.now()}`\n try {\n const runResult: any = await runScenario(instanceName, s.name, {}, context)\n if (!runResult) {\n console.warn(`[collect] '${s.name}' no result on domain '${domain.subdomain}'`)\n throw new Error('업데이트할 정보가 없습니다')\n }\n if (runResult.state === 'HALTED') {\n console.warn(\n `[collect] '${s.name}' HALTED on domain '${domain.subdomain}': ${runResult.message || '(no message)'}`\n )\n throw new Error('업데이트할 정보가 없습니다')\n }\n\n let data = runResult.result ?? runResult.data ?? {}\n if (data && typeof data === 'object' && !Array.isArray(data)) {\n const wrapKeys = Object.keys(data)\n if (\n wrapKeys.length === 1 &&\n data[wrapKeys[0]] &&\n typeof data[wrapKeys[0]] === 'object' &&\n !Array.isArray(data[wrapKeys[0]])\n ) {\n data = data[wrapKeys[0]]\n }\n }\n console.log(`[collect] '${s.name}' OK on '${domain.subdomain}' keys=${Object.keys(data || {}).join(',')}`)\n return { source: s.source, label: s.label, ok: true, message: '완료', data }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n console.warn(`[collect] '${s.name}' failed on '${domain.subdomain}': ${msg}`)\n return { source: s.source, label: s.label, ok: false, message: msg }\n }\n }\n\n /**\n * 외부 시스템 3종 시나리오 순차 실행 + 시스템별 결과 수집.\n */\n private async runExternalDataScenariosWithResults(context: ResolverContext): Promise<ExternalDataCollectionResult[]> {\n const { domain } = context.state\n const SCENARIOS: Array<{ source: string; label: string; name: string }> = [\n { source: 'saeumteo', label: '세움터', name: '건축물관리대장조회' },\n { source: 'allbaro', label: '올바로', name: '건설폐기물정보조회' },\n { source: 'kiscon', label: '키스콘', name: '건설공사정보조회' }\n ]\n\n const results: ExternalDataCollectionResult[] = []\n for (const s of SCENARIOS) {\n results.push(await this.runSingleScenario(s, context))\n }\n return results\n }\n\n /**\n * finalize 흐름용 시나리오 호출. 결과 형태 없이 진행만 — finalize 의 KPI 재계산이 곧\n * 이어지므로 시스템별 결과를 클라이언트에 돌려줄 필요 없음. 실패는 warning 만.\n */\n private async runExternalDataScenarios(context: ResolverContext): Promise<void> {\n await this.runExternalDataScenariosWithResults(context)\n }\n\n /**\n * 프로젝트의 모든 KPI Value들을 계층적으로 재계산합니다.\n * 1. 기존 KPI Value 삭제 (중복 방지)\n * 2. Leaf KPIs (자식이 없는 KPI): formula 기반 계산\n * 3. Parent KPIs (자식이 있는 KPI): 자식 KPI scores의 weighted average 계산\n */\n private async recalculateProjectKpiValues(projectId: string, context: ResolverContext): Promise<void> {\n const { domain, user, tx } = context.state\n const kpiValueRepo = getRepository(KpiValue, tx)\n const kpiRepo = getRepository(Kpi, tx)\n\n try {\n // 1. 기존 KPI Value 삭제 (재계산으로 인한 중복 방지)\n const existingKpiValues = await kpiValueRepo.find({\n where: {\n group: projectId,\n domain: { id: domain.id }\n }\n })\n\n if (existingKpiValues.length > 0) {\n await kpiValueRepo.remove(existingKpiValues)\n console.log(`Deleted ${existingKpiValues.length} existing KPI values for project ${projectId}`)\n }\n\n // 2. 활성 KPI 만 조회 (계층 구조 포함). 비활성 (active=false) KPI 는 재계산\n // 흐름에서 완전 제외 — 미사용 metric 참조 → formula evaluation 실패 회피.\n const allKpisRaw = await kpiRepo.find({\n relations: ['parent', 'children']\n })\n const allKpis = allKpisRaw.filter(kpi => kpi.active !== false)\n\n console.log(`Found ${allKpis.length} active KPIs (of ${allKpisRaw.length} total) for domain`)\n\n // 3. Leaf KPIs (자식이 없는 KPI)와 Parent KPIs 구분. children 중에서도 비활성은 제외.\n const leafKpis = allKpis.filter(\n kpi => kpi.isLeaf || !kpi.children || kpi.children.filter(c => c.active !== false).length === 0\n )\n const parentKpis = allKpis.filter(\n kpi => !kpi.isLeaf && kpi.children && kpi.children.filter(c => c.active !== false).length > 0\n )\n\n console.log(`Processing ${leafKpis.length} leaf KPIs and ${parentKpis.length} parent KPIs`)\n\n // 4. 먼저 Leaf KPIs를 formula로 계산\n for (const leafKpi of leafKpis) {\n try {\n await this.recalculateLeafKpiValue(leafKpi, projectId, context)\n console.log(`Successfully calculated leaf KPI: ${leafKpi.name}`)\n } catch (error) {\n console.error(`Failed to calculate leaf KPI ${leafKpi.name}:`, error.message)\n // 개별 KPI 계산 실패는 전체 프로세스를 중단하지 않음\n }\n }\n\n // 5. Parent KPIs를 계층 레벨순으로 정렬 (깊은 레벨부터)\n const sortedParentKpis = this.sortKpisByLevel(parentKpis, allKpis)\n\n // 6. Parent KPIs를 weighted average로 계산\n for (const parentKpi of sortedParentKpis) {\n try {\n await this.recalculateParentKpiValue(parentKpi, projectId, allKpis, context)\n console.log(`Successfully calculated parent KPI: ${parentKpi.name}`)\n } catch (error) {\n console.error(`Failed to calculate parent KPI ${parentKpi.name}:`, error.message)\n }\n }\n } catch (error) {\n console.error(`Error recalculating KPI values for project ${projectId}:`, error)\n throw error\n }\n }\n\n /**\n * 개별 KPI Value를 재계산합니다.\n * 항상 최신 버전의 KPI를 사용하여 계산합니다.\n */\n private async recalculateKpiValue(kpiValue: KpiValue, context: ResolverContext): Promise<KpiValue> {\n const { domain, user, tx } = context.state\n const kpiValueRepo = getRepository(KpiValue, tx)\n const kpiRepo = getRepository(Kpi, tx)\n const metricRepo = getRepository(KpiMetric, tx)\n const metricValueRepo = getRepository(KpiMetricValue, tx)\n\n // 항상 최신 버전의 KPI를 조회하여 사용\n // kpiValue.kpi가 이미 로드되어 있으면 사용하고, 없으면 DB에서 최신 버전 조회\n const kpi =\n kpiValue.kpi ||\n (await kpiRepo.findOne({\n where: { id: kpiValue.kpiId },\n order: { version: 'DESC' }\n }))\n if (!kpi) throw new Error('KPI 정보 없음')\n if (!kpi.formula) {\n console.log(`KPI ${kpi.name} has no formula, skipping recalculation`)\n return kpiValue\n }\n\n const periodType = kpi.periodType || KpiPeriodType.DAY\n const valueDate = null // kpiValue.valueDate\n const org = kpiValue.group || 'unknown' // project ID를 org로 사용\n\n // things-factory calculator 기반 formula 계산\n let kpiValueResult: number\n try {\n const ast = parseFormula(kpi.formula)\n const provider = new KpiMetricValueProvider({\n valueDate,\n org,\n domainId: domain.id,\n tx\n })\n const evalContext = { functions: builtinFunctions, provider }\n kpiValueResult = await evaluateFormula(ast, evalContext)\n\n if (kpiValueResult == null || isNaN(kpiValueResult)) {\n throw new Error('KPI formula 결과값 없음')\n }\n } catch (error) {\n console.error(`Formula evaluation failed for KPI ${kpi.name}: ${kpi.formula}`, error)\n return kpiValue // 계산 실패시 기존 값 유지\n }\n\n // KPI Value 업데이트 (최신 버전으로)\n kpiValue.value = kpiValueResult\n kpiValue.version = kpi.version || 1\n kpiValue.updater = user\n\n // 성과 점수 자동 계산 및 저장\n try {\n // 2D lookup KPI (X13 등) 의 progressRate — KpiMetric '실적공정율' latest value 우선.\n // 없으면 project.totalProgress fallback. client kpi-2d-lookup-chart 와 동일 source.\n let scoreContext: { progressRate?: number } | undefined\n const gradesData = kpi.grades as any\n if (gradesData && !Array.isArray(gradesData) && gradesData.type === 'PROGRESS_DEVIATION_LOOKUP') {\n const projectId = kpiValue.group || org\n let progressRate: number | null = null\n\n const progressMetric = await getRepository(KpiMetric, tx).findOne({\n where: { name: '실적공정율' }\n })\n if (progressMetric) {\n const latest = await getRepository(KpiMetricValue, tx).findOne({\n where: { metric: { id: progressMetric.id }, org: projectId },\n order: { valueDate: 'DESC' }\n })\n if (latest?.value != null) progressRate = latest.value\n }\n if (progressRate === null) {\n const project = await getRepository(Project, tx).findOne({ where: { id: projectId } })\n progressRate = project?.totalProgress ?? 50\n }\n scoreContext = { progressRate }\n console.log(\n `2D lookup KPI ${kpi.name}: progressRate=${scoreContext.progressRate}% (실적공정율 metric latest 우선)`\n )\n }\n\n await this.calculateAndSaveScore(kpiValue, kpi, scoreContext)\n console.log(`Successfully calculated score for KPI value ${kpiValue.id}`)\n } catch (scoreError) {\n console.error(`Failed to calculate score for KPI value ${kpiValue.id}:`, scoreError.message)\n // 성과 점수 계산 실패는 KPI Value 저장을 막지 않음\n }\n\n return await kpiValueRepo.save(kpiValue)\n }\n\n /**\n * scoreFormula를 사용한 성과 점수 계산\n */\n private async calculateScoreFromFormula(kpi: Kpi, value: number): Promise<{ score: number; calculationMethod: string } | null> {\n if (!kpi.scoreFormula) {\n return null\n }\n\n try {\n const ast = parseFormula(kpi.scoreFormula)\n const provider = {\n get: async (name: string) => {\n if (name === 'value') return value\n return null\n }\n }\n const evalContext = { functions: builtinFunctions, provider }\n const result = await evaluateFormula(ast, evalContext)\n\n if (result !== null && result !== undefined && !isNaN(result)) {\n const performanceScore = Number(result)\n\n return {\n score: performanceScore,\n calculationMethod: 'formula'\n }\n }\n } catch (error) {\n console.error(`Score formula evaluation for '${kpi.name}: ${kpi.scoreFormula}' error:`, error)\n }\n\n return null\n }\n\n /**\n * KPI의 grades lookup table을 이용한 성과 점수 변환\n * 1D (기존 배열) 및 2D (X13 공정률×편차) lookup 모두 지원\n */\n private calculateScoreFromLookup(\n kpi: Kpi,\n value: number,\n context?: { progressRate?: number }\n ): { score: number; calculationMethod: string } | null {\n if (!kpi.grades) {\n return null\n }\n\n // 2D lookup table 처리 (X13: 공정률 × 편차 → 점수)\n const grades = kpi.grades as any\n if (!Array.isArray(grades) && grades.type === 'PROGRESS_DEVIATION_LOOKUP') {\n return this.calculateScoreFrom2DLookup(value, grades, context?.progressRate)\n }\n\n // 1D lookup table 처리 (기존)\n if (!Array.isArray(grades) || grades.length === 0) {\n return null\n }\n\n const grade = grades.find((g: any) => value >= g.minValue && value <= g.maxValue)\n if (!grade) {\n return null\n }\n\n return {\n score: grade.score,\n calculationMethod: 'lookup'\n }\n }\n\n /**\n * 2D lookup table에서 점수 계산 (X13: 공정률 × 편차 → 점수 1~5)\n *\n * 단위 정합:\n * - deviationValue (= KpiMetric '일정 이탈 수준' value): % 단위 (예: 2.5 = 2.5%).\n * - row.boundary*: ratio 단위 (예: 0.025 = 2.5%).\n * - 비교 전 deviationValue 를 /100 해서 ratio 로 변환.\n */\n private calculateScoreFrom2DLookup(\n deviationValue: number,\n grades: any,\n progressRate?: number\n ): { score: number; calculationMethod: string } | null {\n if (!grades.rows || !Array.isArray(grades.rows)) return null\n\n const progress = progressRate ?? 50\n const progressIndex = Math.min(99, Math.max(0, Math.floor(progress)))\n const row = grades.rows.find((r: any) => r.progressRate === progressIndex)\n if (!row) return null\n\n const devRatio = deviationValue / 100\n\n let score: number\n if (devRatio < row.boundary5to4) {\n score = 5\n } else if (devRatio < row.boundary4to3) {\n score = 4\n } else if (devRatio < row.boundary3to2) {\n score = 3\n } else if (devRatio < row.boundary2to1) {\n score = 2\n } else {\n score = 1\n }\n\n return { score, calculationMethod: 'PROGRESS_DEVIATION_LOOKUP' }\n }\n\n /**\n * KpiValue의 성과 점수 계산 및 저장\n * @param context.progressRate X13 등 2D lookup KPI에 필요한 공정률 (0~100)\n */\n private async calculateAndSaveScore(\n kpiValue: KpiValue,\n kpi: Kpi,\n context?: { progressRate?: number }\n ): Promise<void> {\n // 1. scoreFormula 우선 시도\n let scoreResult = await this.calculateScoreFromFormula(kpi, kpiValue.value)\n\n // 2. scoreFormula가 없거나 실패하면 grades lookup table 사용\n if (!scoreResult) {\n scoreResult = this.calculateScoreFromLookup(kpi, kpiValue.value, context)\n }\n\n if (scoreResult) {\n // KpiValue의 score 필드에 성과 점수 저장\n kpiValue.score = scoreResult.score\n console.log(`Calculated score ${scoreResult.score} for KPI ${kpi.name} with method ${scoreResult.calculationMethod}`)\n } else {\n console.log(`No score calculation method available for KPI ${kpi.name}`)\n }\n }\n\n /**\n * Leaf KPI Value를 formula로 계산합니다.\n * 참고: recalculateProjectKpiValues에서 호출 시 기존 값이 이미 삭제되었으므로 항상 새로 생성됩니다.\n */\n private async recalculateLeafKpiValue(kpi: Kpi, projectId: string, context: ResolverContext): Promise<void> {\n const { domain, user, tx } = context.state\n const kpiValueRepo = getRepository(KpiValue, tx)\n\n // 기존 KPI Value 조회 또는 생성 — 좌표별 latest version 매칭.\n let kpiValue = await kpiValueRepo.findOne({\n where: {\n kpi: { id: kpi.id },\n group: projectId,\n domain: { id: domain.id }\n },\n order: { version: 'DESC' }\n })\n\n if (!kpiValue) {\n // 새 KPI Value 생성\n kpiValue = kpiValueRepo.create({\n kpi,\n version: kpi.version || 1,\n group: projectId,\n domain,\n valueDate: new Date().toISOString().slice(0, 10),\n value: 0,\n score: 0,\n updater: user\n })\n }\n\n // formula 기반 계산\n await this.recalculateKpiValue(kpiValue, context)\n }\n\n /**\n * Parent KPI Value를 계산합니다.\n * 1. formula가 있으면 자식 KPI 값들을 변수로 사용하여 formula 계산\n * 2. formula가 없으면 자식 KPI scores의 weighted average로 계산\n * 참고: recalculateProjectKpiValues에서 호출 시 기존 값이 이미 삭제되었으므로 항상 새로 생성됩니다.\n */\n private async recalculateParentKpiValue(\n parentKpi: Kpi,\n projectId: string,\n allKpis: Kpi[],\n context: ResolverContext\n ): Promise<void> {\n const { domain, user, tx } = context.state\n const kpiValueRepo = getRepository(KpiValue, tx)\n\n // 자식 KPIs 조회\n const childKpis = allKpis.filter(kpi => kpi.parent?.id === parentKpi.id)\n\n if (childKpis.length === 0) {\n console.log(`No child KPIs found for parent KPI: ${parentKpi.name}`)\n return\n }\n\n // 자식 KPI Values 조회 — 같은 (kpi, group, domain) 좌표에 여러 version 가능.\n // version DESC 정렬 후 좌표별 latest 만 통과.\n const childKpiIds = childKpis.map(kpi => kpi.id)\n const allChildKpiValues = await kpiValueRepo.find({\n where: {\n kpi: { id: In(childKpiIds) },\n group: projectId,\n domain: { id: domain.id }\n },\n relations: ['kpi'],\n order: { version: 'DESC' }\n })\n const childLatestByKpi = new Map<string, KpiValue>()\n for (const kv of allChildKpiValues) {\n if (!childLatestByKpi.has(kv.kpi.id)) childLatestByKpi.set(kv.kpi.id, kv)\n }\n const childKpiValues = Array.from(childLatestByKpi.values())\n\n if (childKpiValues.length === 0) {\n console.log(`No child KPI values found for parent KPI: ${parentKpi.name}`)\n return\n }\n\n let calculatedValue: number\n let calculatedScore: number\n\n // 1. formula가 있으면 formula로 계산\n if (parentKpi.formula) {\n try {\n const ast = parseFormula(parentKpi.formula)\n\n // 자식 KPI 이름 -> score 값 매핑을 위한 provider\n const childKpiScoreMap: Record<string, number> = {}\n childKpiValues.forEach(kpiValue => {\n const childKpi = childKpis.find(k => k.id === kpiValue.kpi.id)\n if (childKpi) {\n childKpiScoreMap[childKpi.name] = kpiValue.score ?? 0\n }\n })\n\n const provider = {\n get: async (name: string) => {\n const value = childKpiScoreMap[name]\n if (value === undefined) {\n throw new Error(`Child KPI '${name}' not found in parent KPI formula`)\n }\n return value\n }\n }\n\n const evalContext = { functions: builtinFunctions, provider }\n const result = await evaluateFormula(ast, evalContext)\n\n calculatedValue = result\n calculatedScore = result\n\n console.log(`Calculated parent KPI ${parentKpi.name} using formula: value=${calculatedValue.toFixed(4)}`)\n } catch (error) {\n console.error(`Failed to evaluate formula for parent KPI ${parentKpi.name}:`, error)\n // formula 계산 실패 시 가중치 평균으로 대체\n const { weightedValue, weightedScore } = this.calculateWeightedAverage(childKpiValues, childKpis)\n calculatedValue = weightedValue\n calculatedScore = weightedScore\n console.log(`Fallback to weighted average for parent KPI ${parentKpi.name}`)\n }\n } else {\n // 2. formula가 없으면 가중치 평균 계산\n const { weightedValue, weightedScore } = this.calculateWeightedAverage(childKpiValues, childKpis)\n calculatedValue = weightedValue\n calculatedScore = weightedScore\n console.log(`Calculated parent KPI ${parentKpi.name} using weighted average`)\n }\n\n // 기존 Parent KPI Value 조회 또는 생성 (프로젝트 재계산 시에는 이미 삭제되어 항상 새로 생성됨)\n let parentKpiValue = await kpiValueRepo.findOne({\n where: {\n kpi: { id: parentKpi.id },\n group: projectId,\n domain: { id: domain.id }\n }\n })\n\n if (parentKpiValue) {\n // 기존 값 업데이트 (최신 버전으로)\n parentKpiValue.value = calculatedValue\n parentKpiValue.score = calculatedScore\n parentKpiValue.version = parentKpi.version || 1\n parentKpiValue.updater = user\n } else {\n // 새 값 생성\n parentKpiValue = kpiValueRepo.create({\n kpi: parentKpi,\n group: projectId,\n version: parentKpi.version || 1,\n domain,\n valueDate: new Date().toISOString().slice(0, 10),\n value: calculatedValue,\n score: calculatedScore,\n updater: user\n })\n }\n\n await kpiValueRepo.save(parentKpiValue)\n console.log(`Updated parent KPI ${parentKpi.name}: value=${calculatedValue.toFixed(4)}, score=${calculatedScore.toFixed(4)}`)\n }\n\n /**\n * KPIs를 계층 레벨순으로 정렬합니다 (깊은 레벨부터)\n */\n private sortKpisByLevel(parentKpis: Kpi[], allKpis: Kpi[]): Kpi[] {\n const kpiLevels = new Map<string, number>()\n\n const calculateLevel = (kpi: Kpi): number => {\n if (kpiLevels.has(kpi.id)) {\n return kpiLevels.get(kpi.id)!\n }\n\n if (!kpi.parent) {\n kpiLevels.set(kpi.id, 0)\n return 0\n }\n\n const parentKpi = allKpis.find(k => k.id === kpi.parent?.id)\n if (!parentKpi) {\n kpiLevels.set(kpi.id, 1)\n return 1\n }\n\n const level = calculateLevel(parentKpi) + 1\n kpiLevels.set(kpi.id, level)\n return level\n }\n\n // 각 parent KPI의 레벨 계산\n parentKpis.forEach(kpi => calculateLevel(kpi))\n\n // 레벨 순으로 정렬 (깊은 레벨부터)\n return parentKpis.sort((a, b) => (kpiLevels.get(b.id) || 0) - (kpiLevels.get(a.id) || 0))\n }\n\n /**\n * 자식 KPI values의 weighted average를 계산합니다.\n */\n private calculateWeightedAverage(childValues: any[], childKpis: Kpi[]): { weightedValue: number; weightedScore: number } {\n let totalWeightedValue = 0\n let totalWeightedScore = 0\n let totalWeight = 0\n\n for (const value of childValues) {\n const childKpi = childKpis.find(kpi => kpi.id === value.kpi.id)\n const weight = childKpi?.weight || 1\n\n totalWeightedValue += value.score * weight /* value.score 가 value 역할을 value.value 가 아니라 value.score 가 맞다. */\n totalWeightedScore += value.score * weight\n totalWeight += weight\n }\n\n if (totalWeight === 0) {\n return { weightedValue: 0, weightedScore: 0 }\n }\n\n return {\n weightedValue: totalWeightedValue / totalWeight,\n weightedScore: totalWeightedScore / totalWeight\n }\n }\n}\n"]}
|
|
@@ -6,6 +6,18 @@ const type_graphql_1 = require("type-graphql");
|
|
|
6
6
|
const shell_1 = require("@things-factory/shell");
|
|
7
7
|
const kpi_1 = require("@things-factory/kpi");
|
|
8
8
|
const project_1 = require("@dssp/project/dist-server/service/project/project");
|
|
9
|
+
/** valueDate(최신) → version → updatedAt/createdAt 순으로 a 가 b 보다 더 최신이면 true */
|
|
10
|
+
function isMoreRecentKpiValue(a, b) {
|
|
11
|
+
var _a, _b, _c, _d, _e, _f;
|
|
12
|
+
const dateCmp = (a.valueDate || '').localeCompare(b.valueDate || '');
|
|
13
|
+
if (dateCmp !== 0)
|
|
14
|
+
return dateCmp > 0;
|
|
15
|
+
if (((_a = a.version) !== null && _a !== void 0 ? _a : 0) !== ((_b = b.version) !== null && _b !== void 0 ? _b : 0))
|
|
16
|
+
return ((_c = a.version) !== null && _c !== void 0 ? _c : 0) > ((_d = b.version) !== null && _d !== void 0 ? _d : 0);
|
|
17
|
+
const ta = new Date((_e = (a.updatedAt || a.createdAt)) !== null && _e !== void 0 ? _e : 0).getTime();
|
|
18
|
+
const tb = new Date((_f = (b.updatedAt || b.createdAt)) !== null && _f !== void 0 ? _f : 0).getTime();
|
|
19
|
+
return ta > tb;
|
|
20
|
+
}
|
|
9
21
|
let KpiValueQueryForProject = class KpiValueQueryForProject {
|
|
10
22
|
async kpiValues(params) {
|
|
11
23
|
const queryBuilder = (0, shell_1.getQueryBuilderFromListParams)({
|
|
@@ -17,11 +29,10 @@ let KpiValueQueryForProject = class KpiValueQueryForProject {
|
|
|
17
29
|
return { items, total };
|
|
18
30
|
}
|
|
19
31
|
async projectXKpiValues(projectId) {
|
|
20
|
-
var _a
|
|
32
|
+
var _a;
|
|
21
33
|
const repository = await (0, shell_1.getRepository)(kpi_1.KpiValue);
|
|
22
34
|
// history 포함 전체 fetch — 한 프로젝트의 X KPI 들이라 row 수가 적어 JS group-by 가
|
|
23
|
-
// SQL DISTINCT ON 보다 단순.
|
|
24
|
-
// 큰 것만 통과.
|
|
35
|
+
// SQL DISTINCT ON 보다 단순.
|
|
25
36
|
const allKpiValues = await repository
|
|
26
37
|
.createQueryBuilder('kpiValue')
|
|
27
38
|
.leftJoinAndSelect('kpiValue.kpi', 'kpi')
|
|
@@ -29,12 +40,15 @@ let KpiValueQueryForProject = class KpiValueQueryForProject {
|
|
|
29
40
|
.andWhere('kpi.name LIKE :namePrefix', { namePrefix: 'X%' })
|
|
30
41
|
.orderBy('kpi.name', 'ASC')
|
|
31
42
|
.getMany();
|
|
32
|
-
//
|
|
43
|
+
// (kpiId, kpiOrgScope) 별로 '가장 최근 valueDate' 1건만 선택.
|
|
44
|
+
// 여러 날짜·여러 데이터가 입력돼 있어도 최신 날짜의 값이 대표값이 되도록 한다.
|
|
45
|
+
// valueDate 가 같으면 version, 그래도 같으면 updatedAt/createdAt 으로 최신 우선
|
|
46
|
+
// (같은 valueDate·version 에도 복수 row 가 존재할 수 있어 단일 기준으로는 부족).
|
|
33
47
|
const latestByKey = new Map();
|
|
34
48
|
for (const kv of allKpiValues) {
|
|
35
|
-
const key = `${kv.kpiId || ((_a = kv.kpi) === null || _a === void 0 ? void 0 : _a.id)}:${kv.
|
|
49
|
+
const key = `${kv.kpiId || ((_a = kv.kpi) === null || _a === void 0 ? void 0 : _a.id)}:${kv.kpiOrgScopeId || ''}`;
|
|
36
50
|
const existing = latestByKey.get(key);
|
|
37
|
-
if (!existing || (
|
|
51
|
+
if (!existing || isMoreRecentKpiValue(kv, existing)) {
|
|
38
52
|
latestByKey.set(key, kv);
|
|
39
53
|
}
|
|
40
54
|
}
|
|
@@ -57,7 +71,7 @@ tslib_1.__decorate([
|
|
|
57
71
|
], KpiValueQueryForProject.prototype, "kpiValues", null);
|
|
58
72
|
tslib_1.__decorate([
|
|
59
73
|
(0, type_graphql_1.Directive)('@privilege(category: "kpi", privilege: "read", domainOwnerGranted: true, superUserGranted: true)'),
|
|
60
|
-
(0, type_graphql_1.Query)(returns => [kpi_1.KpiValue], { description: 'To fetch KpiValues by project group with X prefix kpi names (latest
|
|
74
|
+
(0, type_graphql_1.Query)(returns => [kpi_1.KpiValue], { description: 'To fetch KpiValues by project group with X prefix kpi names (latest valueDate only)' }),
|
|
61
75
|
tslib_1.__param(0, (0, type_graphql_1.Arg)('projectId', type => String)),
|
|
62
76
|
tslib_1.__metadata("design:type", Function),
|
|
63
77
|
tslib_1.__metadata("design:paramtypes", [String]),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kpi-value-query.js","sourceRoot":"","sources":["../../../server/service/kpi-value/kpi-value-query.ts"],"names":[],"mappings":";;;;AAAA,+CAAqG;AACrG,iDAAuG;AAEvG,6CAAiE;AACjE,+EAA2E;
|
|
1
|
+
{"version":3,"file":"kpi-value-query.js","sourceRoot":"","sources":["../../../server/service/kpi-value/kpi-value-query.ts"],"names":[],"mappings":"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","sourcesContent":["import { Resolver, Query, FieldResolver, Root, Args, Arg, Ctx, Directive, Float } from 'type-graphql'\nimport { Domain, getQueryBuilderFromListParams, getRepository, ListParam } from '@things-factory/shell'\nimport { User } from '@things-factory/auth-base'\nimport { Kpi, KpiValue, KpiValueList } from '@things-factory/kpi'\nimport { Project } from '@dssp/project/dist-server/service/project/project'\n\n/** valueDate(최신) → version → updatedAt/createdAt 순으로 a 가 b 보다 더 최신이면 true */\nfunction isMoreRecentKpiValue(a: KpiValue, b: KpiValue): boolean {\n const dateCmp = (a.valueDate || '').localeCompare(b.valueDate || '')\n if (dateCmp !== 0) return dateCmp > 0\n if ((a.version ?? 0) !== (b.version ?? 0)) return (a.version ?? 0) > (b.version ?? 0)\n const ta = new Date((a.updatedAt || a.createdAt) ?? 0).getTime()\n const tb = new Date((b.updatedAt || b.createdAt) ?? 0).getTime()\n return ta > tb\n}\n\n@Resolver(KpiValue)\nexport class KpiValueQueryForProject {\n @Directive('@privilege(category: \"kpi\", privilege: \"read\", domainOwnerGranted: true, superUserGranted: true)')\n @Query(returns => KpiValueList, { description: 'To fetch multiple KpiValues' })\n async kpiValues(@Args(type => ListParam) params: ListParam): Promise<KpiValueList> {\n const queryBuilder = getQueryBuilderFromListParams({\n params,\n repository: await getRepository(KpiValue),\n searchables: ['kpi', 'group', 'valueDate']\n })\n\n const [items, total] = await queryBuilder.getManyAndCount()\n\n return { items, total }\n }\n\n @Directive('@privilege(category: \"kpi\", privilege: \"read\", domainOwnerGranted: true, superUserGranted: true)')\n @Query(returns => [KpiValue], { description: 'To fetch KpiValues by project group with X prefix kpi names (latest valueDate only)' })\n async projectXKpiValues(@Arg('projectId', type => String) projectId: string): Promise<KpiValue[]> {\n const repository = await getRepository(KpiValue)\n\n // history 포함 전체 fetch — 한 프로젝트의 X KPI 들이라 row 수가 적어 JS group-by 가\n // SQL DISTINCT ON 보다 단순.\n const allKpiValues = await repository\n .createQueryBuilder('kpiValue')\n .leftJoinAndSelect('kpiValue.kpi', 'kpi')\n .where('kpiValue.group = :projectId', { projectId })\n .andWhere('kpi.name LIKE :namePrefix', { namePrefix: 'X%' })\n .orderBy('kpi.name', 'ASC')\n .getMany()\n\n // (kpiId, kpiOrgScope) 별로 '가장 최근 valueDate' 1건만 선택.\n // 여러 날짜·여러 데이터가 입력돼 있어도 최신 날짜의 값이 대표값이 되도록 한다.\n // valueDate 가 같으면 version, 그래도 같으면 updatedAt/createdAt 으로 최신 우선\n // (같은 valueDate·version 에도 복수 row 가 존재할 수 있어 단일 기준으로는 부족).\n const latestByKey = new Map<string, KpiValue>()\n for (const kv of allKpiValues) {\n const key = `${(kv as any).kpiId || kv.kpi?.id}:${(kv as any).kpiOrgScopeId || ''}`\n const existing = latestByKey.get(key)\n if (!existing || isMoreRecentKpiValue(kv, existing)) {\n latestByKey.set(key, kv)\n }\n }\n return Array.from(latestByKey.values()).sort((a, b) => (a.kpi?.name || '').localeCompare(b.kpi?.name || ''))\n }\n\n @FieldResolver(type => Project)\n async project(@Root() kpiValue: KpiValue): Promise<Project | null> {\n if (!kpiValue.group) return null\n return await getRepository(Project).findOneBy({ id: kpiValue.group })\n }\n}\n"]}
|