272 lines
12 KiB
JavaScript
272 lines
12 KiB
JavaScript
/* -*- coding: utf-8 -*- */
|
|
/**
|
|
* 보고서 부속 (report_init.js) — 〓 INITIAL 〓 설정 시트 · 금액 한글 표기(AMTTOHAN) · 제잡비 요율표 인쇄
|
|
* 근거: 지식DB STmate/old/20_분석 18 §2.3(INITIAL = 엑셀 → STmate 재등록 메타) · 24 §2.4(AMTTOHAN 「금 일억삼천사백이십만원정」)
|
|
* · §3(CONV_XLS_2_ST) · 06 §1~2 · 15 §4(제비율표 좌표 — scr_kanjub_rate.js StmateRate)
|
|
* 정답 대조: resources/tester/test_stmate_report_coll.py(INITIAL — 원본 STMATE 출력 엑셀)
|
|
*/
|
|
const StmateReportInit = (() => {
|
|
const g = typeof globalThis !== "undefined" ? globalThis : {};
|
|
const C = g.STMATE_REPORT_CORE || require("./report_core.js");
|
|
const { num, str } = C;
|
|
const tf = (v) => (String(v ?? "").trim() === "1" || v === true ? "True" : "False");
|
|
|
|
/**
|
|
* [Sheet정보] 18칸 — 칸 이름 · 시트 id · 열 자리(ITNAME NAME SIZE QTY UNIT SPOS · TAMT…NAMOUNT · INFO)
|
|
* 열 자리 = 각 시트 양식의 열 차례(재등록 때 읽는 자리) · EPOS = 그 시트 마지막 행
|
|
*/
|
|
const F = (it, nm, sz, q, un, sp, amts, info) => ({ it, nm, sz, q, un, sp, amts, info });
|
|
const LIST = F(null, 2, 3, null, 4, 4, [5], 7);
|
|
const BIMOK = F(null, 2, 3, null, 4, 4, [5, null, 7, null, 6, null, 8], 10);
|
|
const SLOTS = [
|
|
["재료비목록표", "재료비목록표", LIST],
|
|
["노무비목록표", "노무비목록표", LIST],
|
|
["경비목록표", "경비목록표", LIST],
|
|
["일식목록표", "일식견적목록표", BIMOK],
|
|
["환율 및 기초자료", "환율및기초자료", F(2, 3, 4, null, 5, 6, [6], 9)],
|
|
["중기목록표", "중기목록표", BIMOK],
|
|
["실적단가표", null, null],
|
|
["일위대가목록표", "일위대가목록표", BIMOK],
|
|
["산출근거목록표", "단가산출근거목록표", BIMOK],
|
|
[
|
|
"자재단가대비표",
|
|
"자재단가대비표",
|
|
F(null, 2, 3, null, 4, 5, [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], 18),
|
|
],
|
|
["내역서", "설계내역서", F(1, 2, 3, 4, 5, 5, [6, 7, 10, 11, 8, 9, 12, 13], 15)],
|
|
["총괄내역서", "총괄내역서", F(1, 2, 3, null, 5, 4, [4, 9, 13, 14, 15, 16], 8)],
|
|
["중기사용료", "중기사용료", F(null, 1, 2, 3, 4, 5, [5, 6, 9, 10, 7, 8, 11, 12], 14)],
|
|
["일위대가표", "일위대가표", F(null, 1, 2, 3, 4, 5, [5, 6, 9, 10, 7, 8, 11, 12], 14)],
|
|
[
|
|
"단가산출근거",
|
|
"단가산출근거",
|
|
F(1, 2, null, null, null, 5, [3, null, 5, null, 4, null, 6], 7),
|
|
],
|
|
["", null, null],
|
|
["", null, null],
|
|
["표준시장목록표", "표준시장목록표", BIMOK],
|
|
];
|
|
const COLS = "CDEFGHIJKLMNOPQRSTUVWX".split("");
|
|
|
|
// 차수 목록 — P_ORD [지금 차수, 저장된 차수…] 다섯 칸
|
|
function stageList(state, n) {
|
|
const ks = Object.keys((state && state.kanjubStages) || {})
|
|
.map(Number)
|
|
.filter((k) => k > 0)
|
|
.sort((a, b) => a - b);
|
|
const list = ks.length ? ks : [1];
|
|
return [n].concat(list, [0, 0, 0, 0, 0]).slice(0, 6).map(String);
|
|
}
|
|
|
|
/**
|
|
* 〓 INITIAL 〓 — sheets = 묶음 시트 모형(id·name·rows) · n 차수 · opts.date(출력 일시) · opts.path(파일 자리)
|
|
* 절 머리(B) 의 D 칸 = 다음 절 머리 행 번호
|
|
*/
|
|
function initialSheet(dbf, state, sheets, n = 1, opts = {}) {
|
|
const ini = (dbf && dbf.start_ini) || {};
|
|
const prj = (dbf && dbf.prjlst) || {};
|
|
const sh = { name: "〓 INITIAL 〓", title: "INITIAL", rows: [], cols: {} };
|
|
const put = (r, cells) => C.put(sh, r, cells);
|
|
put(2, {
|
|
B: "※※ 현재 Sheet를 수정 또는 삭제하지 마십시요[수정/삭제시 STmate 데이타로 변환할 수 없습니다] ※※",
|
|
});
|
|
const byId = {};
|
|
for (const s of sheets || []) byId[s.id || s.name] = s;
|
|
put(4, { B: "[Sheet정보]", C: false, D: 24 });
|
|
const hd = { B: "목차", C: "Sheet", D: "FPos", E: "ITNAME", F: "NAME", G: "SIZE", H: "QTY" };
|
|
Object.assign(hd, { I: "UNIT", J: "SPOS", K: "EPOS" });
|
|
"TAMT TAMOUNT MAMT MAMOUNT LAMT LAMOUNT SAMT SAMOUNT AAMT AAMOUNT NAMT NAMOUNT"
|
|
.split(" ")
|
|
.forEach((t, i) => (hd[COLS[9 + i]] = t));
|
|
hd.X = "INFO";
|
|
put(5, hd);
|
|
SLOTS.forEach(([label, id, f], i) => {
|
|
const cells = { B: `${i + 1}. ${label}` };
|
|
const s = id && (byId[id] || Object.values(byId).find((x) => x.name === id));
|
|
if (s && f) {
|
|
Object.assign(cells, {
|
|
C: s.name,
|
|
D: `${opts.path || ""}[${opts.file || "STMATE"}]${s.name}`,
|
|
});
|
|
const pos = { E: f.it, F: f.nm, G: f.sz, H: f.q, I: f.un, J: f.sp, K: s.rows.length };
|
|
f.amts.forEach((v, j) => (pos[COLS[9 + j]] = v));
|
|
pos.X = f.info;
|
|
for (const [k, v] of Object.entries(pos)) if (v != null) cells[k] = v;
|
|
}
|
|
put(6 + i, cells);
|
|
});
|
|
// [공사정보]
|
|
put(24, { B: "[공사정보]", D: 33 });
|
|
const info = [
|
|
["M_VER", str(prj.M_VER || "")],
|
|
["PNAME", C.projectName(dbf)],
|
|
["PCLAS", str(prj.PCLASS ?? "0").trim() || "0"],
|
|
["SCLAS", str(prj.SCLASS ?? "0").trim() || "0"],
|
|
["K_ORD", str(prj.K_ORD ?? "0").trim() || "0"],
|
|
["PRIPR", tf(prj.PRIV_PR === "T" || prj.PRIV_PR === true ? "1" : prj.PRIV_PR)],
|
|
["ACTYP", str(prj.ACTTYP ?? "0").trim() || "0"],
|
|
["ACTOP", str(prj.ACTOPT ?? "0").trim() || "0"],
|
|
];
|
|
info.forEach(([k, v], i) => put(25 + i, v === "" ? { B: k } : { B: k, C: v }));
|
|
// [초기값] — 환율 8칸 = 달러 저·고 · 달러 저·고 · 유로 둘 · 엔 둘(원본 출력 차례)
|
|
put(33, { B: "[초기값]", D: 52 });
|
|
const pOrd = stageList(state, n);
|
|
put(34, { B: "P_ORD", C: pOrd[0], D: pOrd[1], E: pOrd[2], F: pOrd[3], G: pOrd[4], H: pOrd[5] });
|
|
const ex = ["EXLNM1", "EXHNM1", "EXLNM1", "EXHNM1", "EXEUR1", "EXEUR1", "EXYEN1", "EXYEN1"];
|
|
const exRow = { B: "EXNM_" };
|
|
ex.forEach((k, i) => (exRow[COLS[i]] = num(ini[k])));
|
|
put(35, exRow);
|
|
const init = [
|
|
["EXRNM", tf(ini.EXRNM)],
|
|
["RXNM_", str(ini.RXXNM)],
|
|
["COND_", str(ini.CONLD)],
|
|
["KCDNM", str(ini.KCDNM ?? "1")],
|
|
["JCDNM", str(ini.JCDNM ?? "0")],
|
|
["ECDNM", str(ini.ECDNM ?? "0")],
|
|
["ACDNM", str(ini.ACDNM ?? "1")],
|
|
["BPNNM", str(ini.BPNNM ?? "1")],
|
|
["ZCDNM", str(ini.ZCDNM ?? "2")],
|
|
["CHGNM", tf(ini.CHGNM)],
|
|
["CHBNM", tf(ini.CHBNM)],
|
|
["CHNNM", tf(ini.CHNNM)],
|
|
["CUTNM", tf(ini.CUTNM)],
|
|
["OPTNM", str(ini.OPTNM || "SML")],
|
|
["S_JDA", tf(ini.S_JDA)],
|
|
["SUBNM", str(ini.SUBNM)],
|
|
];
|
|
init.forEach(([k, v], i) => put(36 + i, { B: k, C: v }));
|
|
// [인쇄정보]
|
|
put(52, { B: "[인쇄정보]", D: 75 });
|
|
const bm = [1, 2, 3, 4].map((i) => str(ini[`BMK_STR${i}`]));
|
|
put(53, { B: "BMSTR", C: bm[0], D: bm[1], E: bm[2], F: bm[3] });
|
|
put(54, { B: "BMKNM", C: str(ini.BMKNM || "TLMS") });
|
|
put(55, { B: "JEMNM", C: str(ini.JEMNM) });
|
|
for (let i = 1; i <= 6; i++) {
|
|
const cells = { B: `JMKN${i}`, C: str(ini[`JMOK${i}`]).trim() };
|
|
if (i < 6) cells.D = str(ini[`JMK${i}0`]).trim();
|
|
put(55 + i, cells);
|
|
}
|
|
const caps = "CODE NO IBRD EQCOD ITNUM NAME SIZE QTY SUNIT AMT PAGE AMOUNT BIGO".split(" ");
|
|
caps.forEach((k, i) => put(62 + i, { B: `CAP_${k}`, C: str(ini[`CAP_${k}`]) }));
|
|
// [PREPARE]
|
|
put(75, { B: "[PREPARE]", D: 79 });
|
|
put(76, { B: "PREP_VER", C: `w${str(ini.PRG_V)}` });
|
|
put(77, { B: "PREP_COP", C: str(opts.cop || "STMATE 재현 앱") });
|
|
put(78, { B: "PREP_DATE", C: str(opts.date || "") });
|
|
put(79, { B: "[.끝.]" });
|
|
return sh;
|
|
}
|
|
|
|
/**
|
|
* 금액 한글 표기(AMTTOHAN) — 「금 일억삼천사백이십만원정」
|
|
* 네 자리 묶음(만·억·조·경)마다 천·백·십 · 자리 숫자 1 도 「일」로 적음(금액 고침 막기 · 원본 예 「일억」)
|
|
*/
|
|
const DIG = ["", "일", "이", "삼", "사", "오", "육", "칠", "팔", "구"];
|
|
const SMALL = ["천", "백", "십", ""];
|
|
const BIG = ["", "만", "억", "조", "경"];
|
|
function amtToHan(v, opts = {}) {
|
|
const n = Math.trunc(Math.abs(num(v)));
|
|
if (!n) return opts.bare ? "영" : "금 영원정";
|
|
const s = String(n);
|
|
const groups = [];
|
|
for (let i = s.length; i > 0; i -= 4)
|
|
groups.unshift(s.slice(Math.max(0, i - 4), i).padStart(4, "0"));
|
|
let out = "";
|
|
groups.forEach((gp, gi) => {
|
|
let part = "";
|
|
for (let k = 0; k < 4; k++) if (gp[k] !== "0") part += DIG[gp[k]] + SMALL[k];
|
|
if (part) out += part + BIG[groups.length - 1 - gi];
|
|
});
|
|
const sign = num(v) < 0 ? "마이너스 " : "";
|
|
return opts.bare ? sign + out : `금 ${sign}${out}원정`;
|
|
}
|
|
|
|
/**
|
|
* 제잡비 요율표 인쇄(PM_KAN_RATE) — 공사규모 묶음 × 공사기간 · 간접노무비·기타경비(공종별) · 일반관리비 · 이윤
|
|
* + 부속표(보험·안전관리비) · 값 = STC 안 RATE_R.DBF(행렬 좌표는 StmateRate)
|
|
*/
|
|
function rateSheet(dbf, opts = {}) {
|
|
const R = g.StmateRate || require("./scr_kanjub_rate.js");
|
|
const src = opts.table || "RATE_R.DBF";
|
|
const rows = ((dbf && dbf.rate_tables) || {})[src];
|
|
const m = R.matrixFromRows(rows || []);
|
|
const sh = C.newSheet("제잡비요율표", "제 잡 비 요 율 표", C.projectName(dbf), "R");
|
|
if (!m.length) {
|
|
C.push(sh, { A: `${src} 없음`, _k: "item" });
|
|
return sh;
|
|
}
|
|
const kongs = [
|
|
[1, "토목"],
|
|
[2, "산설(토)"],
|
|
[3, "조경"],
|
|
[4, "건축"],
|
|
[5, "산설(건)"],
|
|
];
|
|
const cols = "CDEFGHIJKLMNOP".split("");
|
|
const h3 = { A: "공사규모", B: "공사기간", _k: "head" };
|
|
kongs.forEach(([, l], i) => ((h3[cols[i]] = `간노 ${l}`), (h3[cols[i + 5]] = `기타 ${l}`)));
|
|
Object.assign(h3, { M: "일반관리비", N: "일반관리비(전문)", O: "이윤" });
|
|
C.push(sh, h3);
|
|
for (const b of R.BANDS) {
|
|
if (b.optional && !kongs.some(([c]) => R.cell(m, b.row, c))) continue;
|
|
R.KIKAN.forEach((k, p) => {
|
|
const row = b.row + p;
|
|
const cells = { A: p === 0 ? b.name : "", B: k, _k: "item" };
|
|
kongs.forEach(([c], i) => {
|
|
cells[cols[i]] = R.cell(m, row, c);
|
|
cells[cols[i + 5]] = R.cell(m, row, c + 5);
|
|
});
|
|
if (p === 0)
|
|
Object.assign(cells, {
|
|
M: R.cell(m, row, 11),
|
|
N: R.cell(m, row, 15),
|
|
O: R.cell(m, row, 16),
|
|
});
|
|
C.push(sh, cells);
|
|
});
|
|
}
|
|
C.push(sh, {});
|
|
C.push(sh, { A: "부속표", B: "구분", C: "요율", _k: "head" });
|
|
const annex = [
|
|
["산재보험료", 45, 1],
|
|
["건강보험료", 46, 1],
|
|
["연금보험료", 46, 6],
|
|
["노인장기요양보험료", 46, 11],
|
|
];
|
|
for (const [l, r, c] of annex) C.push(sh, { B: l, C: R.cell(m, r, c), _k: "item" });
|
|
for (let gr = 1; gr <= 7; gr++)
|
|
C.push(sh, {
|
|
B: `고용보험 ${gr < 7 ? `${gr} 등급` : "7 등급이하"}`,
|
|
C: R.cell(m, 45, 10 + gr),
|
|
_k: "item",
|
|
});
|
|
C.push(sh, {});
|
|
C.push(sh, {
|
|
A: "안전관리비",
|
|
B: "공종",
|
|
C: "5억 미만",
|
|
D: "5~50억 미만",
|
|
E: "기초액(천원)",
|
|
F: "50억 이상",
|
|
_k: "head",
|
|
});
|
|
for (const [l, t] of [
|
|
["건축", 0],
|
|
["토목", 1],
|
|
["중건설", 3],
|
|
["특수건설", 4],
|
|
]) {
|
|
const o = R.ANJUN_OFF[t];
|
|
const cells = { B: l, C: R.cell(m, 10 + o, 17), D: R.cell(m, 20 + o, 17), _k: "item" };
|
|
Object.assign(cells, { E: R.cell(m, 20 + o, 18), F: R.cell(m, 25 + o, 17) });
|
|
C.push(sh, cells);
|
|
}
|
|
return sh;
|
|
}
|
|
|
|
return { initialSheet, amtToHan, rateSheet, SLOTS };
|
|
})();
|
|
|
|
if (typeof window !== "undefined") window.STMATE_REPORT_INIT = StmateReportInit;
|
|
if (typeof module !== "undefined" && module.exports) module.exports = StmateReportInit;
|