Derive device voltages from project settings

This commit is contained in:
2026-07-29 09:53:58 +02:00
parent b1a11397b3
commit 084103bf54
39 changed files with 2696 additions and 76 deletions
@@ -3,11 +3,16 @@ import {
defaultDistributionBoardSupplyTypes,
distributionBoardSupplyTypes,
} from "../../shared/constants/distribution-board.js";
import {
resolveCircuitPhaseType,
resolveProjectVoltage,
} from "../services/project-voltage.service.js";
export const legacyProjectStateSnapshotSchemaVersion = 1 as const;
export const previousProjectStateSnapshotSchemaVersion = 2 as const;
export const distributionBoardProjectStateSnapshotSchemaVersion = 3 as const;
export const projectStateSnapshotSchemaVersion = 4 as const;
export const supplyTypesProjectStateSnapshotSchemaVersion = 4 as const;
export const projectStateSnapshotSchemaVersion = 5 as const;
const idSchema = z.string().trim().min(1);
const nullableStringSchema = z.string().nullable();
@@ -198,15 +203,20 @@ const distributionBoardProjectStateSnapshotSchema = z
})
.strict();
export const projectStateSnapshotSchema = z
const supplyTypesProjectStateSnapshotSchema = z
.object({
schemaVersion: z.literal(projectStateSnapshotSchemaVersion),
schemaVersion: z.literal(supplyTypesProjectStateSnapshotSchemaVersion),
project: currentProjectSchema,
distributionBoards: z.array(distributionBoardSchema),
...commonProjectStateSnapshotContents,
})
.strict();
export const projectStateSnapshotSchema =
supplyTypesProjectStateSnapshotSchema.extend({
schemaVersion: z.literal(projectStateSnapshotSchemaVersion),
});
export type ProjectStateSnapshot = z.infer<
typeof projectStateSnapshotSchema
>;
@@ -217,23 +227,33 @@ export function parseProjectStateSnapshot(
const version = isPlainObject(value) ? value.schemaVersion : undefined;
const snapshot =
version === legacyProjectStateSnapshotSchemaVersion
? upgradeDistributionBoardProjectStateSnapshot(
upgradePreviousProjectStateSnapshot(
upgradeLegacyProjectStateSnapshot(
legacyProjectStateSnapshotSchema.parse(value)
? upgradeSupplyTypesProjectStateSnapshot(
upgradeDistributionBoardProjectStateSnapshot(
upgradePreviousProjectStateSnapshot(
upgradeLegacyProjectStateSnapshot(
legacyProjectStateSnapshotSchema.parse(value)
)
)
)
)
: version === previousProjectStateSnapshotSchemaVersion
? upgradeDistributionBoardProjectStateSnapshot(
upgradePreviousProjectStateSnapshot(
previousProjectStateSnapshotSchema.parse(value)
? upgradeSupplyTypesProjectStateSnapshot(
upgradeDistributionBoardProjectStateSnapshot(
upgradePreviousProjectStateSnapshot(
previousProjectStateSnapshotSchema.parse(value)
)
)
)
: version === distributionBoardProjectStateSnapshotSchemaVersion
? upgradeDistributionBoardProjectStateSnapshot(
distributionBoardProjectStateSnapshotSchema.parse(value)
? upgradeSupplyTypesProjectStateSnapshot(
upgradeDistributionBoardProjectStateSnapshot(
distributionBoardProjectStateSnapshotSchema.parse(value)
)
)
: version === supplyTypesProjectStateSnapshotSchemaVersion
? upgradeSupplyTypesProjectStateSnapshot(
supplyTypesProjectStateSnapshotSchema.parse(value)
)
: projectStateSnapshotSchema.parse(value);
assertProjectStateSnapshotRelations(snapshot);
return snapshot;
@@ -271,10 +291,10 @@ function upgradePreviousProjectStateSnapshot(
function upgradeDistributionBoardProjectStateSnapshot(
snapshot: z.infer<typeof distributionBoardProjectStateSnapshotSchema>
): ProjectStateSnapshot {
): z.infer<typeof supplyTypesProjectStateSnapshotSchema> {
return {
...snapshot,
schemaVersion: projectStateSnapshotSchemaVersion,
schemaVersion: supplyTypesProjectStateSnapshotSchemaVersion,
project: {
...snapshot.project,
enabledDistributionBoardSupplyTypes: [
@@ -284,6 +304,37 @@ function upgradeDistributionBoardProjectStateSnapshot(
};
}
function upgradeSupplyTypesProjectStateSnapshot(
snapshot: z.infer<typeof supplyTypesProjectStateSnapshotSchema>
): ProjectStateSnapshot {
const settings = snapshot.project;
const sectionById = new Map(
snapshot.circuitSections.map((section) => [section.id, section])
);
return {
...snapshot,
schemaVersion: projectStateSnapshotSchemaVersion,
projectDevices: snapshot.projectDevices.map((device) => ({
...device,
voltageV: resolveProjectVoltage(device.phaseType, settings),
})),
circuits: snapshot.circuits.map((circuit) => {
const section = sectionById.get(circuit.sectionId);
if (!section) {
return circuit;
}
const phaseType = resolveCircuitPhaseType(
section.key,
circuit.deviceRows.map((row) => row.phaseType)
);
return {
...circuit,
voltage: resolveProjectVoltage(phaseType, settings),
};
}),
};
}
function isPlainObject(value: unknown): value is Record<string, unknown> {
return value !== null && typeof value === "object" && !Array.isArray(value);
}
@@ -364,6 +415,14 @@ function assertProjectStateSnapshotRelations(
}
for (const device of snapshot.projectDevices) {
assertProjectOwnership(device.projectId, projectId, "project device");
if (
device.voltageV !==
resolveProjectVoltage(device.phaseType, snapshot.project)
) {
throw new Error(
"Snapshot project device voltage must match project settings."
);
}
}
for (const floor of snapshot.floors) {
assertProjectOwnership(floor.projectId, projectId, "floor");
@@ -394,6 +453,18 @@ function assertProjectStateSnapshotRelations(
"Snapshot circuit reserve state must match its device rows."
);
}
const expectedVoltage = resolveProjectVoltage(
resolveCircuitPhaseType(
section.key,
circuit.deviceRows.map((row) => row.phaseType)
),
snapshot.project
);
if (circuit.voltage !== expectedVoltage) {
throw new Error(
"Snapshot circuit voltage must match project settings."
);
}
for (const row of circuit.deviceRows) {
if (row.circuitId !== circuit.id) {
throw new Error(