Renumber circuit groups explicitly

This commit is contained in:
2026-07-31 07:53:07 +02:00
parent 0cb280ddb2
commit be9c6f0d52
6 changed files with 347 additions and 1 deletions
+146
View File
@@ -10,6 +10,9 @@ import type { CircuitTreeSectionDto } from "../types";
import type {
CircuitGroupReorderAssignment,
} from "../../domain/models/circuit-group-structure-project-command.model";
import type {
CircuitGroupRenumberPlan,
} from "../../domain/services/circuit-group-renumbering";
export function toCircuitGroupSnapshot(
section: CircuitTreeSectionDto,
@@ -115,6 +118,75 @@ export function buildCircuitGroupReorderAssignments(
}));
}
export function buildCircuitGroupRenumberPlan(
sections: readonly CircuitTreeSectionDto[],
category: CircuitGroupCategory
): CircuitGroupRenumberPlan | null {
const groups = getOrderedCategoryGroups(sections, category);
if (!canRenumberCircuitGroups(sections, category)) {
return null;
}
return {
groups: groups.map((group, index) => {
const targetGroupNumber = index + 1;
const expectedPrefix = formatGroupPrefix(
category,
group.groupNumber
);
if (group.prefix !== expectedPrefix) {
throw new Error(
`Das Präfix der Gruppe „${group.displayName}“ passt nicht zu ihrer Gruppennummer.`
);
}
return {
groupId: group.id,
category,
expectedGroupNumber: group.groupNumber,
targetGroupNumber,
expectedPrefix,
targetPrefix: formatGroupPrefix(category, targetGroupNumber),
circuits: group.circuits.map((circuit) => {
const circuitNumber = parseCircuitNumber(
circuit.equipmentIdentifier,
category,
group.groupNumber
);
return {
circuitId: circuit.id,
expectedEquipmentIdentifier: circuit.equipmentIdentifier,
targetEquipmentIdentifier: formatCircuitIdentifier(
category,
targetGroupNumber,
circuitNumber
),
};
}),
components: group.components.map((component) => ({
componentId: component.id,
expectedEquipmentIdentifier: component.equipmentIdentifier,
targetEquipmentIdentifier: formatGroupComponentIdentifier(
category,
targetGroupNumber,
component.role
),
})),
};
}),
};
}
export function canRenumberCircuitGroups(
sections: readonly CircuitTreeSectionDto[],
category: CircuitGroupCategory
) {
const groups = getOrderedCategoryGroups(sections, category);
return (
groups.length > 0 &&
groups.some((group, index) => group.groupNumber !== index + 1)
);
}
function getNewGroupSortOrder(
category: CircuitGroupCategory,
sections: readonly (CircuitTreeSectionDto & {
@@ -141,3 +213,77 @@ function getNewGroupSortOrder(
? previous.sortOrder + (next.sortOrder - previous.sortOrder) / 2
: previous.sortOrder + 10;
}
function formatGroupPrefix(
category: CircuitGroupCategory,
groupNumber: number
) {
return `-${circuitGroupCategoryNumbers[category]}F${groupNumber}.`;
}
function getOrderedCategoryGroups(
sections: readonly CircuitTreeSectionDto[],
category: CircuitGroupCategory
) {
return sections
.filter(
(section): section is CircuitTreeSectionDto & {
category: CircuitGroupCategory;
groupNumber: number;
} =>
section.category === category &&
Number.isInteger(section.groupNumber) &&
(section.groupNumber ?? 0) > 0
)
.sort(
(left, right) =>
left.sortOrder - right.sortOrder ||
left.id.localeCompare(right.id)
);
}
function formatCircuitIdentifier(
category: CircuitGroupCategory,
groupNumber: number,
circuitNumber: number
) {
return `${formatGroupPrefix(category, groupNumber)}${circuitNumber}`;
}
function parseCircuitNumber(
equipmentIdentifier: string,
category: CircuitGroupCategory,
groupNumber: number
) {
const prefix = formatGroupPrefix(category, groupNumber);
const suffix = equipmentIdentifier.startsWith(prefix)
? equipmentIdentifier.slice(prefix.length)
: "";
const circuitNumber = Number(suffix);
if (
!/^[1-9]\d*$/.test(suffix) ||
!Number.isSafeInteger(circuitNumber)
) {
throw new Error(
`Das Stromkreis-BMK „${equipmentIdentifier}“ passt nicht zu seiner Gruppe.`
);
}
return circuitNumber;
}
function formatGroupComponentIdentifier(
category: CircuitGroupCategory,
groupNumber: number,
role: CircuitTreeSectionDto["components"][number]["role"]
) {
const categoryNumber = circuitGroupCategoryNumbers[category];
if (role === "group_upstream_protection") {
return `-${categoryNumber}F${groupNumber}.0`;
}
if (role === "group_residual_current_protection") {
return `-${categoryNumber}Q${groupNumber}.0`;
}
throw new Error(
"Die Stromkreisgruppe enthält eine nicht unterstützte Verteilerkomponente."
);
}