feat(est): complete four business workflows
This commit is contained in:
@@ -78,8 +78,24 @@ const EstModel = (() => {
|
||||
"Cost",
|
||||
...Array.from({ length: 6 }, (_, i) => `Cost${i + 1}`),
|
||||
]);
|
||||
for (const key of ["ANU", "AGU", "AJU", "ASU", "EscPlanned", "EscActual", "EscProgress"])
|
||||
for (const key of [
|
||||
"ANU",
|
||||
"AGU",
|
||||
"AJU",
|
||||
"ASU",
|
||||
"EscPlanned",
|
||||
"EscActual",
|
||||
"EscProgress",
|
||||
"EscManualQuantity",
|
||||
"EscConstruction",
|
||||
"EscPS",
|
||||
"EscBefore",
|
||||
])
|
||||
numeric.add(key);
|
||||
for (const prefix of ["Jun", "Gum", "Sa", "Total"])
|
||||
for (const field of ["GN", "TC", "Ratio", "NC", "GC", "JC", "SC"]) numeric.add(prefix + field);
|
||||
for (const field of ["ContractCost", "JunCost", "GumCost", "SaCost", "TotalCost"])
|
||||
numeric.add(field);
|
||||
const definitions = {
|
||||
EstMainDat: [
|
||||
"Level",
|
||||
@@ -282,10 +298,95 @@ const EstModel = (() => {
|
||||
}
|
||||
}
|
||||
project.options ||= {};
|
||||
if (typeof project.options !== "object" || Array.isArray(project.options))
|
||||
throw Error("계산 옵션 형식 오류");
|
||||
const validNumber = (value, label) => {
|
||||
if (
|
||||
typeof value !== "number" ||
|
||||
!Number.isFinite(value) ||
|
||||
Math.abs(value) > Number.MAX_SAFE_INTEGER
|
||||
)
|
||||
throw Error(`수치 필드 오류: ${label}`);
|
||||
};
|
||||
if (project.options.EscDesignTotal != null) {
|
||||
validNumber(project.options.EscDesignTotal, "조사 도급액");
|
||||
if (project.options.EscDesignTotal < 0) throw Error("조사 도급액은 0 이상입니다.");
|
||||
}
|
||||
for (const key of ["quantities", "progress", "annual", "drawings"]) {
|
||||
if (project[key] === undefined) project[key] = [];
|
||||
if (!Array.isArray(project[key])) throw Error(`${key} 형식 오류`);
|
||||
}
|
||||
const ids = new Set();
|
||||
for (const round of project.progress) {
|
||||
if (
|
||||
!round ||
|
||||
typeof round !== "object" ||
|
||||
typeof round.id !== "string" ||
|
||||
!round.id ||
|
||||
ids.has(round.id)
|
||||
)
|
||||
throw Error("기성 회차 ID가 없거나 중복됩니다.");
|
||||
ids.add(round.id);
|
||||
for (const field of ["locked", "approved", "separateComponents"])
|
||||
if (round[field] != null && typeof round[field] !== "boolean")
|
||||
throw Error("기성 옵션 형식 오류");
|
||||
if (round.name != null && typeof round.name !== "string")
|
||||
throw Error("기성 회차 이름 형식 오류");
|
||||
round.inputs ??= {};
|
||||
if (typeof round.inputs !== "object" || Array.isArray(round.inputs))
|
||||
throw Error("기성 입력 형식 오류");
|
||||
round.inputs = Object.assign(Object.create(null), round.inputs);
|
||||
for (const input of Object.values(round.inputs)) {
|
||||
if (!input || typeof input !== "object" || Array.isArray(input))
|
||||
throw Error("기성 입력 행 형식 오류");
|
||||
for (const prefix of ["Gum", "Sa"]) {
|
||||
if (
|
||||
input[prefix + "Mode"] != null &&
|
||||
!["quantity", "amount", "ratio", "components"].includes(input[prefix + "Mode"])
|
||||
)
|
||||
throw Error("기성 입력방법 오류");
|
||||
for (const field of ["", "NC", "GC", "JC", "SC"])
|
||||
if (input[prefix + field] != null)
|
||||
validNumber(input[prefix + field], "기성 " + prefix + field);
|
||||
}
|
||||
for (const field of ["QuantityDigits", "AmountDigits"])
|
||||
if (input[field] != null) {
|
||||
validNumber(input[field], field);
|
||||
if (!Number.isInteger(input[field]) || input[field] < 0 || input[field] > 12)
|
||||
throw Error("기성 자릿수 형식 오류");
|
||||
}
|
||||
}
|
||||
if (
|
||||
round.amountDigits != null &&
|
||||
(!Number.isInteger(round.amountDigits) || round.amountDigits < 0 || round.amountDigits > 4)
|
||||
)
|
||||
throw Error("기성 금액 자릿수는 0~4입니다.");
|
||||
if (round.contract) {
|
||||
validate({
|
||||
schema: "est-web-2",
|
||||
name: "기성 계약",
|
||||
tables: { EstMainDat: round.contract.rows, Wonga: round.contract.wonga },
|
||||
options: round.contract.options,
|
||||
});
|
||||
}
|
||||
if (round.result?.rows)
|
||||
validate({
|
||||
schema: "est-web-2",
|
||||
name: "기성 결과",
|
||||
tables: { EstMainDat: round.result.rows },
|
||||
});
|
||||
if (round.result)
|
||||
for (const field of ["total", "ratio"])
|
||||
if (round.result[field] != null) validNumber(round.result[field], "확정 기성 " + field);
|
||||
}
|
||||
for (const year of project.annual)
|
||||
if (!year || typeof year.name !== "string" || typeof year.formula !== "string")
|
||||
throw Error("연차 이름·수식 형식 오류");
|
||||
if (project.baseline) {
|
||||
if (!project.baseline.tables || !Array.isArray(project.baseline.tables.EstMainDat))
|
||||
throw Error("당초 내역 형식 오류");
|
||||
validate({ schema: "est-web-2", name: "당초", tables: project.baseline.tables });
|
||||
}
|
||||
return project;
|
||||
}
|
||||
function legacy(data) {
|
||||
@@ -416,8 +517,16 @@ const EstModel = (() => {
|
||||
if (rows[at].TitleCode === old) rows[at].TitleCode = code;
|
||||
}
|
||||
}
|
||||
function newRow(table, rows) {
|
||||
const max = Math.max(0, ...rows.map((r) => Number(r.PkID) || 0));
|
||||
function newRow(table, rows, project) {
|
||||
const historical = [rows, project?.baseline?.tables?.[table] || []];
|
||||
if (table === "EstMainDat")
|
||||
for (const round of project?.progress || [])
|
||||
historical.push(round.contract?.rows || [], round.result?.rows || []);
|
||||
const max = historical.reduce(
|
||||
(maximum, list) =>
|
||||
list.reduce((value, row) => Math.max(value, Number(row.PkID) || 0), maximum),
|
||||
0,
|
||||
);
|
||||
const row = {
|
||||
PkID: max + 1,
|
||||
Index: 0,
|
||||
|
||||
Reference in New Issue
Block a user