feat(est): reproduce native tables and calculations
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
// REA f18804 → f16638 / f15868 / f15f40 / f16320 → f16ec8.
|
||||
const EstMachine = (() => {
|
||||
const { num, components, fixed, floating, even, sum } = EstMath;
|
||||
const fuels = new Set([
|
||||
"주연료",
|
||||
"선박용경유",
|
||||
"전력",
|
||||
"경유",
|
||||
"휘발유",
|
||||
"중유",
|
||||
"전",
|
||||
"가스",
|
||||
"가솔린",
|
||||
"디젤",
|
||||
"diesel",
|
||||
"gasoline",
|
||||
"heavyoil",
|
||||
"lpg",
|
||||
"l.p.g",
|
||||
]);
|
||||
function calculate(rows, criteria, options = {}) {
|
||||
const settings = new Map(criteria.map((row) => [num(row.Index), num(row.TC)]));
|
||||
const get = (index) => settings.get(index) ?? 0;
|
||||
const output = structuredClone(rows),
|
||||
titles = [],
|
||||
errors = [];
|
||||
let head = null,
|
||||
body = [];
|
||||
function finish() {
|
||||
if (!head) return;
|
||||
components.forEach(
|
||||
(key) =>
|
||||
(head[key] = floating(
|
||||
body.filter((r) => num(r.CalcIndex) < 2).reduce((n, r) => n + num(r[key]), 0),
|
||||
)),
|
||||
);
|
||||
head.TC = sum(head);
|
||||
titles.push({
|
||||
...head,
|
||||
OTC: head.TC,
|
||||
ONC: head.NC,
|
||||
OGC: head.GC,
|
||||
OJC: head.JC,
|
||||
OSC: head.SC,
|
||||
});
|
||||
}
|
||||
for (const row of output) {
|
||||
const index = num(row.Index),
|
||||
link = num(row.LinkIndex);
|
||||
if (index > 0 && link !== 57) {
|
||||
finish();
|
||||
head = row;
|
||||
body = [];
|
||||
continue;
|
||||
}
|
||||
if (!head || row.Index == null) continue;
|
||||
if (link === 52) {
|
||||
finish();
|
||||
const title = titles[titles.length - 1],
|
||||
rate = num(row.GN) / 100;
|
||||
components.forEach((key) => (head[key] = floating(num(title[key]) * rate)));
|
||||
head.TC = sum(head);
|
||||
Object.assign(title, head, { NachalRatio: num(row.GN) });
|
||||
row.TU = title.OTC;
|
||||
head = null;
|
||||
body = [];
|
||||
continue;
|
||||
}
|
||||
if (![0, 2].includes(num(row.CalcIndex))) {
|
||||
body.push(row);
|
||||
continue;
|
||||
}
|
||||
components.forEach((key) => (row[key] = 0));
|
||||
const q = num(row.GN) / (["%", "%"].includes(row.Unite) ? 100 : 1),
|
||||
rate = 1 + num(row.Ratio) / 100;
|
||||
const digits = EstMath.even(get(index));
|
||||
let value = 0,
|
||||
field = "JC";
|
||||
if (index === -3) {
|
||||
const currency = String(row.Unite || "")[0];
|
||||
if (currency === "\\") value = num(row.TU) * q * 1e-7;
|
||||
else if ("$PEFLMY".includes(currency || "\u0000")) {
|
||||
let exchange = get(currency.charCodeAt(0));
|
||||
if (currency === "L" && !settings.has(76)) exchange = get(70);
|
||||
if (currency === "Y") exchange /= 100;
|
||||
if (!exchange) errors.push(`${head.Name}: 환율 없음 (${currency})`);
|
||||
const cut = options.DollarCostCut ? 1000 : 1;
|
||||
// f1580c receives two Currency integers; binary float multiplication can
|
||||
// turn an exact thousand (226644000) into the previous thousand.
|
||||
const converted =
|
||||
Number(
|
||||
(BigInt(even(num(row.TU) * 10000)) * BigInt(even(exchange * 10000))) /
|
||||
BigInt(cut * 100000000),
|
||||
) * cut;
|
||||
value = converted * q * 1e-7;
|
||||
} else value = num(row.TU) * q;
|
||||
value = fixed((even(value * 10000) / 10000) * rate, digits);
|
||||
} else if (index === -2) {
|
||||
let unitPrice = num(row.TU),
|
||||
quantity = q;
|
||||
if (String(row.Name || "").includes("잡")) {
|
||||
const fuel = [...body].reverse().find(
|
||||
(r) =>
|
||||
num(r.Index) === -2 &&
|
||||
fuels.has(
|
||||
String(r.Name || "")
|
||||
.replace(/\s/g, "")
|
||||
.toLowerCase(),
|
||||
),
|
||||
);
|
||||
unitPrice = fuel ? num(fuel.GC) || (num(fuel.SCheck) === 3 ? num(fuel.JC) : 0) : 0;
|
||||
row.TU = unitPrice;
|
||||
row.Unite = "%";
|
||||
quantity = num(row.GN) / 100;
|
||||
}
|
||||
value = fixed(even(even(unitPrice * quantity * 10000) * rate) / 10000, digits);
|
||||
field = num(row.SCheck) === 3 ? "JC" : "GC";
|
||||
} else if (index === -1) {
|
||||
const coefficient = Math.trunc(get(num(row.NCGasu)) * 1e10) / 1e10;
|
||||
let price = num(row.TU) * coefficient;
|
||||
if (options.JDLCalcMethod) price = floating(price, 1);
|
||||
value = fixed(even(even(price * q * 10000) * rate) / 10000, digits);
|
||||
field = "NC";
|
||||
}
|
||||
row[field] = value;
|
||||
row.TC = sum(row);
|
||||
body.push(row);
|
||||
}
|
||||
finish();
|
||||
return { rows: output, titles, errors };
|
||||
}
|
||||
return { calculate };
|
||||
})();
|
||||
Reference in New Issue
Block a user