// 원본 기성 원가계산서(TfrmWongaAccomH 0xd48408 / V 0xd46914) 편집 — 회차별 원가 서식 사본(round.wonga)에만 적용. // 한줄 삽입·추가(0xd49758: 새 행 Index 0·CalcIndex 0·Checked 끔, 앞 행 끝줄 표지 이어받기), 한줄 삭제(확인 뒤, 재계산 없음), // 내용 삭제(LinkIndex·Cost·Biul·Youl·VSusic·Diget 비움), 선택항목 절하(0xd094dc, 기성은 도급액 행도 허용), // 선택데이타 절하(popupTrunc: 직전 자리수를 그대로, CalcBase 행 제외), 공사비역산 자리수(목표 = 10^n 미만 절하 → 이윤 역산), // 초기화(사본 지움 = 도급 원가 서식), 되살리기(직전 조작 전), 산출근거 약어로 표시(A8: 수식칸 편집 잠금만). // 원본의 번호·참조 재작성(0xc97398·0xc971e8)은 하지 않는다 — 웹 수식은 Gubun·이름으로 찾으므로 새 행은 기호를 직접 적는다. const EstProgressWonga = (() => { const num = (value) => Number(value) || 0; function template(project, round) { return round.contract?.wonga || project.tables.Wonga || []; } function edit(project, round, mutate) { if (round.locked) throw Error("확정한 회차는 고칠 수 없습니다."); round.wongaUndo = round.wonga ? structuredClone(round.wonga) : null; round.wonga ||= structuredClone(template(project, round)); return mutate(round.wonga); } function blank(list, at) { const row = { Index: 0, Gubun: "", Name: "", Youl: "", VSusic: "", Cost: 0, CalcIndex: 0 }; const prev = list[at - 1], end = num(prev?.EndLineIndex); row.EndLineIndex = end === 1 ? 1 : end === 3 ? 3 : 0; if (end === 3) prev.EndLineIndex = 0; row.Checked = false; return row; } const ops = { insert(project, round, at) { edit(project, round, (list) => list.splice(at, 0, blank(list, at))); }, append(project, round) { edit(project, round, (list) => list.push(blank(list, list.length))); }, remove(project, round, at) { edit(project, round, (list) => { if (!list[at]) throw Error("삭제할 줄을 고르세요."); list.splice(at, 1); }); }, clear(project, round, at) { edit(project, round, (list) => { if (!list[at]) throw Error("내용을 지울 줄을 고르세요."); Object.assign(list[at], { LinkIndex: 0, Cost: 0, Biul: "", Youl: "", VSusic: "", Diget: 0, Checked: false, }); }); }, position(project, round, at, method, digits) { edit(project, round, (list) => EstWongaTools.position( { tables: { Wonga: list }, options: project.options }, [at], method, digits, true, ), ); }, trunc(project, round, at) { edit(project, round, (list) => { if (!list[at]) throw Error("절하할 줄을 고르세요."); if (!list[at].CalcBase) list[at].Diget = num(project.options.WongaLastDiget); }); }, total(project, round, digits) { if (round.locked) throw Error("확정한 회차는 고칠 수 없습니다."); if (!Number.isInteger(digits) || digits < 0 || digits > 9) throw Error("자리수는 0~9 사이로 입력하세요."); if (digits) round.wongaTotalDigits = digits; else delete round.wongaTotalDigits; }, init(project, round) { if (round.locked) throw Error("확정한 회차는 고칠 수 없습니다."); round.wongaUndo = round.wonga ? structuredClone(round.wonga) : null; delete round.wonga; delete round.wongaTotalDigits; }, undo(project, round) { if (round.locked) throw Error("확정한 회차는 고칠 수 없습니다."); if (!("wongaUndo" in round)) throw Error("되살릴 조작이 없습니다."); if (round.wongaUndo) round.wonga = round.wongaUndo; else delete round.wonga; delete round.wongaUndo; }, field(project, round, at, name, value) { edit(project, round, (list) => { if (!list[at] || !["Gubun", "Name", "Youl", "VSusic", "Cost"].includes(name)) throw Error("고칠 칸이 없습니다."); list[at][name] = name === "Cost" ? num(String(value).replaceAll(",", "")) : value; }); }, }; // 화면 function render(state, round, output) { const { esc, number } = EstApp, project = state.project, list = round.wonga || template(project, round), locked = round.locked, lockFormula = project.options.WongaSNameShow, pick = state.progressWongaRow; const b = (action, label) => ``; const tools = [ b("pw-insert", "한줄 삽입"), b("pw-append", "한줄 추가"), b("pw-delete", "한줄 삭제"), b("pw-clear", "내용 삭제"), b("pw-position", "선택항목 절하하기"), b("pw-trunc", "선택데이타 절하하기"), b("pw-total", "공사비역산 자리수 맞추기"), b("pw-init", "원가계산서 초기화"), b("pw-undo", "되살리기"), ``, round.wonga ? "회차 서식 사용 중" : "", round.wongaTotalDigits ? `역산 ${round.wongaTotalDigits}자리` : "", ].join(""); const input = (i, name, value, disabled) => ``; const body = (output.costs || []) .map((row, i) => { const tpl = list[i] || {}; return `
| 기호 | 원가 비목 | 요율 | 산출근거 | 자리 | 도급금액 | 전회 | 금회 | 사정 | 누계 |
|---|