// 원본 조달청 XML 내보내기 전 검사(TfrmJDLConvert 0xe7d4bc)와 자리수자동수정(TfrmXMLDigetCheck btnOk 0xcc848c). // 오류 1: 단가산출에서 비목 지정 값(SCheck −5~−1) 또는 −20 행부터 소계(61)까지의 재료·노임 연결(5·6) 행에 행별 자리수. // 오류 8: 7개 단가 표 코드 중복 · 10: 코드에 영문 소문자 · 11: 기계경비 코드 길이 ≠ 17. // 자리수자동수정은 오류 1 행의 Diget·DigetIndex 만 0 으로 풀고 다시 계산한다(특정 자리로 고치지 않음). // 웹은 기존 XML 내보내기를 막지 않고 별도 검사 창으로 알린다. const EstXmlCheck = (() => { const num = (value) => Number(value) || 0; const tables = [ "LaborcDat", "StuffcDat", "EstiMateDat", "SilJukDat", "MachTitleDat", "CostTitleDat", "HeadTitleDat", ]; const explain = { 1: "비목값에 자리수지정", 8: "코드 중복", 10: "코드에 소문자사용", 11: "장비코드 길이가틀림(17자리)", }; function check(project) { const out = []; let head = null, flag = false; (project.tables.CostMainDat || []).forEach((row, index) => { if (num(row.Index) > 0) head = row; if (num(row.Index) === -20) flag = true; if (num(row.LinkIndex) === 61) flag = false; const digit = num(row.DigetIndex) || num(row.Diget), sc = num(row.SCheck); if (digit && ((sc >= -5 && sc <= -1) || (flag && [5, 6].includes(num(row.LinkIndex))))) out.push({ kind: 1, table: "CostMainDat", index, code: head?.Code ?? "", name: head?.Name ?? "", text: EstText.clean(row.LineData || ""), }); }); for (const table of tables) { const seen = new Map(); (project.tables[table] || []).forEach((row, index) => { if (!row.Code) return; const first = seen.get(row.Code); if (first) out.push({ kind: 8, table, index, code: row.Code, name: row.Name ?? "", text: `${num(first.Index)}.${first.Name ?? ""}(${first.Size ?? ""}) 와 코드 중복`, }); else seen.set(row.Code, row); if (/[a-z]/.test(row.Code)) out.push({ kind: 10, table, index, code: row.Code, name: row.Name ?? "", text: explain[10], }); if (table === "MachTitleDat" && String(row.Code).length !== 17) out.push({ kind: 11, table, index, code: row.Code, name: row.Name ?? "", text: explain[11], }); }); } return out; } function fix(project) { const rows = project.tables.CostMainDat || []; const targets = check(project).filter((e) => e.kind === 1); for (const e of targets) Object.assign(rows[e.index], { Diget: 0, DigetIndex: 0 }); return targets.length; } function show(state) { const list = check(state.project), { esc } = EstApp, counts = [1, 8, 10, 11].map( (k) => `${explain[k]} ${list.filter((e) => e.kind === k).length}건`, ); EstApp.showDialog( "조달청 XML 검사", `
${counts.join(" · ")}
| 구분 | 표 | 코드 | 품명 | 내용 |
|---|---|---|---|---|
| ${esc(explain[e.kind])} | ${esc(EstApp.titles?.[e.table] || e.table)} | ${esc(e.code)} | ${esc(e.name)} | ${esc(e.text)} |