auto: 2026-11-13 19:28 (EOMSANGDON-HOME)
This commit is contained in:
@@ -0,0 +1,20 @@
|
||||
// STMATE 재현 앱 구성 조립 설정 — stdin {cases:[{rows, table, ini, code, sys}]} → 각 결과(M·L·S)와 설정
|
||||
globalThis.window = globalThis;
|
||||
require("../../tools/stmate-test/calc.js");
|
||||
require("../../tools/stmate-test/smt_eval.js");
|
||||
require("../../tools/stmate-test/smt_engine.js");
|
||||
let buf = "";
|
||||
process.stdin.setEncoding("utf8");
|
||||
process.stdin.on("data", (d) => (buf += d));
|
||||
process.stdin.on("end", () => {
|
||||
const { cases } = JSON.parse(buf);
|
||||
const out = cases.map((c) => {
|
||||
const ctx = { dbfData: { start_ini: c.ini || {}, costn_rows: [] }, state: { sysConfig: c.sys || {} } };
|
||||
const opts = window.STMATE_ENGINE.compositionOptions(ctx, c.code || "X00001", c.row || {});
|
||||
const lookup = (code) => c.table[code] || null;
|
||||
const ev = window.STMATE_SMT_EVAL.evaluateComposition(c.rows, lookup, opts);
|
||||
const smt = window.STMATE_ENGINE.smtOptions(ctx, "D00001");
|
||||
return { M: ev.M, L: ev.L, S: ev.S, opts: { ...opts, labor: null }, smtLine: smt.lineDigits };
|
||||
});
|
||||
process.stdout.write(JSON.stringify(out));
|
||||
});
|
||||
@@ -0,0 +1,11 @@
|
||||
// STMATE 재현 앱 계산 도구(수량 계산기 · 실적→일식 비목율) — stdin [{fn, args}] → 결과 배열
|
||||
const X = require("../../tools/stmate-test/calc_xrate.js");
|
||||
const A = require("../../tools/stmate-test/calc_a2w.js");
|
||||
let buf = "";
|
||||
process.stdin.setEncoding("utf8");
|
||||
process.stdin.on("data", (d) => (buf += d));
|
||||
process.stdin.on("end", () => {
|
||||
const fns = { ...X, ...A };
|
||||
const out = JSON.parse(buf).map(({ fn, args }) => fns[fn](...args));
|
||||
process.stdout.write(JSON.stringify(out));
|
||||
});
|
||||
@@ -0,0 +1,94 @@
|
||||
"""STMATE 재현 앱 구성 조립 설정 — 소수 자리(KCD·BPN·ACD·JCD·ECD) · 외산장비 환율($ 구간·€·¥).
|
||||
|
||||
근거: 22번 §3.4(0·1·2 자리) · REA 14 TWM_SET_SYS 안내문
|
||||
KCD 중기사용료 금액 · BPN 일위대가표 금액 · ACD 단가산출서 금액 · JCD 「X」의 중기노임 단가 · ECD 「X」의 $장비 단가
|
||||
₩/$(10만$이상은 ed_EXH) · ₩/€ · ₩/100¥ · 단가의 조사시점(ARENM) = 환율 칸 1/2.
|
||||
실무 7건 값(KCD·ACD·BPN = 1 · ECD = 0 · JCD 0/1 · EXLNM = EXHNM)은 test_stmate_ilwi_eval 이 1원 대조 · 여기는 손셈.
|
||||
"""
|
||||
|
||||
import json
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
HELPER = Path(__file__).with_name("helper_stmate_smt_opts.cjs")
|
||||
|
||||
|
||||
def run(*cases):
|
||||
out = subprocess.check_output(
|
||||
["node", str(HELPER)],
|
||||
input=json.dumps({"cases": list(cases)}, ensure_ascii=False),
|
||||
text=True,
|
||||
encoding="utf-8",
|
||||
)
|
||||
return json.loads(out)
|
||||
|
||||
|
||||
def comp(rows, table, ini=None, code="X00001", row=None):
|
||||
return {"rows": rows, "table": table, "ini": ini or {}, "code": code, "row": row or {}}
|
||||
|
||||
|
||||
M1 = {"M00001": {"M": 333, "L": 0, "S": 0, "unit": "kg"}}
|
||||
ROWS = [{"CODE": "M00001", "QTY1": 0.33}] # 333 × 0.33 = 109.89
|
||||
|
||||
|
||||
def test_line_digits_by_kind():
|
||||
a, b, c, d = run(
|
||||
comp(ROWS, M1, {"KCDNM": "1"}),
|
||||
comp(ROWS, M1, {"KCDNM": "0"}),
|
||||
comp(ROWS, M1, {"BPNNM": "2"}, code="B00001"),
|
||||
comp(ROWS, M1, {"KCDNM": "0", "BPNNM": "1"}, code="B00001"),
|
||||
)
|
||||
# 줄 금액 109.89 → 1 자리 109.8 · 0 자리 109 · 결과는 원 미만 절사
|
||||
assert a["opts"]["lineDigits"] == 1 and b["opts"]["lineDigits"] == 0
|
||||
assert c["opts"]["lineDigits"] == 2 and d["opts"]["lineDigits"] == 1
|
||||
assert a["M"] == b["M"] == 109
|
||||
|
||||
|
||||
def test_line_digits_change_sum():
|
||||
rows = [{"CODE": "M00001", "QTY1": 0.33}] * 3 # 109.89 × 3
|
||||
one, zero, two = run(
|
||||
comp(rows, M1, {"KCDNM": "1"}), comp(rows, M1, {"KCDNM": "0"}), comp(rows, M1, {"KCDNM": "2"})
|
||||
)
|
||||
assert (one["M"], zero["M"], two["M"]) == (329, 327, 329) # 329.4 · 327 · 329.67
|
||||
|
||||
|
||||
def test_acd_digits_for_smt():
|
||||
a, b = run(comp([], {}, {"ACDNM": "0"}), comp([], {}, {}))
|
||||
assert a["smtLine"] == 0 and b["smtLine"] == 1
|
||||
|
||||
|
||||
def test_wage_digits_jcd():
|
||||
table = {"L00001": {"M": 0, "L": 100001, "S": 0, "unit": "인"}}
|
||||
rows = [{"CODE": "L00001", "QTY1": 10}]
|
||||
ini = {"CONLD": "L00001", "RXXNM": "1/8", "KCDNM": "2"}
|
||||
j0, j1 = run(comp(rows, table, {**ini, "JCDNM": "0"}), comp(rows, table, {**ini, "JCDNM": "1"}))
|
||||
# 100001 / 8 = 12500.125 → JCD 0 = 12500 · JCD 1 = 12500.1 → × 10
|
||||
assert j0["L"] == 125000 and j1["L"] == 125001
|
||||
|
||||
|
||||
def test_foreign_units_and_usd_band():
|
||||
table = {
|
||||
"S00001": {"M": 0, "L": 0, "S": 49594, "unit": "$"},
|
||||
"S00002": {"M": 0, "L": 0, "S": 150000, "unit": "$"},
|
||||
"S00003": {"M": 0, "L": 0, "S": 1000, "unit": "€"},
|
||||
"S00004": {"M": 0, "L": 0, "S": 1000, "unit": "¥"},
|
||||
}
|
||||
ini = {"EXLNM1": "1470", "EXHNM1": "1500", "EXEUR1": "1423", "EXYEN1": "915"}
|
||||
ini |= {"EXLNM2": "1000", "EXHNM2": "1000", "EXEUR2": "1000", "EXYEN2": "1000"}
|
||||
one = lambda c: [{"CODE": c, "QTY1": 1}] # noqa: E731
|
||||
r = run(
|
||||
comp(one("S00001"), table, ini),
|
||||
comp(one("S00002"), table, ini),
|
||||
comp(one("S00003"), table, ini),
|
||||
comp(one("S00004"), table, ini),
|
||||
comp(one("S00001"), table, {**ini, "ARENM": "2"}),
|
||||
)
|
||||
# 단가(천원) = 가격 × 환율 ÷ 1000 · 10만$ 이상 = EXHNM · ¥ 는 100¥당
|
||||
assert [x["S"] for x in r] == [72903, 225000, 1423, 9, 49594]
|
||||
|
||||
|
||||
def test_usd_real_case_ulljin():
|
||||
# 울진 X00127 트럭트랙터 — S00346 49594$ × 1470 ÷ 1000 × 0.2529 = 18437(저장 SAMT1)
|
||||
table = {"S00346": {"M": 0, "L": 0, "S": 49594, "unit": "$"}}
|
||||
(r,) = run(comp([{"CODE": "S00346", "QTY1": 0.2529}], table, {"EXLNM1": "1470", "EXHNM1": "1470"}))
|
||||
assert r["S"] == 18437
|
||||
@@ -0,0 +1,66 @@
|
||||
"""STMATE 재현 앱 계산 도구 — 노무·장비 수량 계산기(wM_Edit_XRate) · 실적→일식 비목율(wM_Conv_A2W).
|
||||
|
||||
근거: REA 30 labor_equipment_quantity_rules.json · REA 27 conversion_component_rate_rules.json — 손셈 대조.
|
||||
수량 계산기 반올림(MROUNDUD) 방향은 미확정 — 반올림으로 둔 값은 경계가 아닌 수로만 봄.
|
||||
"""
|
||||
|
||||
import json
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
HELPER = Path(__file__).with_name("helper_stmate_smt_tools.cjs")
|
||||
|
||||
|
||||
def call(*calls):
|
||||
payload = [{"fn": f, "args": list(a)} for f, *a in calls]
|
||||
out = subprocess.check_output(
|
||||
["node", str(HELPER)], input=json.dumps(payload), text=True, encoding="utf-8"
|
||||
)
|
||||
return json.loads(out)
|
||||
|
||||
|
||||
def test_xrate_daily_and_applied_quantity():
|
||||
lab, eq, zero = call(
|
||||
("compute", {"qty1": 120, "cond": "0.9*1.1", "hrat": 80, "lqty": 3, "labor": True, "point": 4}),
|
||||
("compute", {"qty1": 120, "cond": "", "hrat": 100, "lqty": 1, "labor": False, "auto": True}),
|
||||
("compute", {"qty1": 0, "cond": "", "hrat": 100, "lqty": 2, "labor": True, "point": 3}),
|
||||
)
|
||||
# 120 × 0.99 × 80% = 95.04 · 노무 3 × 1 ÷ 95.04 = 0.031565… → 4 자리 0.0316
|
||||
assert lab["qday"] == 95.04 and lab["cqty"] == 0.0316 and abs(lab["cond"] - 0.99) < 1e-12
|
||||
# 장비 1 × 8 ÷ 120 = 0.0666… · 자동 자리 = 「120」 3자리 + 1 = 4 → 0.0667
|
||||
assert eq["point"] == 4 and eq["cqty"] == 0.0667
|
||||
assert zero["qday"] == 0 and zero["cqty"] == 0
|
||||
|
||||
|
||||
def test_xrate_auto_point_and_condition_chars():
|
||||
p1, p2, p3, bad, paren, power = call(
|
||||
("autoPoint", 5.5),
|
||||
("autoPoint", 123456.0),
|
||||
("autoPoint", 1234),
|
||||
("condFactor", "0.9 * a"),
|
||||
("condFactor", "(1+2)"),
|
||||
("condFactor", "2^3/4"),
|
||||
)
|
||||
assert (p1, p2, p3) == (2, 6, 5)
|
||||
assert not bad["ok"] and not paren["ok"] and bad["value"] == 1
|
||||
assert power == {"ok": True, "value": 2}
|
||||
|
||||
|
||||
def test_a2w_editor_row_and_bulk():
|
||||
e1, e2, e3, r1, r2 = call(
|
||||
("normalizeEditor", 70, 50, "L"),
|
||||
("normalizeEditor", 70, 50, "M"),
|
||||
("normalizeEditor", 130, 0, "L"),
|
||||
("normalizeRow", 70, 50, 10),
|
||||
("normalizeRow", 70, 50, 9),
|
||||
)
|
||||
assert e1 == {"L": 70, "M": 30, "E": 0} and e2 == {"L": 50, "M": 50, "E": 0}
|
||||
assert e3 == {"L": 100, "M": 0, "E": 0}
|
||||
assert r1 == {"L": 50, "M": 50, "E": 0} and r2 == {"L": 70, "M": 30, "E": 0}
|
||||
rows = [{"sel": True, "rateL": 0}, {"sel": True, "rateL": 80}, {"sel": False, "L": 5}]
|
||||
plain, indiv = call(
|
||||
("bulkApply", rows, {"L": 40, "M": 30}, {}),
|
||||
("bulkApply", rows, {"L": 40, "M": 30}, {"individual": True}),
|
||||
)
|
||||
assert [(r["L"], r["M"], r["E"]) for r in plain] == [(40, 30, 30), (40, 30, 30), (0, 0, 0)]
|
||||
assert [(r["L"], r["M"], r["E"]) for r in indiv] == [(40, 30, 30), (80, 20, 0), (0, 0, 0)]
|
||||
Reference in New Issue
Block a user