- 원본 변환 전 검사 1·8·10·11 규칙으로 목록 표시 - 비목값 자리수 지정만 풀고 다시 계산 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
128 lines
4.5 KiB
JavaScript
128 lines
4.5 KiB
JavaScript
// 원본 조달청 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 };
|
||
})();
|