feat(B09 설계내역서): 경쟁사 내역 엑셀 줄 불러오기 서버 — 읽기 · 짜기 · 고정 단가 칸 (PLAN 707-1)
- 읽기(Bill_Excel) — STmate 「설계내역서」 숨은 코드 · 부모 코드 열 · EST 「내역서」 공종 번호 깊이 · 비고 대가 · 산근 · 단산 · 일위 · 제외 묶음(관급 · 제외금액) · 조달수수료 = 율 · DRM = 「읽을 수 없음」 · 열 머리 = M02 실무자료 칸 읽기 재사용 - 짜기(Bill_Import) — 공종 = 새 묶음 · 항목 = 새 줄 + 고정 단가 칸 · 수량 갈래 take · price · 이름 같은 자동 줄 붙임 · 남은 자동 줄 지움 · 같은 파일 다시 = 갈아 끼움 · 어긋난 줄 목록 - 길(Router_Import) — import/bill(file · file_key) 미리 보기 · import/bill/apply(같은 파일 이름 실무자료 사전조합 → 서고 사본 연결 · 층 쓰기 0) · 저장 안 함 - 셈 짝(Calc_Bill py · ts) — 줄 price = 연결이 단가를 못 낼 때 금액 · fixed · src_qty · Store 다듬기 - 확인 = 기번3 710,359,136 · 영월 767,148,700 · 봉화 781,283,415 · 거창 384,916,227 직접비 합 = 엑셀 · 빈 줄 0 · 어긋남 0 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -13,6 +13,8 @@
|
||||
* 단가 = `refPrice(ref)` 하나(dg 대가 목록 · sg 산근 목록 · logic = 서버 sg_hand 산근(702-3 연결 즉시 뒤에서 셈) · 그 밖 hopyo)
|
||||
* 자유 편집(184) = `user.bill` v2 덮개 {v: 2, rows: [표 차례 · 고친 칸 · 새 줄], gone: [지운 자동 줄]} ·
|
||||
* 옛 꼴(qty · 손 줄 after · parent) 그대로 읽음 · 저장 꼴 · 출력 줄 칸(계약) = 짝 .py 머리
|
||||
* 고정 단가 칸(707-1) = 줄 price {labor, material, expense} — 연결이 단가를 못 내면 그것으로 금액(줄 fixed) ·
|
||||
* src_qty = 불러온 수량(비교 칸)
|
||||
* 출력 줄 칸 = kind · key · name · parent · level · no · cost · auto | hand · auto_{칸} · section
|
||||
* ========================================================================== */
|
||||
|
||||
@@ -79,6 +81,8 @@ function itemRow(item: Row, prices: Row | null): Row {
|
||||
ref: item.ref ?? null,
|
||||
...Object.fromEntries(Object.entries(item).filter(([k]) => k.startsWith("auto_"))),
|
||||
...(item.hand ? { hand: true } : { auto: true }),
|
||||
...(item.fixed ? { fixed: true } : {}),
|
||||
...(num(item.src_qty) !== null ? { src_qty: item.src_qty } : {}),
|
||||
...amounts(qty, prices),
|
||||
};
|
||||
row._gaps = [];
|
||||
@@ -134,15 +138,31 @@ export function refPrice(ref: Row | null, books: Row, hopyo: Row, rowKey = ""):
|
||||
return key ? (hopyo[key] ?? null) : null;
|
||||
}
|
||||
|
||||
/** 새 줄(hand:) → [항목, 단가, 까닭] — 연결 = 고른 호표(로직 = 새 산근 키로 풀어 둠) */
|
||||
/** 고정 단가 칸(707-1) → 1 단위 단가 — 빈 비목 0 · 칸 없음 = null */
|
||||
export function fixedPrice(price: unknown): Row | null {
|
||||
if (!price || typeof price !== "object" || Array.isArray(price)) return null;
|
||||
const out: Row = { no: "" };
|
||||
for (const p of PARTS) out[p] = num((price as Row)[p]) || 0;
|
||||
out.sum = out.labor + out.material + out.expense;
|
||||
return out;
|
||||
}
|
||||
|
||||
/** 새 줄(hand:) → [항목, 단가, 까닭] — 연결 = 고른 호표(로직 = 새 산근 키로 풀어 둠) ·
|
||||
* 연결이 단가를 못 내면 고정 단가 칸(707-1) */
|
||||
export function handItems(user: Row, books: Row, hopyo: Row): Array<[Row, Row | null, string]> {
|
||||
const out: Array<[Row, Row | null, string]> = [];
|
||||
for (const hand of (user.bill || {}).rows || []) {
|
||||
if (!String(hand.key || "").startsWith("hand:")) continue;
|
||||
const price = refPrice(hand.ref ?? null, books, hopyo, hand.key);
|
||||
let price = refPrice(hand.ref ?? null, books, hopyo, hand.key);
|
||||
const ref = price?.tab ? { tab: price.tab, key: price.key } : null;
|
||||
let fixed = false;
|
||||
if (price === null) {
|
||||
price = fixedPrice(hand.price);
|
||||
fixed = price !== null;
|
||||
}
|
||||
const why = hand.ref?.tab === "logic" ? WHY_LOGIC : WHY_HAND;
|
||||
out.push([{ ...hand, hand: true, note: price?.no || "", ref }, price, why]);
|
||||
const note = price?.no || hand.note || "";
|
||||
out.push([{ ...hand, hand: true, note, ref, fixed }, price, why]);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
@@ -171,6 +191,11 @@ function covered(
|
||||
out.note = prices?.no || "";
|
||||
if (cover.ref?.tab === "logic") out.why = WHY_LOGIC;
|
||||
}
|
||||
if (prices === null) {
|
||||
prices = fixedPrice(cover.price); // 707-1 연결이 단가를 못 냄 = 고정 단가 칸
|
||||
if (prices !== null) out.fixed = true;
|
||||
}
|
||||
if (num(cover.src_qty) !== null) out.src_qty = num(cover.src_qty);
|
||||
return [out, prices];
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user