/* -*- coding: utf-8 -*- */ /** * 자재 후보단가 채택 (scr_edit_price.js) — 가격지 1~5단가(AMT_1n~AMT_5n) 중 최소단가 자동채택 · 지정 단가 · * 보호표시(UC=T) 수동 고정 우선 · 0원 후보 제외 * 근거: 지식DB STmate/old/20_분석 17 §5.5(최저가 채택) · 22 §3.1(보호표시·0원 수정 안 됨) · * ui_form_catalog wM_Boxa RG_MComp(변동없음 · 1~5 단가 · 최소단가) · 13 T10(수동값 우선) */ (function (global) { "use strict"; const num = (v) => Number(v) || 0; /** * rows = COSTN 행 · opts { slot: 차수 1~4, mode: "min" | 1~5 | "keep", kinds: "M" } * 돌려줌 { changed: [{code, from, to, src}], kept: [보호표시 코드] } · rows 는 그대로(적용은 부르는 쪽) */ function adoptCandidates(rows, opts = {}) { const slot = Number(opts.slot) || 1, mode = opts.mode ?? "min", kinds = opts.kinds || "M"; const changed = [], kept = []; if (mode === "keep") return { changed, kept }; for (const r of rows || []) { const code = String(r.CODE || "").trim(); if (!code || !kinds.includes(code[0])) continue; const cand = [1, 2, 3, 4, 5].map((i) => num(r[`AMT_${i}${slot}`])); let to = null, src = 0; if (mode === "min") { cand.forEach((v, i) => v > 0 && (to === null || v < to) && ((to = v), (src = i + 1))); } else if (cand[Number(mode) - 1] > 0) [to, src] = [cand[Number(mode) - 1], Number(mode)]; if (to === null) continue; if (String(r.UC || "").trim() === "T") { kept.push(code); continue; } const from = num(r[`MAMT${slot}`]); if (from !== to) changed.push({ code, from, to, src }); } return { changed, kept }; } const api = { adoptCandidates }; global.STMATE_PRICE_ADOPT = api; if (typeof module !== "undefined" && module.exports) module.exports = api; // 화면 — 단가표 메뉴에 「자재 후보단가 채택」 창 if (typeof document === "undefined") return; const P = (global.STMATE_PLUGINS = global.STMATE_PLUGINS || { screens: {}, actions: {}, menus: [], }); P.actions.Act_Qty_AdoptPrice = (ctx, app) => { if (!ctx.dbfData) return alert("먼저 프로젝트를 여세요."); const opts = [ "min:최소단가(0원 제외)", "1:1 단가", "2:2 단가", "3:3 단가", "4:4 단가", "5:5 단가", "keep:변동없음", ]; app.openModal( "자재 후보단가 채택 (wM_Boxa RG_MComp)", `

가격지 1~5단가 중 고른 단가를 재료비 적용단가로 · 보호표시(UC=T) 자재는 수동값 그대로 · 0원 후보는 제외

`, ); const $ = (id) => document.getElementById(id); const run = () => adoptCandidates(ctx.dbfData.costn_rows, { mode: $("adopt-mode").value, slot: $("adopt-slot").value, }); $("adopt-run-preview").onclick = () => { const res = run(); $("adopt-preview").innerHTML = `
바뀔 자재 ${res.changed.length}건 · 보호표시로 그대로 ${res.kept.length}건
` + res.changed .map((c) => `
${c.code}: ${app.fmt(c.from)} → ${app.fmt(c.to)} (${c.src}단가)
`) .join(""); }; $("adopt-run-apply").onclick = () => { const res = run(); const slot = Number($("adopt-slot").value) || 1; const by = Object.fromEntries(ctx.dbfData.costn_rows.map((r) => [String(r.CODE).trim(), r])); const sync = global.STMATE_VIEW_PRJ_BOQ && global.STMATE_VIEW_PRJ_BOQ.syncCostnUnitPrice; for (const c of res.changed) { const r = by[c.code]; if (slot === 1 && sync) sync(ctx, c.code, c.to, num(r.LAMT1), num(r.SAMT1)); else Object.assign(r, { [`MAMT${slot}`]: String(c.to), [`TAMT${slot}`]: String(c.to + num(r[`LAMT${slot}`]) + num(r[`SAMT${slot}`])), }); } app.closeModal(); app.cascadeAndRender(); alert(`자재 ${res.changed.length}건 채택 · 보호표시 ${res.kept.length}건 그대로`); }; }; if (!P.menus.some((m) => m.act === "Act_Qty_AdoptPrice")) P.menus.push({ menu: "m2", label: "자재 후보단가 채택(최소단가)", act: "Act_Qty_AdoptPrice" }); })(typeof window !== "undefined" ? window : globalThis);