181 lines
6.0 KiB
TypeScript
181 lines
6.0 KiB
TypeScript
import { B08Api } from "./B08_wf5_Quantity_Api";
|
|
import { el, formData, input, section, select, table } from "./B08_wf5_Quantity_UI_Dom";
|
|
import { TabContext } from "./B08_wf5_Quantity_Types";
|
|
export function renderBasis(ctx: TabContext) {
|
|
const b = ctx.state.data.basis ?? {
|
|
project_id: ctx.state.projectId,
|
|
version: ctx.state.basisVersion,
|
|
base_date: "",
|
|
region: "",
|
|
currency: "KRW",
|
|
status: "DRAFT",
|
|
price_sources: [],
|
|
exchange_rates: [],
|
|
rate_policies: [],
|
|
};
|
|
const root = section("기준정보", "가격 출처·환율·제경비 요율을 버전 단위로 관리합니다.");
|
|
const meta = el("form", "b08-form-grid") as HTMLFormElement;
|
|
meta.append(
|
|
input("base_date", "기준일", "date", b.base_date ?? ""),
|
|
input("region", "적용 지역", "text", b.region ?? ""),
|
|
input("currency", "기준 통화", "text", b.currency ?? "KRW"),
|
|
select("status", "상태", [
|
|
["DRAFT", "작성중"],
|
|
["CONFIRMED", "확정"],
|
|
]),
|
|
);
|
|
(meta.elements.namedItem("status") as HTMLSelectElement).value = b.status;
|
|
const save = el("button", "b08-button b08-button--primary", "기준정보 저장") as HTMLButtonElement;
|
|
save.type = "submit";
|
|
meta.append(save);
|
|
meta.onsubmit = async (e) => {
|
|
e.preventDefault();
|
|
const x = formData(meta);
|
|
await B08Api.saveBasis(ctx.state.projectId, b.version, {
|
|
...b,
|
|
...x,
|
|
project_id: ctx.state.projectId,
|
|
version: b.version,
|
|
});
|
|
ctx.message("기준정보를 저장했습니다.");
|
|
await ctx.refresh();
|
|
};
|
|
root.append(meta);
|
|
root.append(renderSources(ctx, b), renderFx(ctx, b), renderPolicies(ctx, b));
|
|
return root;
|
|
}
|
|
function renderSources(ctx: TabContext, b: any) {
|
|
const box = section("가격 출처", "조달가격·물가정보·견적 등 후보단가의 출처와 우선순위입니다.");
|
|
const f = el("form", "b08-inline-form") as HTMLFormElement;
|
|
f.append(
|
|
input("source_code", "출처 코드"),
|
|
input("source_name", "출처명"),
|
|
input("priority_no", "우선순위", "number", "100"),
|
|
input("publisher", "발행기관"),
|
|
input("reference_date", "기준일", "date"),
|
|
);
|
|
const btn = el("button", "b08-button", "출처 추가") as HTMLButtonElement;
|
|
btn.type = "submit";
|
|
f.append(btn);
|
|
f.onsubmit = async (e) => {
|
|
e.preventDefault();
|
|
const x = formData(f);
|
|
b.price_sources.push({ ...x, priority_no: Number(x.priority_no) });
|
|
await B08Api.saveBasis(ctx.state.projectId, b.version, b);
|
|
await ctx.refresh();
|
|
};
|
|
box.append(
|
|
f,
|
|
table(
|
|
["코드", "출처", "발행기관", "우선순위", "기준일"],
|
|
b.price_sources.map((x: any) => [
|
|
x.source_code,
|
|
x.source_name,
|
|
x.publisher,
|
|
x.priority_no,
|
|
x.reference_date,
|
|
]),
|
|
),
|
|
);
|
|
return box;
|
|
}
|
|
function renderFx(ctx: TabContext, b: any) {
|
|
const box = section("환율", "외화 기초단가를 원화로 변환할 때 적용합니다.");
|
|
const f = el("form", "b08-inline-form") as HTMLFormElement;
|
|
f.append(
|
|
input("currency", "통화", "text"),
|
|
input("rate_to_krw", "원화환율", "number"),
|
|
select("source_id", "환율 출처", [
|
|
["", "직접 입력"],
|
|
...b.price_sources.map((x: any) => [String(x.id), x.source_name]),
|
|
]),
|
|
input("effective_from", "적용 시작일", "date"),
|
|
input("effective_to", "적용 종료일", "date"),
|
|
);
|
|
const btn = el("button", "b08-button", "환율 추가") as HTMLButtonElement;
|
|
btn.type = "submit";
|
|
f.append(btn);
|
|
f.onsubmit = async (e) => {
|
|
e.preventDefault();
|
|
const x = formData(f);
|
|
b.exchange_rates.push({
|
|
...x,
|
|
rate_to_krw: String(x.rate_to_krw),
|
|
source_id: x.source_id === "" ? null : Number(x.source_id),
|
|
effective_to: x.effective_to || null,
|
|
});
|
|
await B08Api.saveBasis(ctx.state.projectId, b.version, b);
|
|
await ctx.refresh();
|
|
};
|
|
box.append(
|
|
f,
|
|
table(
|
|
["통화", "원화환율", "출처", "시작일", "종료일"],
|
|
b.exchange_rates.map((x: any) => [
|
|
x.currency,
|
|
x.rate_to_krw,
|
|
b.price_sources.find((source: any) => source.id === x.source_id)?.source_name,
|
|
x.effective_from,
|
|
x.effective_to,
|
|
]),
|
|
),
|
|
);
|
|
return box;
|
|
}
|
|
function renderPolicies(ctx: TabContext, b: any) {
|
|
const box = section("요율 규칙", "승인된 규칙만 최종공사비 계산에 사용됩니다.");
|
|
const f = el("form", "b08-inline-form b08-policy-form") as HTMLFormElement;
|
|
f.append(
|
|
input("rule_code", "규칙 코드"),
|
|
input("rule_name", "규칙명"),
|
|
input("base_expression", "기준식"),
|
|
input("rate_value", "요율", "number"),
|
|
input("minimum_amount", "최소금액", "number"),
|
|
input("maximum_amount", "최대금액", "number"),
|
|
select("rounding_mode", "처리", [
|
|
["FLOOR", "절사"],
|
|
["ROUND", "반올림"],
|
|
["CEILING", "올림"],
|
|
]),
|
|
input("rounding_unit", "단위", "number", "1"),
|
|
input("source_reference", "근거 문서"),
|
|
select("status", "상태", [
|
|
["DRAFT", "작성중"],
|
|
["APPROVED", "승인"],
|
|
]),
|
|
);
|
|
const btn = el("button", "b08-button", "요율 추가") as HTMLButtonElement;
|
|
btn.type = "submit";
|
|
f.append(btn);
|
|
f.onsubmit = async (e) => {
|
|
e.preventDefault();
|
|
const x = formData(f);
|
|
b.rate_policies.push({
|
|
...x,
|
|
rate_value: x.rate_value || null,
|
|
rounding_unit: Number(x.rounding_unit),
|
|
minimum_amount: x.minimum_amount === "" ? null : Number(x.minimum_amount),
|
|
maximum_amount: x.maximum_amount === "" ? null : Number(x.maximum_amount),
|
|
condition_json: {},
|
|
sort_order: b.rate_policies.length,
|
|
});
|
|
await B08Api.saveBasis(ctx.state.projectId, b.version, b);
|
|
await ctx.refresh();
|
|
};
|
|
box.append(
|
|
f,
|
|
table(
|
|
["코드", "규칙", "기준식", "요율", "처리", "상태"],
|
|
b.rate_policies.map((x: any) => [
|
|
x.rule_code,
|
|
x.rule_name,
|
|
x.base_expression,
|
|
x.rate_value,
|
|
x.rounding_mode,
|
|
x.status,
|
|
]),
|
|
),
|
|
);
|
|
return box;
|
|
}
|