feat(est): exchange annual and draft progress
This commit is contained in:
@@ -35,7 +35,17 @@ const EstExchange = (() => {
|
||||
const name = sheet.getAttribute("name");
|
||||
if (
|
||||
(!EstNative.empty().tables[name] &&
|
||||
!["Quantities", "Schedule", "QDocuments", "QLines", "QItems", "Review"].includes(name)) ||
|
||||
![
|
||||
"Quantities",
|
||||
"Schedule",
|
||||
"QDocuments",
|
||||
"QLines",
|
||||
"QItems",
|
||||
"Review",
|
||||
"Annual",
|
||||
"ProgressDrafts",
|
||||
"ProgressInputs",
|
||||
].includes(name)) ||
|
||||
name.startsWith("Cad")
|
||||
)
|
||||
continue;
|
||||
@@ -196,8 +206,82 @@ const EstExchange = (() => {
|
||||
const next = structuredClone(project);
|
||||
const sheets = quantitySheets(next, tables);
|
||||
if (sheets) next.quantitySheets = sheets;
|
||||
if (Object.hasOwn(tables, "ProgressDrafts") || Object.hasOwn(tables, "ProgressInputs")) {
|
||||
if (!Object.hasOwn(tables, "ProgressDrafts") || !Object.hasOwn(tables, "ProgressInputs"))
|
||||
throw Error("기성 Excel에는 ProgressDrafts와 ProgressInputs 시트가 모두 필요합니다.");
|
||||
const old = next.progress || [],
|
||||
locked = old.filter((round) => round.locked);
|
||||
if (old.slice(0, locked.length).some((round) => !round.locked))
|
||||
throw Error("확정 기성 회차 순서 오류");
|
||||
const previous = new Map(
|
||||
old.filter((round) => !round.locked).map((round) => [round.id, round]),
|
||||
);
|
||||
const ids = new Set(locked.map((round) => round.id)),
|
||||
drafts = new Map();
|
||||
for (const row of tables.ProgressDrafts) {
|
||||
if (typeof row.id !== "string" || !row.id || ids.has(row.id))
|
||||
throw Error("기성 회차 ID가 없거나 중복됩니다.");
|
||||
ids.add(row.id);
|
||||
const round = {
|
||||
...previous.get(row.id),
|
||||
id: row.id,
|
||||
name: row.name ?? "",
|
||||
locked: false,
|
||||
approved: row.approved ?? false,
|
||||
separateComponents: row.separateComponents ?? true,
|
||||
inputs: Object.create(null),
|
||||
};
|
||||
delete round.contract;
|
||||
delete round.result;
|
||||
if (row.amountDigits == null) delete round.amountDigits;
|
||||
else round.amountDigits = row.amountDigits;
|
||||
drafts.set(row.id, round);
|
||||
}
|
||||
const inputFields = [
|
||||
"GumMode",
|
||||
"Gum",
|
||||
"GumNC",
|
||||
"GumGC",
|
||||
"GumJC",
|
||||
"GumSC",
|
||||
"SaMode",
|
||||
"Sa",
|
||||
"SaNC",
|
||||
"SaGC",
|
||||
"SaJC",
|
||||
"SaSC",
|
||||
"QuantityDigits",
|
||||
"AmountDigits",
|
||||
];
|
||||
for (const row of tables.ProgressInputs) {
|
||||
const round = drafts.get(row.RoundId);
|
||||
if (
|
||||
!round ||
|
||||
typeof row.RowKey !== "string" ||
|
||||
!row.RowKey ||
|
||||
Object.hasOwn(round.inputs, row.RowKey)
|
||||
)
|
||||
throw Error("기성 입력의 회차·행 식별자가 없거나 중복됩니다.");
|
||||
const prior = previous.get(row.RoundId)?.inputs?.[row.RowKey] || {};
|
||||
const input = Object.fromEntries(
|
||||
Object.entries(prior).filter(([key]) => !inputFields.includes(key)),
|
||||
);
|
||||
for (const field of inputFields) if (row[field] != null) input[field] = row[field];
|
||||
round.inputs[row.RowKey] = input;
|
||||
}
|
||||
next.progress = [...locked, ...drafts.values()];
|
||||
}
|
||||
for (const [table, rows] of Object.entries(tables)) {
|
||||
if (["QDocuments", "QLines", "QItems"].includes(table)) continue;
|
||||
if (["QDocuments", "QLines", "QItems", "ProgressDrafts", "ProgressInputs"].includes(table))
|
||||
continue;
|
||||
if (table === "Annual") {
|
||||
next.annual = rows.map((row) => {
|
||||
if (typeof row.name !== "string" || typeof row.formula !== "string")
|
||||
throw Error("연차 이름·수식 형식 오류");
|
||||
return { name: row.name, formula: row.formula };
|
||||
});
|
||||
continue;
|
||||
}
|
||||
if (table === "Review") {
|
||||
const edits = {};
|
||||
for (const row of rows) {
|
||||
@@ -300,6 +384,16 @@ const EstExchange = (() => {
|
||||
return merged;
|
||||
});
|
||||
}
|
||||
if (Object.hasOwn(tables, "ProgressDrafts")) {
|
||||
const counts = new Map();
|
||||
next.tables.EstMainDat.forEach((row, index) => {
|
||||
const key = EstBusiness.rowKey(row, index);
|
||||
counts.set(key, (counts.get(key) || 0) + 1);
|
||||
});
|
||||
for (const round of next.progress.filter((item) => !item.locked))
|
||||
for (const key of Object.keys(round.inputs))
|
||||
if (counts.get(key) !== 1) throw Error(`기성 입력 내역이 없거나 중복됩니다: ${key}`);
|
||||
}
|
||||
return EstModel.validate(next);
|
||||
}
|
||||
async function exportExcel() {
|
||||
|
||||
Reference in New Issue
Block a user