fix(B09 통합 점검): 단가연결 낱말 별칭 · 줄 0 개 일위대가 = 빈 줄 · 단위 다름 알림 · 잊은 짝 짝 표 제안 제외 (통합 점검 흠 ① ③ ④ + 잊기)
- 기준 목록 별칭에 「터파기」→「파기」 낱말(측구파기 → 측구터파기) · 목록 모양 SHAPE 올림 - 줄 0 개 일위대가 = 빈 줄 하나 · 빈 줄 있는 대가를 이은 내역 줄 = 단가 모름(금액 0 아님) · py · ts 짝 + 거울 시험 - 단가연결 때 줄 단위 ≠ 일위대가 단위면 「단위 다름」 알림(연결은 됨) - 잊은 짝은 짝 표 제안에서도 안 나옴(다시 이으면 풀림) - 낡은 시험 여섯: 707-4 잇기 메뉴 묶음(UI_Link) 빠진 소스 목록 보충 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -148,7 +148,7 @@ def suggest(rows: list[dict[str, Any]], memory: dict[str, dict[str, Any]]) -> li
|
|||||||
hit = _resolve(got, free) if got else None
|
hit = _resolve(got, free) if got else None
|
||||||
if hit:
|
if hit:
|
||||||
keys, tag = [hit], RECALL
|
keys, tag = [hit], RECALL
|
||||||
elif row["kind"] == "item":
|
elif row["kind"] == "item" and not (memory.get(key_of(row)) or {}).get(FORGOT):
|
||||||
keys, tag = [EARTH_KEY[n] for n in table(row["name"], row["spec"])], TABLE
|
keys, tag = [EARTH_KEY[n] for n in table(row["name"], row["spec"])], TABLE
|
||||||
keys = [k for k in keys if k in free]
|
keys = [k for k in keys if k in free]
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -171,7 +171,13 @@ def ref_price(
|
|||||||
if row is None:
|
if row is None:
|
||||||
return None
|
return None
|
||||||
no = f"대가{row['no']}" if tab == "dg" else f"산근 {row['no']}호표"
|
no = f"대가{row['no']}" if tab == "dg" else f"산근 {row['no']}호표"
|
||||||
return {"no": no, "tab": tab, "key": key, **{p: row.get(p) for p in (*PARTS, "sum")}}
|
blank = tab == "dg" and row.get("blank") # 빈 줄 있는 대가(줄 0 개 포함) = 단가 모름
|
||||||
|
return {
|
||||||
|
"no": no,
|
||||||
|
"tab": tab,
|
||||||
|
"key": key,
|
||||||
|
**{p: None if blank else row.get(p) for p in (*PARTS, "sum")},
|
||||||
|
}
|
||||||
return hopyo.get(key) if key else None
|
return hopyo.get(key) if key else None
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -132,7 +132,8 @@ export function refPrice(ref: Row | null, books: Row, hopyo: Row, rowKey = ""):
|
|||||||
if (!row) return null;
|
if (!row) return null;
|
||||||
const no = tab === "dg" ? `대가${row.no}` : `산근 ${row.no}호표`;
|
const no = tab === "dg" ? `대가${row.no}` : `산근 ${row.no}호표`;
|
||||||
const out: Row = { no, tab, key };
|
const out: Row = { no, tab, key };
|
||||||
for (const p of [...PARTS, "sum"]) out[p] = row[p] ?? null;
|
const blank = tab === "dg" && row.blank; // 빈 줄 있는 대가(줄 0 개 포함) = 단가 모름
|
||||||
|
for (const p of [...PARTS, "sum"]) out[p] = blank ? null : (row[p] ?? null);
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
return key ? (hopyo[key] ?? null) : null;
|
return key ? (hopyo[key] ?? null) : null;
|
||||||
|
|||||||
@@ -17,7 +17,8 @@
|
|||||||
% 줄 = ROUNDDOWN(밑수 × % / 100, 1) · 관급 · 별도계상 자재 = 대가 안 0원 ·
|
% 줄 = ROUNDDOWN(밑수 × % / 100, 1) · 관급 · 별도계상 자재 = 대가 안 0원 ·
|
||||||
블록 비목 합 = ROUNDDOWN(Σ, 0) · 합계 = 세 비목 합.
|
블록 비목 합 = ROUNDDOWN(Σ, 0) · 합계 = 세 비목 합.
|
||||||
빈칸 = 단가 · 수량을 낸 원천이 없으면 None · 「연결 없음」 목록(gaps).
|
빈칸 = 단가 · 수량을 낸 원천이 없으면 None · 「연결 없음」 목록(gaps).
|
||||||
빈 줄(166-6) = 블록 합 = 아는 줄 합 + `blank` n · `blank_names` — 내역 단가 · 부른 대가로는 안 넘김.
|
빈 줄(166-6) = 블록 합 = 아는 줄 합 + `blank` n · `blank_names` — 내역 단가 · 부른 대가로는 안 넘김 ·
|
||||||
|
줄 0 개 블록 = 빈 줄 하나(`NO_LINES`).
|
||||||
고친 칸 덮개(702-2) = 사용자 값 `daega_cover` {블록 cover: {줄 cid: {qty · 노 · 재 · 경 단가}}} —
|
고친 칸 덮개(702-2) = 사용자 값 `daega_cover` {블록 cover: {줄 cid: {qty · 노 · 재 · 경 단가}}} —
|
||||||
있는 칸만 셈 값 대신 · 줄 `base`(품셈 값 = 셈 수량 · 단가) · `covered`(고친 칸) ·
|
있는 칸만 셈 값 대신 · 줄 `base`(품셈 값 = 셈 수량 · 단가) · `covered`(고친 칸) ·
|
||||||
짝 잃은 덮개(그 블록 · 줄 없음) = `daega_orphans` [{cover, cid}] — 지우지 않고 알림만.
|
짝 잃은 덮개(그 블록 · 줄 없음) = `daega_orphans` [{cover, cid}] — 지우지 않고 알림만.
|
||||||
@@ -36,6 +37,7 @@ from B09_Estimation.B09_Estimation_Calc_Base import SUPPLY, gap, num, rounddown,
|
|||||||
PARTS = ("labor", "material", "expense")
|
PARTS = ("labor", "material", "expense")
|
||||||
COVER_KEYS = ("qty", *PARTS)
|
COVER_KEYS = ("qty", *PARTS)
|
||||||
TAB = "dg"
|
TAB = "dg"
|
||||||
|
NO_LINES = "구성 줄 없음" # 줄 0 개 일위대가의 빈 줄 이름
|
||||||
COPY = "@copy"
|
COPY = "@copy"
|
||||||
ADD = "@add"
|
ADD = "@add"
|
||||||
WHY = {
|
WHY = {
|
||||||
@@ -158,6 +160,8 @@ def _block(
|
|||||||
known = [ln for ln in lines if ln["amount"] is not None]
|
known = [ln for ln in lines if ln["amount"] is not None]
|
||||||
parts = {part: rounddown(sum(ln["amounts"][part] for ln in known), 0) for part in PARTS}
|
parts = {part: rounddown(sum(ln["amounts"][part] for ln in known), 0) for part in PARTS}
|
||||||
blank_names = [ln.get("name") or "" for ln in lines if ln["amount"] is None]
|
blank_names = [ln.get("name") or "" for ln in lines if ln["amount"] is None]
|
||||||
|
if not lines: # 줄 0 개 일위대가 = 금액 0 이 아니라 모름(빈 줄)
|
||||||
|
blank_names = [NO_LINES]
|
||||||
return {
|
return {
|
||||||
**{k: block.get(k) for k in ("id", "kind", "name", "spec", "unit", "cite", "cover")},
|
**{k: block.get(k) for k in ("id", "kind", "name", "spec", "unit", "cite", "cover")},
|
||||||
**({"spec_raw": block["spec_raw"]} if block.get("spec_raw") else {}), # 157-4 풍선
|
**({"spec_raw": block["spec_raw"]} if block.get("spec_raw") else {}), # 157-4 풍선
|
||||||
|
|||||||
@@ -14,7 +14,8 @@
|
|||||||
* 줄 금액 ROUNDDOWN(단가 × 수량, 1) · 블록 비목 합 ROUNDDOWN(Σ, 0) · 합계 = 세 비목 합
|
* 줄 금액 ROUNDDOWN(단가 × 수량, 1) · 블록 비목 합 ROUNDDOWN(Σ, 0) · 합계 = 세 비목 합
|
||||||
* 관급 · 별도계상 자재 = 대가 안 0원(자재대 · 관급 단락에서 셈)
|
* 관급 · 별도계상 자재 = 대가 안 0원(자재대 · 관급 단락에서 셈)
|
||||||
* 빈칸 = 원천이 없으면 null · 「연결 없음」 목록(gaps)
|
* 빈칸 = 원천이 없으면 null · 「연결 없음」 목록(gaps)
|
||||||
* 빈 줄(166-6) = 블록 합 = 아는 줄 합 + blank n · blank_names — 내역 단가 · 부른 대가로는 안 넘김
|
* 빈 줄(166-6) = 블록 합 = 아는 줄 합 + blank n · blank_names — 내역 단가 · 부른 대가로는 안 넘김 ·
|
||||||
|
* 줄 0 개 블록 = 빈 줄 하나(NO_LINES)
|
||||||
* 고친 칸 덮개(702-2) = 사용자 값 daega_cover {블록 cover: {줄 cid: {qty · labor · material · expense}}} —
|
* 고친 칸 덮개(702-2) = 사용자 값 daega_cover {블록 cover: {줄 cid: {qty · labor · material · expense}}} —
|
||||||
* 있는 칸만 셈 값 대신 · 줄 base(품셈 값) · covered(고친 칸) · 짝 잃은 덮개 = daega_orphans(알림만)
|
* 있는 칸만 셈 값 대신 · 줄 base(품셈 값) · covered(고친 칸) · 짝 잃은 덮개 = daega_orphans(알림만)
|
||||||
* 복사본(703-2) = 덮개 K:… 의 @copy {from · name · spec} — 원본 cover 블록을 본뜬 새 호표
|
* 복사본(703-2) = 덮개 K:… 의 @copy {from · name · spec} — 원본 cover 블록을 본뜬 새 호표
|
||||||
@@ -36,6 +37,7 @@ import {
|
|||||||
const PARTS = ["labor", "material", "expense"] as const;
|
const PARTS = ["labor", "material", "expense"] as const;
|
||||||
const COVER_KEYS = ["qty", ...PARTS] as const;
|
const COVER_KEYS = ["qty", ...PARTS] as const;
|
||||||
const TAB = "dg";
|
const TAB = "dg";
|
||||||
|
const NO_LINES = "구성 줄 없음"; // 줄 0 개 일위대가의 빈 줄 이름(파이썬 짝)
|
||||||
export const COPY = "@copy";
|
export const COPY = "@copy";
|
||||||
/** 붙인 줄 덮개 열쇠(705-2) */
|
/** 붙인 줄 덮개 열쇠(705-2) */
|
||||||
export const ADD = "@add";
|
export const ADD = "@add";
|
||||||
@@ -153,7 +155,9 @@ function block(b: Row, books: Row, sums: Record<string, Row>, gaps: Gap[], own:
|
|||||||
known.reduce((acc, ln) => acc + ln.amounts[part], 0),
|
known.reduce((acc, ln) => acc + ln.amounts[part], 0),
|
||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
const blankNames = lines.filter((ln) => ln.amount === null).map((ln) => ln.name || "");
|
const blankNames = lines.length
|
||||||
|
? lines.filter((ln) => ln.amount === null).map((ln) => ln.name || "")
|
||||||
|
: [NO_LINES]; // 줄 0 개 일위대가 = 금액 0 이 아니라 모름(빈 줄)
|
||||||
return {
|
return {
|
||||||
id: b.id,
|
id: b.id,
|
||||||
key: b.id,
|
key: b.id,
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import {
|
|||||||
} from "@ui/ui_template_context_menu";
|
} from "@ui/ui_template_context_menu";
|
||||||
import type { Row } from "./B09_Estimation_Calc_Base";
|
import type { Row } from "./B09_Estimation_Calc_Base";
|
||||||
import type { TabContext, TabTable } from "./B09_Estimation_UI_Tabs";
|
import type { TabContext, TabTable } from "./B09_Estimation_UI_Tabs";
|
||||||
|
import { showToast } from "@ui/ui_template_elements";
|
||||||
import { linkItems, type ApplyRef } from "./B09_Estimation_UI_Tabs_Bill_Link";
|
import { linkItems, type ApplyRef } from "./B09_Estimation_UI_Tabs_Bill_Link";
|
||||||
import { linkMenu } from "./B09_Estimation_UI_Link";
|
import { linkMenu } from "./B09_Estimation_UI_Link";
|
||||||
|
|
||||||
@@ -208,6 +209,9 @@ export function editCell(
|
|||||||
put(ctx, w.bill);
|
put(ctx, w.bill);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 단위 비교 꼴 — 띄어쓰기 · 대소문자 · 호환 글자(㎥ = m3) 무시 */
|
||||||
|
const unitKey = (u: string): string => u.normalize("NFKC").replace(/\s+/g, "").toLowerCase();
|
||||||
|
|
||||||
/** 연결 적용 — 새 줄이 「새 줄」 · 빈 이름이면 고른 호표 명칭 · 규격 · 단위를 채움 */
|
/** 연결 적용 — 새 줄이 「새 줄」 · 빈 이름이면 고른 호표 명칭 · 규격 · 단위를 채움 */
|
||||||
function applyRef(ctx: TabContext, rows: DataRow[], i: number): ApplyRef {
|
function applyRef(ctx: TabContext, rows: DataRow[], i: number): ApplyRef {
|
||||||
return (ref, from) => {
|
return (ref, from) => {
|
||||||
@@ -222,6 +226,10 @@ function applyRef(ctx: TabContext, rows: DataRow[], i: number): ApplyRef {
|
|||||||
e.unit = e.unit || from.unit || "";
|
e.unit = e.unit || from.unit || "";
|
||||||
}
|
}
|
||||||
put(ctx, w.bill);
|
put(ctx, w.bill);
|
||||||
|
const mine = String(e.unit ?? row.unit ?? "");
|
||||||
|
const theirs = String(from?.unit ?? "");
|
||||||
|
if (ref && unitKey(mine) && unitKey(theirs) && unitKey(mine) !== unitKey(theirs))
|
||||||
|
showToast(`단위 다름 ${mine} ↔ ${theirs} — 연결은 됨 · 수량 단위 확인`, "warning");
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ from M01_MasterData import M01_MasterData_Store as m01
|
|||||||
from M02_MasterTemplete import M02_Labor_Inputs as labor_inputs
|
from M02_MasterTemplete import M02_Labor_Inputs as labor_inputs
|
||||||
from M02_MasterTemplete import M02_Template_Layers as layers
|
from M02_MasterTemplete import M02_Template_Layers as layers
|
||||||
|
|
||||||
SHAPE = 2 # 줄 꼴이 바뀌면 올림 — 옛 저장본을 안 씀
|
SHAPE = 3 # 줄 꼴이 바뀌면 올림 — 옛 저장본을 안 씀
|
||||||
KIND = "m02_logic_standard"
|
KIND = "m02_logic_standard"
|
||||||
REGION = "지역" # 지역 = 자동값 한 벌(정함 8)
|
REGION = "지역" # 지역 = 자동값 한 벌(정함 8)
|
||||||
QUIET = ("해당 없음", "없음") # 규격 글에서 뺄 값
|
QUIET = ("해당 없음", "없음") # 규격 글에서 뺄 값
|
||||||
@@ -83,7 +83,10 @@ def kind_of(row: dict) -> str:
|
|||||||
|
|
||||||
def words_of(row: dict) -> list[str]:
|
def words_of(row: dict) -> list[str]:
|
||||||
name = _sq(row.get("이름"))
|
name = _sq(row.get("이름"))
|
||||||
return [w for w, targets in WORDS.items() if any(_sq(t) in name for t in targets)]
|
out = [w for w, targets in WORDS.items() if any(_sq(t) in name for t in targets)]
|
||||||
|
if "터파기" in name: # 내역서 낱말 「측구파기」 ↔ 로직 「측구터파기」
|
||||||
|
out.append(str(row.get("이름")).replace("터파기", "파기"))
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
def _range_label(table: dict, low: Any, high: Any, unit: str) -> str:
|
def _range_label(table: dict, low: Any, high: Any, unit: str) -> str:
|
||||||
|
|||||||
@@ -196,7 +196,7 @@ def test_새_산근_사본_뒤_번호_호표_탭_집계표(tmp_path):
|
|||||||
|
|
||||||
def test_우클릭_메뉴_항목_추가_줄_삭제_연결_TS():
|
def test_우클릭_메뉴_항목_추가_줄_삭제_연결_TS():
|
||||||
# 184-3 — 모든 줄 메뉴 · 셈 출력 줄 = 계약 꼴(parent · auto · auto_{칸}) · 첫 손질 = v2 로 굳힘
|
# 184-3 — 모든 줄 메뉴 · 셈 출력 줄 = 계약 꼴(parent · auto · auto_{칸}) · 첫 손질 = v2 로 굳힘
|
||||||
src = _ts(["UI_Tabs", "UI_Tabs_Bill_Link", "UI_Tabs_Bill_Edit"])
|
src = _ts(["UI_Tabs", "UI_Tabs_Bill_Link", "UI_Link", "UI_Tabs_Bill_Edit"])
|
||||||
rows = [
|
rows = [
|
||||||
{"kind": "title", "key": "sec:1", "parent": None, "auto": True},
|
{"kind": "title", "key": "sec:1", "parent": None, "auto": True},
|
||||||
{"kind": "title", "key": "sec:1.2", "parent": "sec:1", "auto": True},
|
{"kind": "title", "key": "sec:1.2", "parent": "sec:1", "auto": True},
|
||||||
@@ -243,3 +243,26 @@ console.log(JSON.stringify(out));
|
|||||||
# 새 줄 지움 = 덮개에서 빠짐(gone 은 자동 줄만)
|
# 새 줄 지움 = 덮개에서 빠짐(gone 은 자동 줄만)
|
||||||
assert [e["key"] for e in out["left"]["rows"]] == ["sec:1", "sec:1.2", "earth:4"]
|
assert [e["key"] for e in out["left"]["rows"]] == ["sec:1", "sec:1.2", "earth:4"]
|
||||||
assert out["left"]["gone"] == []
|
assert out["left"]["gone"] == []
|
||||||
|
|
||||||
|
|
||||||
|
def test_줄_0개_일위대가_이으면_빈_줄():
|
||||||
|
"""703-1 가져오기 흠 — 줄 0 개 대가(금액 0)를 이은 내역 줄 = 금액 0 이 아니라 빈 줄."""
|
||||||
|
empty = {"no": 4, "key": "DG:e", "labor": 0, "material": 0, "expense": 0, "sum": 0,
|
||||||
|
"blank": 1} # fmt: skip
|
||||||
|
books = {**BOOKS, "daega": [*BOOKS["daega"], empty]}
|
||||||
|
hand = {"key": "hand:e", "section": "1.1", "after": "earth:1", "name": "빈 대가", "spec": "",
|
||||||
|
"unit": "㎡", "qty": 3, "ref": {"tab": "dg", "key": "DG:e"}} # fmt: skip
|
||||||
|
user = {"bill": {"rows": [hand]}}
|
||||||
|
sheets = compute_estimation(INPUTS, user, None, books)
|
||||||
|
row = _rows(sheets)["hand:e"]
|
||||||
|
assert row["sum"] is None and row["note"] == "대가4"
|
||||||
|
ok = _rows(compute_estimation(INPUTS, {"bill": {"rows": [HAND[0]]}}, None, books))
|
||||||
|
assert ok["hand:a"]["sum"] == 12300 # 빈 줄 없는 대가는 그대로
|
||||||
|
calc = _ts(["Calc_Base", "Calc_Bill"])
|
||||||
|
body = (
|
||||||
|
f"\nconst i = {json.dumps(INPUTS, ensure_ascii=False)};"
|
||||||
|
f"\nconst u = {json.dumps(user, ensure_ascii=False)};"
|
||||||
|
f"\nconst b = {json.dumps(books, ensure_ascii=False)};"
|
||||||
|
"\nconsole.log(JSON.stringify(computeEstimation(i, u, null, b)));"
|
||||||
|
)
|
||||||
|
assert json.loads(_node(calc + body)) == sheets # 거울
|
||||||
|
|||||||
@@ -218,7 +218,9 @@ def test_우클릭_레벨_메뉴_TS():
|
|||||||
body = MENU_JS.replace("__ROWS__", json.dumps(rows, ensure_ascii=False)).replace(
|
body = MENU_JS.replace("__ROWS__", json.dumps(rows, ensure_ascii=False)).replace(
|
||||||
"__USER__", json.dumps(USER, ensure_ascii=False)
|
"__USER__", json.dumps(USER, ensure_ascii=False)
|
||||||
)
|
)
|
||||||
out = json.loads(_node(_ts(["UI_Tabs", "UI_Tabs_Bill_Link", "UI_Tabs_Bill_Edit"]) + body))
|
out = json.loads(
|
||||||
|
_node(_ts(["UI_Tabs", "UI_Tabs_Bill_Link", "UI_Link", "UI_Tabs_Bill_Edit"]) + body)
|
||||||
|
)
|
||||||
level = {"묶음 줄로 바꾸기", "항목으로 바꾸기", "들여쓰기 →", "내어쓰기 ←"}
|
level = {"묶음 줄로 바꾸기", "항목으로 바꾸기", "들여쓰기 →", "내어쓰기 ←"}
|
||||||
pick = lambda key: [x for x in out[key] if x in level] # noqa: E731
|
pick = lambda key: [x for x in out[key] if x in level] # noqa: E731
|
||||||
assert [x for x in out["g1"] if "추가" in x] == ["항목 추가"] # 246-1 더함 하나
|
assert [x for x in out["g1"] if "추가" in x] == ["항목 추가"] # 246-1 더함 하나
|
||||||
@@ -312,7 +314,7 @@ def test_연결_단추_칸_메뉴_고르기_창_TS():
|
|||||||
.replace("__BILL__", json.dumps(sheets["bill"], ensure_ascii=False))
|
.replace("__BILL__", json.dumps(sheets["bill"], ensure_ascii=False))
|
||||||
.replace("__DAEGA__", json.dumps(BOOKS["daega"], ensure_ascii=False))
|
.replace("__DAEGA__", json.dumps(BOOKS["daega"], ensure_ascii=False))
|
||||||
)
|
)
|
||||||
src = _ts(["UI_Tabs", "UI_Tabs_Bill_Link", "UI_Tabs_Bill_Edit", "UI_Tabs_Bill"])
|
src = _ts(["UI_Tabs", "UI_Tabs_Bill_Link", "UI_Link", "UI_Tabs_Bill_Edit", "UI_Tabs_Bill"])
|
||||||
out = json.loads(_node(src + body))
|
out = json.loads(_node(src + body))
|
||||||
assert out["columns"] == ["connect", "note"] # 비고 앞 「연결」 칸
|
assert out["columns"] == ["connect", "note"] # 비고 앞 「연결」 칸
|
||||||
# 184-3 모든 항목 줄 · 새 줄 연결됨 = 호표 번호 · 자동 줄 연결됨 = 「연결됨」 · 묶음 = 없음
|
# 184-3 모든 항목 줄 · 새 줄 연결됨 = 호표 번호 · 자동 줄 연결됨 = 「연결됨」 · 묶음 = 없음
|
||||||
@@ -357,7 +359,7 @@ console.log(JSON.stringify(out));
|
|||||||
|
|
||||||
|
|
||||||
def test_글_칸_위_우클릭도_줄_메뉴_TS():
|
def test_글_칸_위_우클릭도_줄_메뉴_TS():
|
||||||
src = _ts(["UI_Tabs", "UI_Tabs_Bill_Link", "UI_Tabs_Bill_Edit", "UI_Tabs_Bill"])
|
src = _ts(["UI_Tabs", "UI_Tabs_Bill_Link", "UI_Link", "UI_Tabs_Bill_Edit", "UI_Tabs_Bill"])
|
||||||
out = json.loads(_node(src + ROW_MENU_JS))
|
out = json.loads(_node(src + ROW_MENU_JS))
|
||||||
assert out["onInput"] is True and out["onCell"] is True
|
assert out["onInput"] is True and out["onCell"] is True
|
||||||
assert out["opened"] == [[5, 6, ["줄 7"]], [5, 6, ["줄 7"]]]
|
assert out["opened"] == [[5, 6, ["줄 7"]], [5, 6, ["줄 7"]]]
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ def _ts(names: list[str]) -> str:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
SRC = ["UI_Tabs", "UI_Tabs_Bill_Link", "UI_Tabs_Bill_Edit"]
|
SRC = ["UI_Tabs", "UI_Tabs_Bill_Link", "UI_Link", "UI_Tabs_Bill_Edit"]
|
||||||
|
|
||||||
|
|
||||||
def _menu(user, labels=(), runs=(), edits=(), rows=ROWS):
|
def _menu(user, labels=(), runs=(), edits=(), rows=ROWS):
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ out.keyAct = [
|
|||||||
console.log(JSON.stringify(out));
|
console.log(JSON.stringify(out));
|
||||||
"""
|
"""
|
||||||
|
|
||||||
SRC = ["UI_Tabs", "UI_Tabs_Bill_Link", "UI_Tabs_Bill_Edit", "UI_Tabs_Bill", "UI_Tabs_Bill_Drag",
|
SRC = ["UI_Tabs", "UI_Tabs_Bill_Link", "UI_Link", "UI_Tabs_Bill_Edit", "UI_Tabs_Bill", "UI_Tabs_Bill_Drag",
|
||||||
"UI_Tabs_Bill_Level"] # fmt: skip
|
"UI_Tabs_Bill_Level"] # fmt: skip
|
||||||
IN, OUT, UP, DOWN = "들여쓰기 →", "내어쓰기 ←", "위로 ↑", "아래로 ↓"
|
IN, OUT, UP, DOWN = "들여쓰기 →", "내어쓰기 ←", "위로 ↑", "아래로 ↓"
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ if str(ROOT) not in sys.path:
|
|||||||
from B09_Estimation import B09_Estimation_Store as store # noqa: E402
|
from B09_Estimation import B09_Estimation_Store as store # noqa: E402
|
||||||
from B09_Estimation.B09_Estimation_Calc_Bill import compute_estimation # noqa: E402
|
from B09_Estimation.B09_Estimation_Calc_Bill import compute_estimation # noqa: E402
|
||||||
|
|
||||||
SRC = ["UI_Tabs", "UI_Tabs_Bill_Link", "UI_Tabs_Bill_Edit", "UI_Tabs_Bill", "UI_Tabs_Bill_Drag",
|
SRC = ["UI_Tabs", "UI_Tabs_Bill_Link", "UI_Link", "UI_Tabs_Bill_Edit", "UI_Tabs_Bill", "UI_Tabs_Bill_Drag",
|
||||||
"UI_Tabs_Bill_Level"] # fmt: skip
|
"UI_Tabs_Bill_Level"] # fmt: skip
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ from B09_Estimation.B09_Estimation_Calc_Bill import compute_estimation # noqa:
|
|||||||
|
|
||||||
IMPORTS = re.compile(r"^import[^;]*;\r?\n", re.MULTILINE)
|
IMPORTS = re.compile(r"^import[^;]*;\r?\n", re.MULTILINE)
|
||||||
TABLE = IMPORTS.sub("", (ROOT / "ui_template" / "ui_template_data_table.ts").read_text("utf-8"))
|
TABLE = IMPORTS.sub("", (ROOT / "ui_template" / "ui_template_data_table.ts").read_text("utf-8"))
|
||||||
SRC = ["UI_Tabs", "UI_Tabs_Bill_Link", "UI_Tabs_Bill_Edit", "UI_Tabs_Bill", "UI_Tabs_Bill_Drag",
|
SRC = ["UI_Tabs", "UI_Tabs_Bill_Link", "UI_Link", "UI_Tabs_Bill_Edit", "UI_Tabs_Bill", "UI_Tabs_Bill_Drag",
|
||||||
"UI_Tabs_Bill_Level"] # fmt: skip
|
"UI_Tabs_Bill_Level"] # fmt: skip
|
||||||
IN, OUT = "들여쓰기 →", "내어쓰기 ←"
|
IN, OUT = "들여쓰기 →", "내어쓰기 ←"
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ from B09_Estimation.B09_Estimation_Calc_Bill import compute_estimation # noqa:
|
|||||||
|
|
||||||
IMPORTS = re.compile(r"^import[^;]*;\r?\n", re.MULTILINE)
|
IMPORTS = re.compile(r"^import[^;]*;\r?\n", re.MULTILINE)
|
||||||
TABLE = IMPORTS.sub("", (ROOT / "ui_template" / "ui_template_data_table.ts").read_text("utf-8"))
|
TABLE = IMPORTS.sub("", (ROOT / "ui_template" / "ui_template_data_table.ts").read_text("utf-8"))
|
||||||
SRC = ["UI_Tabs", "UI_Tabs_Bill_Link", "UI_Tabs_Bill_Edit", "UI_Tabs_Bill"]
|
SRC = ["UI_Tabs", "UI_Tabs_Bill_Link", "UI_Link", "UI_Tabs_Bill_Edit", "UI_Tabs_Bill"]
|
||||||
SUMS = ["sum", "labor", "material", "expense"]
|
SUMS = ["sum", "labor", "material", "expense"]
|
||||||
FOLDER_SVG, LEAF_SVG = "M1.5 3.5h4", "M3.5 1.5h6"
|
FOLDER_SVG, LEAF_SVG = "M1.5 3.5h4", "M3.5 1.5h6"
|
||||||
|
|
||||||
@@ -303,7 +303,7 @@ def test_고른_줄_Enter_F2_입력_시작():
|
|||||||
"bar = levelBar(root, table);", "bar = levelBar(root, table, (i) => edits.push(i));"
|
"bar = levelBar(root, table);", "bar = levelBar(root, table, (i) => edits.push(i));"
|
||||||
)
|
)
|
||||||
body = (setup + KEYS_JS).replace("__ROWS__", json.dumps(FAKE_ROWS, ensure_ascii=False))
|
body = (setup + KEYS_JS).replace("__ROWS__", json.dumps(FAKE_ROWS, ensure_ascii=False))
|
||||||
names = ["UI_Tabs", "UI_Tabs_Bill_Link", "UI_Tabs_Bill_Edit", "UI_Tabs_Bill",
|
names = ["UI_Tabs", "UI_Tabs_Bill_Link", "UI_Link", "UI_Tabs_Bill_Edit", "UI_Tabs_Bill",
|
||||||
"UI_Tabs_Bill_Drag", "UI_Tabs_Bill_Level"] # fmt: skip
|
"UI_Tabs_Bill_Drag", "UI_Tabs_Bill_Level"] # fmt: skip
|
||||||
out = json.loads(_node(_ts(names) + body))
|
out = json.loads(_node(_ts(names) + body))
|
||||||
at = [r["key"] for r in FAKE_ROWS].index("earth:5")
|
at = [r["key"] for r in FAKE_ROWS].index("earth:5")
|
||||||
|
|||||||
@@ -126,3 +126,14 @@ def test_화면_기준_목록_계산서_담기() -> None:
|
|||||||
router = (ROOT / "M02_MasterTemplete/M02_MasterTemplete_Router_Combos.py").read_text("utf-8")
|
router = (ROOT / "M02_MasterTemplete/M02_MasterTemplete_Router_Combos.py").read_text("utf-8")
|
||||||
assert '@router.get("/logic-lib/standard", dependencies=[Depends(verify_session)])' in router
|
assert '@router.get("/logic-lib/standard", dependencies=[Depends(verify_session)])' in router
|
||||||
assert '@router.post("/logic-lib/sheet", dependencies=[Depends(verify_session)])' in router
|
assert '@router.post("/logic-lib/sheet", dependencies=[Depends(verify_session)])' in router
|
||||||
|
|
||||||
|
|
||||||
|
def test_내역서_낱말_측구파기로_측구터파기를_찾음() -> None:
|
||||||
|
logic = next(
|
||||||
|
logic
|
||||||
|
for _, data in m01._logic_files(m01.loaded()[0])
|
||||||
|
for logic in data.get("줄") or []
|
||||||
|
if logic.get("키") == "GF000099" # 9-12-1 측구터파기 토사
|
||||||
|
)
|
||||||
|
row = {**logic, "별칭": ", ".join(st.words_of(logic))}
|
||||||
|
assert hit(row, "측구파기")
|
||||||
|
|||||||
@@ -301,3 +301,17 @@ def test_잊은_짝_느슨한_기억에도_안_나옴(tmp_path, monkeypatch):
|
|||||||
assert lk.recall(memory, third) is None # 잊은 짝 곁에서는 느슨하게 안 좁힘
|
assert lk.recall(memory, third) is None # 잊은 짝 곁에서는 느슨하게 안 좁힘
|
||||||
route.keep(user, {lk.key_of(row): live}) # 다시 이음 = 풀림
|
route.keep(user, {lk.key_of(row): live}) # 다시 이음 = 풀림
|
||||||
assert lk.recall(route.recalled(user), row) == live
|
assert lk.recall(route.recalled(user), row) == live
|
||||||
|
|
||||||
|
|
||||||
|
def test_잊은_짝_짝_표_제안에도_안_나옴(geo):
|
||||||
|
_user, rows = _load(geo)
|
||||||
|
now = {s["key"]: s for s in lk.suggest(rows, {})}
|
||||||
|
line = next(r for r in rows if (r["name"], r.get("spec")) == ("토사절취", "백호0.7㎥"))
|
||||||
|
assert now[line["key"]]["꼬리표"] == lk.TABLE
|
||||||
|
memory = {lk.key_of(line): {lk.FORGOT: True}}
|
||||||
|
after = {s["key"]: s for s in lk.suggest(rows, memory)}
|
||||||
|
assert line["key"] not in after # 짝 표 제안도 잊음
|
||||||
|
assert set(now) - set(after) == {line["key"]} # 다른 줄은 그대로
|
||||||
|
memory[lk.key_of(line)] = {"확정": "earth:4", "이름": "절토(토사)"} # 다시 이음 = 풀림
|
||||||
|
assert lk.suggest(rows, memory)[0] is not None
|
||||||
|
assert line["key"] in {s["key"] for s in lk.suggest(rows, memory)}
|
||||||
|
|||||||
Reference in New Issue
Block a user