Update print view and documentation for logical feeds

This commit is contained in:
Julian Appel 2026-09-28 20:57:58 +02:00
parent 042a050876
commit b74b495fab
10 changed files with 278 additions and 158 deletions

View file

@ -2,7 +2,8 @@ import assert from "node:assert/strict";
import { describe, it } from "node:test";
import {
assertPrintRevisionConsistency,
buildPreliminaryBoardHierarchy,
buildBoardHierarchy,
formatFeedingReference,
formatCircuitCable,
formatProtectionDevice,
summarizePrintBoard,
@ -27,6 +28,8 @@ function board(
location: null,
fedFrom: null,
remark: null,
feedingDistributionBoardId: null,
feedingCircuitId: null,
...info,
};
}
@ -52,6 +55,8 @@ function tree(
const total = deviceRows.reduce((sum, row) => sum + row.rowTotalPower, 0);
return {
circuitListId: "list",
distributionBoardId: "board",
distributionBoardName: "Board",
currentRevision: 1,
singlePhaseVoltageV: 230,
threePhaseVoltageV: 400,
@ -79,7 +84,13 @@ function tree(
sortOrder: 1,
isReserve: false,
circuitTotalPower: total,
circuitApparentPower: deviceRows.reduce(
(sum, row) => sum + row.rowTotalPower / (row.cosPhi || 1),
0
),
circuitCosPhi: 1,
deviceRows,
downstreamBoardLoads: [],
},
],
},
@ -117,16 +128,15 @@ describe("print document model", () => {
assert.equal(formatCircuitCable(circuit), null);
});
it("does not guess a parent when feed text matches more than one board", () => {
it("does not derive hierarchy from the external free text", () => {
const summaries = [
summary("a", { boardNumber: "HV" }, 2),
summary("b", { name: "HV" }, 3),
summary("uv", { fedFrom: " hv " }, 1),
];
for (const ordered of [summaries, [...summaries].reverse()]) {
const entries = buildPreliminaryBoardHierarchy(ordered);
const entries = buildBoardHierarchy(ordered);
assert.ok(entries.every((entry) => entry.parentBoardId === null));
assert.equal(entries.reduce((sum, entry) => sum + entry.cumulatedDemandPowerKw, 0), 6);
}
});
@ -145,17 +155,39 @@ describe("print document model", () => {
});
assert.equal(result.circuitCount, 1);
assert.equal(result.installedPowerKw, 14);
assert.equal(result.devicePowerKw, 10);
assert.equal(result.powerBeforeBoardSimultaneityKw, 10);
assert.equal(result.demandPowerKw, 5);
// S = (4 / 0.8 + 6 / 1) × 0.5 = 5.5 kVA → I = 5500 / (√3 · 400)
assert.ok(Math.abs(result.designCurrentA - 5500 / (Math.sqrt(3) * 400)) < 1e-9);
});
it("nests boards by matching free-text feed and sums downstream demand", () => {
const entries = buildPreliminaryBoardHierarchy([
it("uses the selected one-phase feeder circuit for the design current", () => {
const inputTree = tree([
{ quantity: 1, powerPerUnit: 2.3, simultaneityFactor: 1, cosPhi: 1 },
]);
inputTree.feedingReference = {
distributionBoardId: "hv",
circuitListId: "hv-list",
distributionBoardName: "Hauptverteilung",
distributionBoardNumber: "NSHV",
circuitId: "out",
circuitEquipmentIdentifier: "-2F1.1",
circuitCategory: "single_phase",
};
const result = summarizePrintBoard({
board: board("uv"),
circuitListId: "uv",
floorName: null,
tree: inputTree,
});
assert.ok(Math.abs(result.designCurrentA - 10) < 1e-9);
});
it("nests boards by their logical feeding references", () => {
const entries = buildBoardHierarchy([
summary("hv", { boardNumber: "HV 0.1", fedFrom: "HAK" }, 10),
summary("uv-a", { boardNumber: "UV 1.1", fedFrom: " hv 0.1 " }, 4),
summary("uv-b", { boardNumber: "UV 1.2", fedFrom: "UV 1.1" }, 2),
summary("uv-a", { boardNumber: "UV 1.1", feedingDistributionBoardId: "hv" }, 4),
summary("uv-b", { boardNumber: "UV 1.2", feedingDistributionBoardId: "uv-a" }, 2),
summary("uv-c", { name: "UV-C", fedFrom: "unbekannt" }, 1),
]);
assert.deepEqual(
@ -163,28 +195,37 @@ describe("print document model", () => {
entry.summary.board.id,
entry.depth,
entry.parentBoardId,
entry.cumulatedDemandPowerKw,
]),
[
["hv", 0, null, 16],
["uv-a", 1, "hv", 6],
["uv-b", 2, "uv-a", 2],
["uv-c", 0, null, 1],
["hv", 0, null],
["uv-a", 1, "hv"],
["uv-b", 2, "uv-a"],
["uv-c", 0, null],
]
);
});
it("keeps boards with cyclic feed texts at the top level", () => {
const entries = buildPreliminaryBoardHierarchy([
summary("a", { boardNumber: "A", fedFrom: "B" }, 1),
summary("b", { boardNumber: "B", fedFrom: "A" }, 1),
it("keeps malformed cyclic logical links visible at the top level", () => {
const entries = buildBoardHierarchy([
summary("a", { boardNumber: "A", feedingDistributionBoardId: "b" }, 1),
summary("b", { boardNumber: "B", feedingDistributionBoardId: "a" }, 1),
]);
assert.equal(entries.length, 2);
assert.ok(entries.some((entry) => entry.parentBoardId === null));
assert.equal(
entries.reduce((sum, entry) => sum + (entry.depth === 0 ? entry.cumulatedDemandPowerKw : 0), 0),
2
);
});
it("formats the resolved feeding board and circuit instead of free text", () => {
const value = summary("uv", { fedFrom: "Alttext" }, 1);
value.tree.feedingReference = {
distributionBoardId: "hv",
circuitListId: "hv-list",
distributionBoardName: "Hauptverteilung",
distributionBoardNumber: "NSHV",
circuitId: "out",
circuitEquipmentIdentifier: "-3F1.1",
circuitCategory: "three_phase",
};
assert.equal(formatFeedingReference(value), "NSHV-3F1.1");
});
it("formats protection devices for the plan table", () => {