Files
Aislo/tools/est-test/native-xml-check.js
eomsangdonandClaude Opus 5.5 100f05a9a3 feat(est-test): 조달청 XML 검사와 자리수 자동 수정
- 원본 변환 전 검사 1·8·10·11 규칙으로 목록 표시
- 비목값 자리수 지정만 풀고 다시 계산

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-11 20:27:01 +09:00

128 lines
4.5 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 원본 조달청 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 검사",
`<p>${counts.join(" · ")}</p><div style="max-height:360px;overflow:auto"><table class="sheet" style="font-size:12px"><thead><tr><th>구분</th><th>표</th><th>코드</th><th>품명</th><th>내용</th></tr></thead><tbody>${list
.slice(0, 300)
.map(
(e) =>
`<tr><td>${esc(explain[e.kind])}</td><td>${esc(EstApp.titles?.[e.table] || e.table)}</td><td>${esc(e.code)}</td><td>${esc(e.name)}</td><td style="text-align:left">${esc(e.text)}</td></tr>`,
)
.join(
"",
)}</tbody></table></div>${list.some((e) => e.kind === 1) ? '<button data-action="xml-diget-fix">자리수 자동 수정</button>' : ""}`,
);
}
function handle(name, state) {
if (name === "xml-check") show(state);
else if (name === "xml-diget-fix") {
if (
!confirm(
"자리수 수정후 재계산 시키므로공사금액이 변경될수 있습니다.자리수를 수정하시겠습니까?",
)
)
return true;
let count;
EstApp.change((project) => (count = fix(project)));
state.notice = `단가산출 ${count}줄의 자리수 지정을 풀고 다시 계산했습니다.`;
show(state);
} else return false;
return true;
}
return { check, fix, handle };
})();