feat(est): print progress and adjustment costs

This commit is contained in:
2026-11-07 10:27:09 +09:00
parent e4b7322bb6
commit 5f9b5432ec
4 changed files with 76 additions and 4 deletions
+39
View File
@@ -44,6 +44,45 @@ def test_progress_and_escalation_print_use_selected_calculations():
assert result["empty"]["errors"]
def test_progress_cost_print_preserves_selected_round_costs():
result = run(
"math",
"""(()=>{
const p=EstNative.empty();p.options.SourceRefresh=false;
p.tables.EstMainDat=[{PkID:1,Code:'R',GN:10,GU:100},{LinkIndex:54}];
p.tables.Wonga=[{Gubun:'D',Name:'direct',BaseField:'GC'},{Gubun:'T',Name:'total',LinkIndex:55,VSusic:'D'}];
p.progress=[{id:'one',inputs:{'1':{Gum:2,Sa:1}},approved:true}];
const q=EstProgress.lock(EstNative.calculate(p),'one');
q.tables.EstMainDat[0].GU=200;q.progress.push({id:'two',inputs:{'1':{Gum:3}}});
return {one:EstForms.data('progress-costs',q,{roundId:'one'}),two:EstForms.data('progress-costs',q,{roundId:'two'})};
})()""",
)
assert result["one"]["rows"][-1]["ContractCost"] == 1000
assert result["one"]["rows"][-1]["GumCost"] == 200
assert result["one"]["rows"][-1]["SaCost"] == 100
assert result["two"]["rows"][-1]["JunCost"] == 100
assert result["two"]["rows"][-1]["GumCost"] == 600
assert result["two"]["rows"][-1]["TotalCost"] == 700
def test_escalation_cost_print_uses_computed_cost_breakdowns():
result = run(
"math",
"""(()=>{
const p=EstNative.empty();p.options.SourceRefresh=false;p.options.EscDesignTotal=1000;
p.tables.EstMainDat=[{PkID:1,Code:'R',GN:10,GU:80},{LinkIndex:54}];
p.tables.Wonga=[{Gubun:'D',Name:'direct',BaseField:'GC'},{Gubun:'T',Name:'total',LinkIndex:55,VSusic:'D'}];
const q=EstBusiness.baseline(EstNative.calculate(p));
Object.assign(q.tables.EstMainDat[0],{AGU:100,GU:120,EscActual:3});
return EstForms.data('escalation-costs',q);
})()""",
)
assert result["errors"] == []
assert result["rows"][-1]["ContractCost"] == 800
assert result["rows"][-1]["adjustedCost"] == 960
assert result["rows"][-1]["excludedCost"] == 240
def test_resource_report_separates_each_work_item_without_changing_aggregate():
result = run(
"math",
+1 -1
View File
@@ -6,7 +6,7 @@
인쇄 미리보기는 화면의 100행 페이지 제한 없이 검색 결과/현재 호표의 전체 행을 표시합니다. 출력 범위에서 현재 자료의 모든 호표·행도 선택할 수 있습니다. 원본 인쇄 옵션의 41개 항목 중 CAD를 제외한 40개 서식 이름을 선택하며, ESTX에서 가져온 해당 프로젝트의 인쇄 설정을 우선 사용합니다. 내역·원가·호표/총괄·증감·동원·수량·공정은 표 자료로 출력합니다. 표지·갑지·설명서·시방서·심사 문서는 서식별 본문을 직접 입력합니다. 용지·방향·여백·글자 크기·페이지당 행·시작 쪽·업체명을 저장하고 인쇄/PDF로 출력합니다. ESTX 수정 저장은 서식별 여백과 페이지당 행 수를 반영합니다. 다른 웹 인쇄 설정의 ESTX 쓰기와 원본 인쇄 도형·병합·글꼴 배치의 동등성은 지원하지 않습니다.
별도 인쇄 서식으로 기성 내역서, 물가변동 내역서, 연차 배분표를 선택할 수 있습니다. 기성은 선택한 회차를 출력하고 확정된 회차는 확정 당시 결과를 사용합니다.
별도 인쇄 서식으로 기성·물가변동의 내역서와 원가계산서, 연차 배분표를 선택할 수 있습니다. 기성은 선택한 회차를 출력하고 확정된 회차는 확정 당시 결과를 사용합니다.
저장은 이 폴더의 `data/`에 작업을 보관하고 `.estweb.json` 파일도 내려받습니다. 브라우저 임시 저장은 같은 탭에서 복원하는 용도입니다. JSON은 모든 웹 업무와 원본 압축 파일·바이너리를 보관하는 전체 저장 형식입니다. ESTX 수정 저장은 아래 지원 조건을 따릅니다.
+28 -2
View File
@@ -14,12 +14,19 @@ const EstForms = (() => {
errors: output.errors,
};
}
if (id === "progress-summary") {
if (["progress-summary", "progress-costs"].includes(id)) {
const round =
project.progress.find((item) => item.id === state.roundId) || project.progress.at(-1);
if (!round) return { columns: ["Name"], rows: [], errors: ["기성 회차가 없습니다."] };
const result =
round.locked && round.result ? round.result : EstProgress.calculate(project, round.id);
if (id === "progress-costs")
return {
columns: ["Gubun", "Name", "ContractCost", "JunCost", "GumCost", "SaCost", "TotalCost"],
rows: result.costs || [],
errors: result.errors,
detail: `${round.name || "기성"} (${round.locked ? "확정" : "작성 중"})`,
};
return {
columns: [
"Code",
@@ -41,8 +48,20 @@ const EstForms = (() => {
detail: `${round.name || "기성"} (${round.locked ? "확정" : "작성 중"})`,
};
}
if (id === "escalation-summary") {
if (["escalation-summary", "escalation-costs"].includes(id)) {
const result = EstEscalation.calculate(project);
if (id === "escalation-costs")
return {
columns: ["Gubun", "Name", "ContractCost", "adjustedCost", "excludedCost"],
rows: result.wonga.map((row, index) => ({
...row,
ContractCost: result.contractWonga[index]?.Cost,
adjustedCost: row.Cost,
excludedCost: result.excludedWonga[index]?.Cost,
})),
errors: result.errors,
detail: `도급액 ${result.contractTotal} · 조정액 ${result.adjustment} · 조정률 ${result.rate}%`,
};
return {
columns: [
"Code",
@@ -256,6 +275,13 @@ const EstForms = (() => {
ESC: "산출경비 증감",
directCost: "순공사비",
contractCost: "도급액",
ContractCost: "도급금액",
JunCost: "전회 금액",
GumCost: "금회 금액",
SaCost: "사정 금액",
TotalCost: "누계 금액",
adjustedCost: "조정 금액",
excludedCost: "제외 금액",
TargetCode: "연결 내역",
TU: "단가",
TC: "금액",
+8 -1
View File
@@ -85,7 +85,12 @@ const EstReport = (() => {
? EstNative.groups(state.project.tables[state.view] || []).get(state.group)?.rows[0]
?.Name
: "");
const totals = ["progress-summary", "escalation-summary"].includes(form?.Index)
const totals = [
"progress-summary",
"progress-costs",
"escalation-summary",
"escalation-costs",
].includes(form?.Index)
? null
: state.project.calculation;
const errors = [...(totals?.errors || []), ...(output?.errors || [])];
@@ -132,7 +137,9 @@ const EstReport = (() => {
}));
catalog.push(
{ Index: "progress-summary", Name: "기성 내역서", Name2: "기성 내역서" },
{ Index: "progress-costs", Name: "기성 원가계산서", Name2: "기성 원가계산서" },
{ Index: "escalation-summary", Name: "물가변동 내역서", Name2: "물가변동 내역서" },
{ Index: "escalation-costs", Name: "물가변동 원가계산서", Name2: "물가변동 원가계산서" },
{ Index: "annual-summary", Name: "연차 배분표", Name2: "연차 배분표" },
);
const table = EstApp.state.project.tables[EstApp.state.view];