fix(est): match prior unnamed cost codes
This commit is contained in:
@@ -121,3 +121,22 @@ def test_progress_preserves_zero_wonga_total_and_falls_back_only_when_absent():
|
||||
assert result["zero"]["rows"][0]["GumTC"] == 200
|
||||
assert result["zero"]["total"] == 0
|
||||
assert result["absent"]["total"] == 200
|
||||
|
||||
|
||||
def test_progress_preserves_prior_costs_for_multiple_blank_codes():
|
||||
result = run(
|
||||
"math",
|
||||
"""(()=>{
|
||||
const p=EstNative.empty();p.options.SourceRefresh=false;
|
||||
p.tables.EstMainDat=[{PkID:1,Code:'R',GN:10,GU:100,NU:50},{LinkIndex:54}];
|
||||
p.tables.Wonga=[{Gubun:'',Name:'material',BaseField:'GC'},
|
||||
{Gubun:'',Name:'labor',BaseField:'NC'}];
|
||||
p.progress=[{id:'one',inputs:{'1':{Gum:2}}}];
|
||||
const q=EstProgress.lock(EstNative.calculate(p),'one');
|
||||
q.progress.push({id:'two',inputs:{'1':{Gum:3}}});
|
||||
return EstProgress.calculate(q,'two');
|
||||
})()""",
|
||||
)
|
||||
assert result["errors"] == []
|
||||
assert [row["JunCost"] for row in result["costs"]] == [200, 100]
|
||||
assert [row["TotalCost"] for row in result["costs"]] == [500, 250]
|
||||
|
||||
@@ -61,7 +61,7 @@ Ctrl+S는 입력 중인 셀도 확정한 뒤 저장합니다. 연속 저장 요
|
||||
|
||||
2026-11-06 지정 범위인 설계변경·기성·물가변동·연차의 웹앱 구현을 완료했습니다. 설계변경은 당초 보존·재계산 0/1/2와 신규·삭제·변경 비교를 제공합니다. 삭제된 당초/기성 행 번호를 새 행에 재사용하지 않습니다.
|
||||
|
||||
기성은 수량·금액·비율·비목별 입력, 사정 승인, 전회·금회·누계 원가를 계산합니다. 확정 회차는 당시 계약 자료를 보존하고 서버 저장 시 결과를 재검산합니다. 전회 수정은 이후 회차의 확정도 해제하며, 전회 미확정 상태에서 다음 회차를 확정할 수 없습니다.
|
||||
기성은 수량·금액·비율·비목별 입력, 사정 승인, 전회·금회·누계 원가를 계산합니다. 원가 기호가 없는 항목은 이름과 같은 이름의 순서로 전회 금액을 대응합니다. 확정 회차는 당시 계약 자료를 보존하고 서버 저장 시 결과를 재검산합니다. 전회 수정은 이후 회차의 확정도 해제하며, 전회 미확정 상태에서 다음 회차를 확정할 수 없습니다.
|
||||
|
||||
물가변동은 같은 행 구조의 계약·입찰 자료(JSON/ESTX)를 불러와 조사·계약·변동 단가를 나눕니다. 원본 레코드 순서 방식에 따라 행 순서·코드·레벨이 다른 자료는 거부합니다. 등락 분기, 조사금액 기준 조정률, 자동 최대수량/수동 적용제외, 간접비 포함 적용대가와 기성 누계 불러오기를 제공합니다. 기성과 물가변동은 원가계산서의 명시적인 0원 도급액을 보존합니다. 연차는 수식 참조 오류를 차단하며, 미리보기 뒤 선택한 차수만 독립 사본으로 엽니다.
|
||||
|
||||
|
||||
@@ -224,11 +224,20 @@ const EstProgress = (() => {
|
||||
row[prefix + field] = children.reduce((n, child) => n + num(child[prefix + field]), 0);
|
||||
}
|
||||
const acceptedCost = round.approved ? sa : gum;
|
||||
const priorCosts = new Map(
|
||||
(previous?.costs || previous?.wonga || []).map((row) => [row.Gubun ?? row.Name, row]),
|
||||
);
|
||||
const costKeys = (items) => {
|
||||
const occurrences = new Map();
|
||||
return items.map((row) => {
|
||||
const identity = JSON.stringify(row.Gubun ? ["code", row.Gubun] : ["name", row.Name || ""]);
|
||||
const occurrence = occurrences.get(identity) || 0;
|
||||
occurrences.set(identity, occurrence + 1);
|
||||
return JSON.stringify([identity, occurrence]);
|
||||
});
|
||||
};
|
||||
const oldCosts = previous?.costs || previous?.wonga || [];
|
||||
const priorCosts = new Map(costKeys(oldCosts).map((key, index) => [key, oldCosts[index]]));
|
||||
const currentKeys = costKeys(acceptedCost.rows);
|
||||
const costs = acceptedCost.rows.map((row, index) => {
|
||||
const previous = priorCosts.get(row.Gubun ?? row.Name);
|
||||
const previous = priorCosts.get(currentKeys[index]);
|
||||
const jun = num(previous?.TotalCost ?? previous?.Cost);
|
||||
return {
|
||||
...row,
|
||||
|
||||
Reference in New Issue
Block a user