Files
Aislo/tools/stmate-test/kanjub_calc.js
T

510 lines
20 KiB
JavaScript

/* -*- coding: utf-8 -*- */
/**
* 원가계산서(제잡비) 계산 (kanjub_calc.js) — STMATE Calc_Kanjub 네이티브 순서
* 직접비 → 간접노무비 → 보험 → 안전 → 경비 → (추가1) → 일반관리비 → 이윤 → 이윤 뒤 가산(추가2)
* → 공사보험 → 작업설 감액 → 부가세 → 세후 가산(추가3) → 도급 절사 → 관급 → 사급 → (추가4) → 총공사비
* 근거: 지식DB STmate/old/20_분석 06 · 11 · 12 · 20(KAN_ORD) · 25 · 35
* REA 18(보험·안전·수공 경비·변경 차액) · REA 20(일반관리비·이윤 절사·공사보험·부가세·관급·추가금액 순서)
* 설정: cfg.keys = PRJLST.SMT [n_KANJUB] 원본 키(차수 접두 뗌) · cfg.rates/fixed/scheme 등 옛 칸이 있으면 그 값이 앞섬
* 정답 대조: resources/tester/test_stmate_kanjub_stc.py · test_stmate_kanjub_opts.py
*/
const StmateKanjubFactory = (h) => {
const { num, roundDown, roundUp, roundHalfUp, roundBanker } = h;
// 설정 읽개·항목 표·결과 묶음 — kanjub_parts.js
const P = (globalThis.STMATE_KANJUB_PARTS || require("./kanjub_parts.js"))(h);
const { keyOf, LABEL, S8, reader, addList, finish } = P;
function calcKanjub(data, boqRes, origKanjubRes = null, stageCfg = null) {
const cfg = stageCfg || (data && data.kanjubConfig) || {};
const o = reader(cfg, data),
slot = num(cfg.slot, 1),
adds = addList(cfg, slot);
const addSum = (g, vatOnly = false) =>
adds
.filter((a) => a.stage === g && !(g === 1 && a.addt) && (!vatOnly || a.vat))
.reduce((s, a) => s + num(a.amount), 0);
const B = {
M: num(boqRes.directM),
L: num(boqRes.directL),
S: num(boqRes.directS),
govAll: num(boqRes.govCombinedRaw),
govFee: num(boqRes.govFeeTotal),
};
const run1 = (m, up) => runOnce(o, cfg, B, origKanjubRes, adds, addSum, m, up);
let r = run1(o.k("C_IYUN_M"), o.k("B_BUGA_UP") ? 1 : 0);
// 총액 절사(I_TOT_JEOL) — 총공사비를 자리 절사한 목표에 맞도록 이윤보정액(C_IYUN_M)을 1원씩 조정 · 못 맞추면 부가세 +1(B_BUGA_UP)
const tj = o.k("I_TOT_JEOL");
if (tj > 0 && !o.k("I_JEOLSA")) {
let up = o.k("B_BUGA_UP") ? 1 : 0;
const first = run1(0, up),
target = roundDown(first.grand, -tj),
diff = first.grand - target;
const m0 = o.k("I_BUGA") === 0 ? roundHalfUp(diff / 1.1, 0) : diff;
let m = m0,
seen = new Set();
r = run1(m, up);
for (let i = 0; i < 60 && r.grand !== target; i++) {
seen.add(m);
m += r.grand > target ? 1 : -1;
if (seen.has(m)) {
if (up) break;
((up = 1), (m = m0), (seen = new Set()));
}
r = run1(m, up);
}
Object.assign(r, { target, diffTotal: diff, bugaUp: up });
}
return finish(o, cfg, r, origKanjubRes);
}
// 한 번 계산(이윤보정액 m · 부가세 +1 up 고정)
function runOnce(o, cfg, B, prev, adds, addSum, iyunM, bugaUp) {
const J = o.k("I_KAN_JEOLSA"),
tr = (v) => roundDown(v, -J),
ctx = o.ctx,
actl = o.actl;
const std = ctx === 0 || ctx === 1 || ctx === 2 || ctx === 5,
su = ctx === 3 || ctx === 4;
const rows = {},
keysOut = {};
// 항목 한 줄 — 후보(cand) · D_ 고정 · 옛 변경 계산방식(revModes)
const put = (code, base, rate, cand, desc, tpl, group) => {
const fx = o.fix(code);
let amount = fx != null ? fx : cand;
const mode = o.revModes[code];
const pr = prev && prev.itemMap && prev.itemMap[code];
if (fx == null && pr && mode && mode !== "recalculated") {
const ob = num(pr.baseAmt);
amount =
mode === "carry_original"
? pr.amount
: mode === "proportional"
? pr.amount + tr(pr.amount * (ob > 0 ? (base - ob) / ob : 0))
: mode === "delta_rate"
? pr.amount + tr(((base - ob) * rate) / 100)
: amount;
}
const row = { key: code, code, label: LABEL[code] || code, group: group || "exp" };
Object.assign(row, {
formula: desc,
baseDesc: desc,
baseAmt: base,
base,
rate,
ratePct: rate,
});
Object.assign(row, { cand, amount, fixed: fx != null, tpl: tpl || "" });
if (pr) Object.assign(row, { origAmt: pr.amount, deltaAmt: amount - pr.amount });
row.modeUsed = prev ? mode || "recalculated" : "원설계";
rows[code] = row;
keysOut["C_" + keyOf(code)] = amount;
keysOut["S_" + keyOf(code)] = cand;
return amount;
};
// 율 항목 — 후보 = ROUNDDOWN(밑수×율/100, −간접비 절사자리) · 식 템플릿과 그 변수(25번 §2.1)를 함께 남김
const pctItem = (code, base, desc, tplBase, vars) => {
const r = o.R(code),
amt = put(
code,
base,
r,
tr((base * r) / 100),
desc,
`ROUNDDOWN(${tplBase}*[RAT_1]/100,-[J])`,
);
rows[code].tplVars = Object.assign({ RAT_1: r, J }, vars);
return amt;
};
// 0) 직접비 틀 — 노무비 가산(DOSEOH) · 사급 위치(I_POS_SA=3 재료비 포함) · 실적 대체(CAL_ACTL)
let M = B.M,
L = B.L,
S = B.S;
if (o.R("DOSEOH")) L += pctItem("DOSEOH", L, "직접노무비", "[LAMT]", { LAMT: L });
const posSa = o.k("I_POS_SA"),
sagup = o.k("C_SAGUP");
let Kres = sagup;
if (posSa === 3) ((M += sagup), (Kres = 0));
let T = M + L + S,
c98 = null;
if (actl) {
const DM = o.R("R_DM"),
DL = o.R("R_DL");
if (o.k("I_MTYP") === 1) S = T - L - M;
else if (o.k("I_LTYP")) {
M = roundDown(T * DM, 0);
if (M + L > T) M = T - L;
S = T - M - L;
} else {
M = roundDown(T * DM, 0);
L = roundDown(T * DL, 0);
S = (1 - DM - DL) * T;
L = T * o.R("R_L");
c98 = T * o.R("R_DML");
}
}
const c90 = L + M,
hol = o.k("C_EIS_HOLLAB"),
U = std ? o.k("C_NBUGAM") : 0;
let expAcc = actl ? 0 : S,
Lp = L;
// 1) 간접노무비 — 일반은 노무비, 실적은 간접공사비(I_LTYP≠0 이면 노무비 밑수에도)
const kanno = pctItem("KANNO", L, "직접노무비", "[LAMT]", { LAMT: L });
if (!actl) Lp += kanno;
else ((expAcc += kanno), o.k("I_LTYP") && (Lp += kanno));
if (su) expAcc += put("S_PUMJIL", 0, 0, o.k("C_S_PUMJIL"), "별도내역");
// 2) 산재·고용 = (노무비 + 고용개선 주휴노무비) × 율
expAcc += pctItem("SANBO", Lp + hol, "직접노무비+간접노무비", "([L_AMT][+LAB])", {
L_AMT: Lp,
LAB: hol,
});
expAcc += pctItem("KOBO", Lp + hol, "직접노무비+간접노무비", "([L_AMT][+LAB])", {
L_AMT: Lp,
LAB: hol,
});
// 3) 건강·연금·장기요양·퇴직공제 — 변경 차수 당초액 + 증감(I_BF_CH_BO) · 직접입력 유지(I_COST_BO) · REA 18
const lab = L + hol,
bfch = o.k("I_BF_CH_BO"),
costBo = o.k("I_COST_BO");
const chg = prev && (o.pclass < 0 || o.pclass === 7) && (bfch === 1 || bfch === 2);
const prevBase = prev ? num(prev.dL) + num(prev.hollab) : 0;
const prevAmt = (c) => (prev && prev.itemMap[c] ? num(prev.itemMap[c].amount) : 0);
const hp = (code, sel) => {
const base = o.k(sel) ? o.k("C_SANGSI") : lab,
r = o.R(code);
if (costBo === 1 || costBo === 2) return put(code, base, r, o.k("C_" + code), "직접입력");
if (chg) {
const old = prevAmt(code),
d =
bfch === 2 && prevBase >= 1
? ((lab - prevBase) * old) / prevBase
: ((lab - prevBase) * r) / 100;
return put(code, base, r, old + tr(d), "당초액 + 직노증감", "[C_AMT_B]+ROUNDDOWN(...)");
}
return pctItem(code, base, o.k(sel) ? "상시근로자노무비" : "직접노무비", "[LAMT]", {
LAMT: base,
});
};
const kunbo = hp("KUNBO", "I_KUNBO");
expAcc += kunbo;
const oldKun = prevAmt("KUNBO");
expAcc +=
chg && bfch === 2 && oldKun >= 1
? put(
"SLVBO",
kunbo,
o.R("SLVBO"),
prevAmt("SLVBO") + tr(((kunbo - oldKun) * prevAmt("SLVBO")) / oldKun),
"당초액 + 증감(비율)",
)
: pctItem("SLVBO", kunbo, "건강보험료", "[C_KUNBO]", { C_KUNBO: kunbo });
expAcc += hp("YUNBO", "I_YUNBO");
expAcc +=
costBo === 2
? put("TBUGUM", lab, o.R("TBUGUM"), o.k("C_TBUGUM"), "직접입력")
: prev && bfch === 2 && prevBase >= 1
? put(
"TBUGUM",
lab,
o.R("TBUGUM"),
prevAmt("TBUGUM") + tr(((lab - prevBase) * prevAmt("TBUGUM")) / prevBase),
"당초액 + 증감(비율)",
)
: pctItem("TBUGUM", lab, "직접노무비", "[LAMT]", { LAMT: lab });
// 4) 산업안전보건관리비 — 관급 대상액(C_KN_SA 8갈래) · 후보 3개 · 1.2배 비교 · 변경 비율(I_ANJUNAUTO=2) · REA 18
const gD = o.k("B_KWANGUP_D") ? B.govAll : o.k("C_KWANGUP_D"),
gK = o.k("C_KWANGUP_K");
let jodal = o.k("B_T_JODAL") ? B.govFee : o.k("C_T_JODAL");
if (jodal > gD) jodal = gD;
const gAll = gD + gK,
gA = gAll - gK - jodal,
knT = o.k("I_KN_SA_TYPE");
const kDiv = posSa === 1 ? Kres : Kres / 1.1;
const knSa =
[gA / 1.1, gA, kDiv, Kres, gA / 1.1 + Kres, gA + kDiv, gA / 1.1 + kDiv, gA + Kres][knT] ?? 0;
const busan = actl ? 0 : o.k("C_BUSAN"),
a0 = roundDown(T * o.R("R_MxA"), 0);
const b0 =
o.k("I_MTYP") === 1
? actl
? T
: c90 + busan
: actl && o.k("I_LTYP") === 1 && ((c90 > a0 && o.k("I_MXA") === 0) || o.k("I_MXA") === 1)
? a0
: c90 + busan;
const Dn = std ? o.k("C_T_ANJUN_N") : 0,
selK = [2, 5, 6].includes(knT) ? kDiv : Kres;
let c190 = ((b0 + U - Dn) * o.R("ANJUN1")) / 100 + o.G("C_ANJUN1_G"),
c198 = ((b0 + U + knSa - Dn) * o.R("ANJUN2")) / 100 + o.G("C_ANJUN2_G"),
c1a0 = ((b0 + U + selK - Dn) * o.R("ANJUN")) / 100 + o.k("C_ANJUN_G");
if (ctx !== 4 && o.k("I_AN_DN_TYPE") !== 1)
[c190, c198, c1a0] = [c190, c198, c1a0].map((v) => roundDown(v, 0));
const ak = o.k("I_ANJUN_K"),
auto = o.k("I_ANJUNAUTO");
const l18 = ak === 1 ? c198 : ak === 2 ? c1a0 : c190;
let l10 = c190,
cap = o.k("I_ANJUN_B") === 1,
capAuto = false;
if (auto === 0 && (ak === 1 || ak === 2)) l10 = ak === 1 ? c198 : c1a0;
else if (cfg.anjunCap12 !== false && l10 !== 0 && 1.2 * l10 < l18) cap = capAuto = true;
const anjBasis = b0 + U + knSa - Dn;
let anjCand = cap ? tr(1.2 * l10) : tr(l18),
anjDesc = cap
? "(직노+직재+간재)×율 + 기초액의 1.2배"
: "(직노+직재+간재+관급재/1.1)×율 + 기초액";
if (prev && auto === 2 && (o.pclass < 0 || o.pclass === 7) && num(prev.anjunBaseRaw) >= 1) {
const pa = prevAmt("ANJUN"),
pb = num(prev.anjunBaseRaw);
anjCand = pa + tr(((anjBasis - pb) * pa) / pb);
anjDesc = "당초금액 + 안전관리비 증감액";
}
expAcc += put("ANJUN", roundHalfUp(anjBasis, 0), o.R("ANJUN"), anjCand, anjDesc);
if (su) expAcc += put("S_ANJUN_B", 0, 0, o.k("C_S_ANJUN_B"), "별도내역");
const anjB = o.k("C_ANJUN_B"),
pumB = o.k("C_PUMJIL_B");
expAcc += put("ANJUN_B", 0, 0, anjB, "별도내역") + put("PUMJIL_B", 0, 0, pumB, "별도내역");
// 5) 기타경비(일반) · 수공 세부경비 8 — 공통 밑수(재료비+노무비 · 실적은 직접공사비 또는 조정계수)
const b98 = actl && !o.k("I_LTYP") && c98 != null ? c98 : c90 + kanno;
const a8 = roundDown(o.R("R_MxK") * T, 0),
gL = actl && o.k("I_LTYP") === 1;
const bKita =
o.k("I_MTYP") === 1
? actl
? T
: b98
: gL && ((b98 > a8 && o.k("I_MXK") === 0) || o.k("I_MXK") === 1)
? a8
: b98;
const kitaDesc = actl && o.k("I_MTYP") === 1 ? "직접공사비" : "직접노무비+간접노무비+재료비";
if (std)
expAcc += pctItem("KITA", bKita + U + hol, kitaDesc, "([M_AMT]+[L_AMT][+LAB])", {
M_AMT: bKita + U,
L_AMT: 0,
LAB: hol,
});
if (su)
for (const c of S8)
expAcc += pctItem(c, bKita, kitaDesc, "([L_AMT]+[M_AMT])", { L_AMT: bKita, M_AMT: 0 });
// 6) 공사이행보증 · 하도급 · 환경 · 건설기계 — 밑수 직접공사비(+안전품질 별도·비과세)
const F = o.k("I_ANPUM") === 1 ? anjB + pumB : 0,
tBase = T + F + U;
const ks = tr(
(o.k("C_KONGSU_A") + ((T + F + U - o.k("C_KONGSU_MA")) * o.R("KONGSU")) / 100) *
o.k("Y_KONGSU"),
);
expAcc += put("KONGSU", T, o.R("KONGSU"), ks, "[기초금액+(직접공사비-기준금액)×율]×공기");
const t3 = "재료비 + 직접노무비 + 산출경비";
expAcc += pctItem("HADOSU", tBase, t3, "[T_AMT]", { T_AMT: tBase });
expAcc += pctItem("HWAN", tBase, t3, "[T_AMT]", { T_AMT: tBase });
expAcc += pctItem("EQIP", tBase, t3, "[T_AMT]", { T_AMT: tBase });
expAcc += pctItem("BUDM_SM", Lp + hol, "노무비", "[LAMT]", { LAMT: Lp + hol });
expAcc += pctItem("BUDM_IC", Lp + hol, "노무비", "[LAMT]", { LAMT: Lp + hol });
// 고용개선지원비(서울 5형식) — 주휴수당·사회보험·장려금 각 절사 후 합 · 이윤 뒤 가산 · REA 20
let eisAdd = 0;
if (ctx === 5) {
const i1 = o.R("EIS_HOLIR1"),
i2 = o.R("EIS_HOLIR2");
const hpay = roundDown(((((L * i1) / 100) * i2) / 100) * 1.4, 0);
const keep = (c) => num(o.keys["D_" + c]) === 1;
const soc = keep("EIS_SOCINS")
? o.k("C_EIS_SOCINS")
: roundDown(((L * (o.R("KUNBO") + o.R("YUNBO"))) / 100) * (o.R("EIS_SOCIR2") / 100), 0);
const inc = keep("EIS_INCENT")
? o.k("C_EIS_INCENT")
: roundDown(((((L * i1) / 100) * i2) / 100) * (o.R("EIS_INCENT") / 100), 0);
keysOut.C_EIS_HOLPAY = hpay;
const sup = put(
"EIS_SUPPAY",
L,
0,
tr(hpay + soc + inc),
"주휴수당+사회보험+장려금",
"",
"post",
);
eisAdd = sup + (keep("EIS_SOCINS") ? put("EIS_SOCINS", L, 0, soc, "", "", "post") : 0);
eisAdd += keep("EIS_INCENT") ? put("EIS_INCENT", L, 0, inc, "", "", "post") : 0;
Lp += hol;
}
// 순공사원가(헬퍼 합) — 일반 = 재료비 + 노무비(직+간) + 경비 · 실적 = 직접공사비 + 간접공사비
const add1 = addSum(1);
expAcc += add1;
const total30 = actl ? T + expAcc : M + Lp + expAcc;
const anjunp = put(
"ANJUNP",
total30 + knSa,
o.R("ANJUNP"),
tr(((total30 + knSa) * o.R("ANJUNP")) / 100),
"(순공사원가+관급)×율",
"",
"post",
);
// 7) 일반관리비 — 일반 계열은 비과세자재·관리품목자재 포함
const ilbanBase = std ? total30 + o.k("C_NBUGAM") + o.k("C_T_K_MAT") : total30;
const ilban = put(
"ILBAN",
ilbanBase,
o.R("ILBAN"),
tr((ilbanBase * o.R("ILBAN")) / 100),
"순공사원가",
"",
"ilban",
);
const A = total30 + ilban;
// 8) 이윤 — 일반 (계−재료비)×율 · 실적 계×율 · 원 단위 절사 · 이윤보정액 차감 · 공급가액 절사(I_JEOLSA)
const rIyun = o.R("IYUN"),
P = actl ? roundDown((A * rIyun) / 100, 0) : roundDown(((A - M) * rIyun) / 100, 0);
const fixedAdds =
anjunp +
put("PSAMT_B", 0, 0, o.k("C_PSAMT_B"), "별도", "", "post") +
put("EXCEPT_B", 0, 0, o.k("C_EXCEPT_B"), "별도", "", "post") +
(std && posSa === 1 ? Kres : 0) +
eisAdd +
addSum(2);
const k4 = (o.R("S_SIGONG") / 100) * o.R("S_SIGONG_1"),
jeol = o.k("I_JEOLSA");
const sig = (x) =>
ctx === 4 ? (o.fix("S_SIGONG") ?? roundDown((A + P - x + Kres) * k4, 0)) : 0;
let mAdj = iyunM,
sigong = 0,
RT;
if (!jeol) {
sigong = ctx === 4 ? (o.fix("S_SIGONG") ?? roundDown((A + (P - mAdj) + Kres) * k4, 0)) : 0;
RT = A + (P - mAdj) + fixedAdds + sigong;
} else {
const s0 = sig(0),
gross = A + P + fixedAdds + s0,
target = roundDown(gross, -jeol),
delta = gross - target;
if (ctx !== 4) ((mAdj = delta), (sigong = s0));
else {
let x = roundBanker(delta / (1 + k4) + 0.5, 0);
if (x + s0 - sig(x) !== delta) x = roundDown(delta / (1 + k4), 0);
sigong = x + s0 - sig(x) === delta ? sig(x) : s0 - (delta - x);
mAdj = x;
}
RT = A + (P - mAdj) + fixedAdds + sigong;
}
if (ctx === 4)
put(
"S_SIGONG",
A + P + Kres,
o.R("S_SIGONG"),
sigong,
"(순공사원가+일반관리비+이윤+사급비)×율×계수",
"",
"post",
);
const iyunFinal = P - mAdj,
supply308 = RT;
keysOut.C_IYUN_M = mAdj;
// 9) 공사손해보험 — 대상액 C_KONGSA_J 8갈래(B_KONGSA=1 이면 저장값) · 공급가액 절사 자리
const G23 = posSa === 2 || posSa === 3 ? 1 : 0;
const kjCase = [
gA / 1.1 + supply308,
gA + supply308,
supply308 + (G23 * Kres) / 1.1,
supply308 + G23 * Kres,
gA / 1.1 + supply308 + G23 * Kres,
gA + supply308 + (G23 * Kres) / 1.1,
gA / 1.1 + supply308 + (G23 * Kres) / 1.1,
gA + supply308 + G23 * Kres,
];
const kongsaJ = o.k("B_KONGSA")
? o.k("C_KONGSA_J")
: knT > 7
? supply308
: roundDown(kjCase[knT], 0);
keysOut.C_KONGSA_J = kongsaJ;
keysOut.C_KN_SA = knSa;
RT += put(
"KONGSA",
kongsaJ,
o.R("KONGSA"),
roundDown((kongsaJ * o.R("KONGSA")) / 100, -jeol),
"공사손해보험 대상액",
"",
"post",
);
RT -= put("BUSAN_B", 0, 0, o.k("C_BUSAN_B"), "작업설 등", "", "post");
// 10) 부가세(I_BUGA · REA 20) — 0 공급가액 · 1 재료비 · 2 없음 · 3 산림조합(직접비−노무비+안전품질+과세 추가) · 4 3에서 면세품 뺌
const buga = o.k("I_BUGA"),
up = bugaUp ? 1 : 0,
E = addSum(2, true);
const forest = T - L + F + E - (buga === 4 ? o.k("C_BUGA_M") : 0);
const vat =
buga === 0
? roundDown(0.1 * RT, 0) + up
: buga === 1
? roundDown(0.1 * M, 0) + up
: buga === 3 || buga === 4
? roundDown(forest * 0.1, 0) + up
: 0;
const supplyFinal = RT;
RT += vat;
// 11) 세후 가산 · 도급 절사 · 관급(도급자설치·관급자설치 따로 자리·절상/반올림/절사) · 사급 · 추가4
RT += put("PURCHAS", 0, 0, o.k("C_PURCHAS"), "", "", "post");
if (std)
for (const c of ["T_PEGI", "T_KOLJAE", "NBUGAM"])
RT += put(c, 0, 0, o.k("C_" + c), "", "", "post");
if (std && posSa === 2) RT += Kres;
const add3 = addSum(3);
RT += add3;
const contractRaw = RT;
if (o.k("I_DOG_JEOL") > 0) RT = roundDown(RT, -o.k("I_DOG_JEOL"));
const contractFinal = RT;
const rnd = (v, digits, updn) =>
updn === 1
? roundBanker(v, -digits)
: updn === 2
? roundDown(v, -digits)
: roundUp(v, -digits);
const comb = o.k("I_KWN_COMB");
const govFinal = rnd(comb === 0 ? gD : gAll, o.k("I_KWN_JEOLSA"), o.k("I_KWN_UPDN"));
const govK = comb === 0 ? rnd(gK, o.k("I_KWN_K_JEOLSA"), o.k("I_KWN_K_UPDN")) : 0;
RT += govFinal + govK;
Object.assign(keysOut, { C_UPDNKWN: govFinal, C_KWANGUP: gAll, C_KWANGUP_D: gD });
Object.assign(keysOut, { C_KWANGUP_K: gK, C_T_JODAL: jodal });
for (const c of [
"DOSEOH",
"S_SIGONG",
"EIS_SUPPAY",
"EIS_SOCINS",
"EIS_INCENT",
"EIS_HOLPAY",
...S8,
])
if (keysOut["C_" + c] == null) keysOut["C_" + c] = o.fix(c) ?? 0;
const sagAfter = std && (posSa === 1 || posSa === 2) ? 0 : Kres;
RT += sagAfter;
RT += addSum(4);
const anjunCase = { c190, c198, c1a0, l10, l18, cap, capAuto, b0, U, Dn, knSa };
return Object.assign(
{ rows, keysOut, M, L, S, T, Lp, hol, kanno, expAcc, add1, total30, ilbanBase, ilban, A, P },
{ mAdj, iyunFinal, fixedAdds, sigong, supply308, kongsaJ, supplyFinal, vat, contractRaw },
{ contractFinal, govFinal, govK, sagAfter, gD, gK, jodal, knSa, anjBasis, anjunCase },
{ grand: RT, add3, rIyun, ctx, actl, adds },
);
}
Object.assign(calcKanjub, { evalTpl: P.evalTpl, LABEL: P.LABEL, ORD_CODE: P.ORD_CODE });
Object.assign(calcKanjub, { KAN_ORD: P.KAN_ORD, keyOf, codeOf: P.codeOf });
return calcKanjub;
};
if (typeof window !== "undefined") window.STMATE_KANJUB_FACTORY = StmateKanjubFactory;
if (typeof module !== "undefined" && module.exports) module.exports = StmateKanjubFactory;