feat(723-4): 723-1 뒤 B09 일위대가 수량 연결 마무리 — 알약 값 쓴 SC 만 덮개 나눔 · SK 속 SC · 공사 불러오기 수량 · 비고 경고
- Labor_Source = 덮개 열쇠 `C:참조|S:사본` 은 알약 값 쓴 SC 블록만(빈 수량 · 옛 손 = `C:참조` 그대로 = 703-1 지난 공사 가져옴 꼴) · SK 속 SC 안 줄 수량 없음 = 엔진엔 0 값묶음(`_Loose`) · 그 줄 = 사전조합 블록(이 공사 입력) — SK 통째 빈칸 안 됨 - Bill_Hopyo(707-7 공사 통째 불러오기) = 이 공사 엑셀 수량을 굳힌 손으로 남김(723-1 `with_pills` 수량 걷기는 M02 저장용) - Daega_Personal 원천 = 블록 origin 참조(덮개 열쇠 꼬리 무관) · 내 자료집 저장 알림 글 = 줄 수량 저장 안 함 - 비고(펼침 · 일위대가표) = 수량 없는 SC 안 줄은 「산근 n호표 · 수량 없음 — 이 공사에서 입력」(`noteOf`) - 낡은 시험 고침(사유 = 723-1 SC 안 줄 수량 저장 안 함 · 이 공사 입력 · 알약으로 이음): test_204_2(서고 SC 수량 없음 · ask) · test_703(자료집 저장 손 걷힘) · test_719_1(서고 사본 = 알약 값으로 같은 값 · 없으면 수량 없음) · test_719_2(SK 속 SC = 빈 줄 → 이 공사 입력 1 = M02 알약 1 금액) · test_702_3(서고 SC 빈 줄 3 → 입력 뒤 금액) - test_723_4 = 구조물 사본 면적 알약 굳힘 · 설계 연동 · 알약 안 이음 = 빈 줄 시험 더함 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -141,7 +141,9 @@ def _copies(docs: dict[int, dict[str, Any]], tag: str, no: int) -> dict[str, dic
|
||||
rid = refs.ref_id(_ref(tag, at))
|
||||
if rid in out or at not in docs:
|
||||
continue
|
||||
out[rid] = refs.with_pills(docs[at])
|
||||
# 이 공사 엑셀 수량 = 굳힌 손(723-4 · `with_pills` 의 723-1 수량 걷기는 M02 저장용)
|
||||
doc = docs[at]
|
||||
out[rid] = {**refs.with_pills(doc), **{k: doc.get(k) or [] for k in ("담은로직", "자재")}}
|
||||
todo += [
|
||||
int(one["참조"]["키"][3:])
|
||||
for one in docs[at].get("담은로직") or []
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
"""B09 「내 자료집에 저장」(PLAN 703-2) — 펼친 일위대가(대가 블록) → 개인 층 사전조합(SC).
|
||||
|
||||
담는 것 = 담은로직(넣을 값 · 고른 자재 얹음) · 자재 · 줄 수량(= 수량산출 수기 `손`) —
|
||||
맨 위 줄 수량 덮개 = 손(원래 손 × 덮개 ÷ 블록 줄 수량 · 대가 줄 ÷ 배를 되돌림)
|
||||
맨 위 줄 수량 덮개 = 손(원래 손 × 덮개 ÷ 블록 줄 수량 · 대가 줄 ÷ 배를 되돌림) ·
|
||||
SC 쓸 때 손 걷힘(723-1 `refs.no_qty` · 쓰는 곳 알약 · 이 공사 입력으로 이음)
|
||||
안 담는 것 = 품 덮개(부른 블록 안 줄 · 품셈 블록 줄 — 로직 통째 배수로 바꾸면 다른 줄까지 바뀜) ·
|
||||
단가 덮개(사전조합 꼴에 단가 칸 없음) → 수만 알림(품은 PLAN 705 고정 줄이 생기면 담김)
|
||||
원천 = 블록 cover — 조합 `S:`/`L:` = 사본 폴더(일위대가 · 넣을 값 · 고른 자재 · 셈 수량) ·
|
||||
@@ -107,7 +108,8 @@ def source(root: Path, block: dict[str, Any], base: str) -> tuple[list[dict], li
|
||||
doc = ((read_json(folder / LABOR_FILE) or {}).get("참조사본") or {}).get(refs.ref_id(ref))
|
||||
if isinstance(doc, dict):
|
||||
return _precombo(doc)
|
||||
if head == "C" and (doc := _frozen(root, rest)) is not None:
|
||||
rid = (block.get("origin") or {}).get("참조") or rest # 덮개 `C:참조|쓰는 곳`(723-4) = 참조만
|
||||
if head == "C" and (doc := _frozen(root, rid)) is not None:
|
||||
return _precombo(doc)
|
||||
raise LookupError(f"일위대가 원천을 못 찾음 「{base}」")
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
사전조합 참조 SC = 겹 대가(굳힌 `참조사본`) · 줄 = 그 안 로직 · 참조 줄 · 자재 줄(175-2) ·
|
||||
안 줄 수량(723-4) = 굳힌 옛 손 → 쓰는 구조물 사본 면적 알약 값(723-1
|
||||
「참조 id#차례」 · 「참조 id#자재|코드」) → 없음 = 빈 줄(`ask` · 이 공사에서 입력 =
|
||||
702 덮개 qty) ·
|
||||
알약 · 없음 쓴 블록 덮개 = `C:참조|S:사본` · `C:참조|L:서고`(옛 손뿐 = `C:참조`)
|
||||
702 덮개 qty) · 알약 값 쓴 블록 덮개 = `C:참조|S:사본`(사본마다 값 다름) ·
|
||||
그 밖 = `C:참조`(공사 안 한 덮개)
|
||||
품셈 일위대가화(승격) 줄 · 옛 참조 SP = 로직마다 따로(노무 · 재료 · 중기 · 산근 · % 줄)
|
||||
— 조합이 수량만큼 부름 · 기계 = 기계경비 로직 줄 · 다른 돈 로직 줄 = 하위 산근
|
||||
산근 단가산출 줄(일위대가화 아닌 로직 줄) = 산근 호표 참조(키 = 145-1 `sangeun_key`)
|
||||
@@ -173,11 +173,11 @@ class Builder:
|
||||
단가산출 속 일위대가 · SK 줄(참조) = 그 대가 블록을 부르는 줄(펼침 · B09 차례 그대로) ·
|
||||
고정 줄 = `fixed` · 단가 고친 줄(덮개 · 더한줄 단가 · 값묶음) = `fixed`(줄 단가 = M02 셈) ·
|
||||
cover = `P:` + SK 이름표(SK 를 고쳐 [업데이트] 해도 B09 덮개 그대로) ·
|
||||
속 일위대가 안 줄 수량 없음(723-4) = 엔진엔 0 값묶음 · 그 줄 = 사전조합 블록(이 공사 입력) ·
|
||||
줄 `sk` · `poom`(M02 에서 고친 줄의 품셈 값 = 원본 덮개 `원값`)."""
|
||||
from M02_MasterTemplete import M02_Item_Sangeun as item_sk
|
||||
from M02_MasterTemplete import M02_Sangeun_Calc as calc
|
||||
from M02_MasterTemplete import M02_Sangeun_Doc as sd
|
||||
from M02_MasterTemplete.M02_Labor_Expand import Expand
|
||||
|
||||
rid = refs.ref_id(ref)
|
||||
key = str((doc.get("바탕") or {}).get("로직") or "")
|
||||
@@ -190,7 +190,7 @@ class Builder:
|
||||
try:
|
||||
got = calc.resolve(doc, whole, read, (rid,))
|
||||
row = {**got["줄"], "키": key, "호표": [dict(x) for x in got["줄"]["호표"]]}
|
||||
if calc._bundles(row, whole, Expand(whole, read), (rid,)):
|
||||
if calc._bundles(row, whole, _Loose(whole, read), (rid,)):
|
||||
return None
|
||||
except (sd.DocError, mf.FormulaError, ArithmeticError, KeyError, TypeError, ValueError):
|
||||
return None
|
||||
@@ -334,15 +334,15 @@ class Builder:
|
||||
use: tuple[dict, str] = ({}, ""),
|
||||
) -> str:
|
||||
"""사전조합(SC) = 겹 대가 — 로직 줄 = 품셈 호표 · 자재 줄(175-2) · 줄 수량(723-4) =
|
||||
옛 손 → use 알약 값 → 없음(`ask`) · use = (쓰는 구조물 사본 면적 알약 값, 덮개 자리)."""
|
||||
굳힌 손 → use 알약 값 → 없음(`ask`) · use = (쓰는 구조물 사본 면적 알약 값, 덮개 자리)."""
|
||||
from M01_MasterData import M01_MasterData_Store_Combo as combo_store
|
||||
|
||||
rid, (given, where) = refs.ref_id(ref), use
|
||||
loose: list[bool] = [] # 줄마다 손 아닌 수량(알약 · 없음)
|
||||
pilled: list[bool] = [] # 줄마다 알약 값을 썼나
|
||||
|
||||
def qty_of(key: str, hand: Any) -> float | None: # 짝 = `M02_Labor_Expand._qty` 차례
|
||||
got = _f(hand)
|
||||
loose.append(got is None)
|
||||
pilled.append(got is None and key in given)
|
||||
return _f(given.get(key)) if got is None else got
|
||||
|
||||
inner = [one for one in doc.get("담은로직") or [] if isinstance(one, dict)]
|
||||
@@ -379,7 +379,7 @@ class Builder:
|
||||
"origin": {"참조": rid},
|
||||
"lines": lines,
|
||||
},
|
||||
f"C:{rid}|{where}" if where and any(loose) else None,
|
||||
f"C:{rid}|{where}" if where and any(pilled) else None,
|
||||
)
|
||||
|
||||
# ── 조합(구조물 사본) ───────────────────────────────────────────────
|
||||
@@ -444,7 +444,22 @@ class Builder:
|
||||
whole = item_prices.load_prices(read_json(folder / PRICE_FILE) or {})
|
||||
if manifest["종류"] == "sangeun": # 내 자료집 단가산출(719-2)
|
||||
return self.sangeun(whole, ref, doc, copies, 1)
|
||||
return self.precombo(whole, ref, doc, copies, 1, ({}, f"L:{folder.name}"))
|
||||
return self.precombo(whole, ref, doc, copies, 1)
|
||||
|
||||
|
||||
def _Loose(whole: Any, read: Any) -> Any:
|
||||
"""B09 SK 속 펼침(723-4) — 사전조합 안 줄 수량 없음 = 0 값묶음(엔진 차례 · 수량만 씀 ·
|
||||
그 줄 값 = B09 사전조합 블록 · 이 공사에서 입력) · 그 밖 까닭은 그대로."""
|
||||
from M02_MasterTemplete.M02_Labor_Expand import NO_QTY, Expand
|
||||
|
||||
class Loose(Expand):
|
||||
def __call__(self, ref: dict, trail: tuple[str, ...] = ()) -> dict[str, Any]:
|
||||
got = super().__call__(ref, trail)
|
||||
if got.get("기준") is None and str(got.get("까닭") or "").endswith(NO_QTY):
|
||||
return {**got, "기준": dict.fromkeys(labor_doc.COSTS, Decimal(0))}
|
||||
return got
|
||||
|
||||
return Loose(whole, read)
|
||||
|
||||
|
||||
def fixed_line(fx: dict, qty: Any) -> dict[str, Any]:
|
||||
|
||||
@@ -158,6 +158,12 @@ export const blockLevel = (key: string, top: (index: number) => boolean): TabTab
|
||||
of: (i) => (top(i) ? 1 : 2),
|
||||
});
|
||||
|
||||
/** 대가 줄 비고 — 호표 번호 · 까닭 · 수량 없는 SC 안 줄(723-4 `ask`)은 번호 뒤에도 경고 */
|
||||
export const noteOf = (ln: Row): string =>
|
||||
ln.ask && ln.qty == null
|
||||
? [ln.ref_no, ln.why].filter(Boolean).join(" · ")
|
||||
: ln.ref_no || ln.why || "";
|
||||
|
||||
/* ── 열 꼴 ────────────────────────────────────────────────────────────── */
|
||||
|
||||
export const text = (key: string, label: string, width?: number, group?: string[]): DataColumn => ({
|
||||
|
||||
@@ -22,7 +22,7 @@ import { attachHoverInfo } from "@ui/ui_template_hover_info";
|
||||
import { cellColumn, createDataTable, type DataRow } from "@ui/ui_template_data_table";
|
||||
import type { MapContextMenuItem } from "@ui/ui_template_context_menu";
|
||||
import type { Row } from "./B09_Estimation_Calc_Base";
|
||||
import { money, parseNumber, qty, text, type TabContext } from "./B09_Estimation_UI_Tabs";
|
||||
import { money, noteOf, parseNumber, qty, text, type TabContext } from "./B09_Estimation_UI_Tabs";
|
||||
import { attachRowMenu } from "./B09_Estimation_UI_Tabs_Bill_Edit";
|
||||
import { foldMenu } from "./B09_Estimation_UI_Tabs_Bill_Fold_Menu";
|
||||
import { API_BASE_URL } from "@config/config_frontend";
|
||||
@@ -139,7 +139,7 @@ function foldCard(
|
||||
expense_price: line.prices?.expense,
|
||||
amount: line.amount,
|
||||
base: baseText(line),
|
||||
note: line.ref_no || line.why || "",
|
||||
note: noteOf(line),
|
||||
}));
|
||||
const edited = lines.filter((at) => (at.line.covered || []).length);
|
||||
const columns = [
|
||||
|
||||
@@ -95,7 +95,7 @@ async function savePersonal(ctx: TabContext, block: Row): Promise<void> {
|
||||
title: "내 자료집에 저장",
|
||||
message: sk
|
||||
? "내 자료집 단가산출로 — 옵션 값 · 고른 자재 · 품 · 단가 고친 칸까지"
|
||||
: "내 자료집 일위대가로 — 옵션 값 · 고른 자재 · 줄 수량 고친 칸까지",
|
||||
: "내 자료집 일위대가로 — 옵션 값 · 고른 자재까지(줄 수량은 저장 안 함 · 쓰는 곳에서 이음)",
|
||||
value: block.name || "",
|
||||
okLabel: "저장",
|
||||
});
|
||||
|
||||
@@ -15,6 +15,7 @@ import type { Row } from "./B09_Estimation_Calc_Base";
|
||||
import {
|
||||
blockLevel,
|
||||
money,
|
||||
noteOf,
|
||||
text,
|
||||
type Link,
|
||||
type TabBuild,
|
||||
@@ -99,7 +100,7 @@ export const buildDaegaBlocks: TabBuild = ({ sheets }): TabTable | string => {
|
||||
unit: ln.unit || "",
|
||||
prices: { sum: ln.price, ...ln.prices },
|
||||
amounts: { sum: ln.amount, ...ln.amounts },
|
||||
note: ln.ref_no || ln.why || "",
|
||||
note: noteOf(ln),
|
||||
tag: ln.kind === "fixed" ? HOPYO_TAG.fix : HOPYO_TAG.pum, // 705-1 고정 줄
|
||||
})),
|
||||
})),
|
||||
|
||||
Reference in New Issue
Block a user