fix(m01): 자동값 빈 줄에서 텍스트 수식이 멈추지 않음 — 빈 줄은 빈 글

- 빈 줄(후보 0 · 값 빈 품목 · 빈 덧줄)은 글 빈 값 · 금액 null 그대로 · 덧줄 식을 다시 셈하지 않음
- 덧줄 합 · 이름 값에 빈 줄을 넣지 않음
- 자동값으로 1,354 전부 텍스트 멈춤 62 → 0

검증: test_m01_text 23개 통과 · 자동값 1,354 멈춤 0 · GC000027 계 = 계산 계.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ACe3CR4gBWhWUN5p44fLe4
This commit is contained in:
2026-09-24 09:10:11 +09:00
co-authored by Claude Sonnet 5
parent d2380094cb
commit de8e1d51c2
2 changed files with 39 additions and 4 deletions
+11 -4
View File
@@ -353,7 +353,9 @@ def _shares(line: dict) -> list[tuple[str, Decimal]]:
def _line_text(item: dict, line: dict, env: dict, master, part: str | None) -> str:
"""「단가 * 수량식 = 금액」 — 비목이 나뉜 로직 줄은 그 비목 몫만."""
"""「단가 * 수량식 = 금액」 — 비목이 나뉜 로직 줄은 그 비목 몫만 · 빈 줄(금액 null)은 빈 글."""
if line["금액"] is None:
return ""
qty = render(mf.parse(item["수량"]), env, master)
money = line["비목"][part] if part else line["금액"]
price = line["단가"] if part is None or line["수량"] == 0 else money / line["수량"]
@@ -370,6 +372,8 @@ def _line_names(item: dict, line: dict, env: dict, master, part: str | None, nam
def _extra_text(extra: dict, line: dict, env: dict, master) -> str:
if line["금액"] is None: # 빈 덧줄 — 식을 다시 셈하지 않음
return ""
return f"{render(mf.parse(extra['']), env, master)} = {fmt_money(line['금액'])}"
@@ -520,7 +524,9 @@ def _extras(
row: dict, shown: list, made: dict, env: dict, master, name_of: dict, alias_by_name: dict
) -> None:
"""덧줄 — 앞선 줄까지의 비목 합을 넣고 한 줄씩(식 안의 비목 이름은 그 수로 바뀜)."""
sums = {name: sum((one["금액"] for one in made[name]), Decimal(0)) for name in mf.COST_ITEMS}
sums = {
name: sum((one["금액"] or 0 for one in made[name]), Decimal(0)) for name in mf.COST_ITEMS
}
for extra, line in zip(row.get("덧줄") or [], shown):
env.update(sums)
one = {
@@ -531,8 +537,9 @@ def _extras(
"조각": _formula_pieces(extra[""], env, master, name_of, alias_by_name),
}
made[extra["비목"]].append(one)
sums[extra["비목"]] += line["금액"]
env[extra["이름"]] = line["금액"]
if line["금액"] is not None: # 빈 덧줄은 합·이름 값에 안 넣음
sums[extra["비목"]] += line["금액"]
env[extra["이름"]] = line["금액"]
def _cut_note(row: dict, on: str = "") -> str:
+28
View File
@@ -303,3 +303,31 @@ def test_글_안의_돈은_정수_계산_값은_소수_그대로(client: TestCli
first = _all_lines(got)[0]
assert first[""] == "275,790 * 0.22 * 1.31 = 79,483" # 수량·비율은 소수 그대로
assert Decimal(str(first["금액"])) == Decimal("79482.678") # 값은 그대로
def test_자동값으로_모든_로직을_돌려도_멈추지_않는다() -> None:
"""빈 줄(후보 0 · 값 빈 품목) — 그 줄만 빈 글 · 로직은 계속(PLAN 3-2)."""
files = store.cm.load(folder=REAL)
master = store.cm.master(REAL)
stops = []
for rows in master.index.values():
for key in rows:
if mt.mf.mk.GROUP_OF.get(key[:2]) != "로직":
continue
given = {n: store._dec(v) for n, v in store.auto(key)[""].items()}
try:
mt.lines(files, key, given)
except mt._CALC_ERRORS as e:
stops.append((key, str(e)))
assert not stops, stops[:3]
def test_빈_줄은_빈_글이고_소계는_빈_줄_빼고_더한다(client: TestClient) -> None:
key = "GC000027"
given = {n: str(v) for n, v in store.auto(key)[""].items()}
got = client.post("/api/m01/text", json={"key": key, "inputs": given}).json()
calc = client.post("/api/m01/calc", json={"key": key, "inputs": given}).json()
assert got["ok"] is True
blank = [one for one in _all_lines(got) if one["금액"] is None]
assert blank and all(one[""] == "" and one["까닭"] for one in blank)
assert Decimal(str(got[""])) == Decimal(str(calc["sums"][""]))