forked from jappel/leistungsbilanz-ts
Add proposed cable-sizing module
Isolated module (mirrors src/external-model/ dependency direction) that adds an on-demand, DIN VDE 0298-4 referenced cable cross-section calculator: a click-on-a-circuit input mask for laying method, insulation, ambient temperature, grouping and voltage-drop limit that suggests a cross-section for the circuit cableCrossSection/cableLength fields. Applying a suggestion goes through the existing circuit.update command (expectedRevision, undo/redo) unchanged - nothing here writes to circuits directly or touches the revision/command system. See docs/cable-sizing-module.md for the full rationale, API contract, verification status and maintenance plan. Proposal, not yet reviewed by the project owner - see the docs file. 423 existing + 11 new tests pass, build:api/build:web/typecheck:scripts clean.
This commit is contained in:
parent
a17e2e3f4b
commit
1d030971dd
17 changed files with 4179 additions and 2 deletions
80
src/server/controllers/cable-sizing.controller.ts
Normal file
80
src/server/controllers/cable-sizing.controller.ts
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
import { randomUUID } from "node:crypto";
|
||||
import type { Request, Response } from "express";
|
||||
import { cableSizingRequestSchema } from "../../cable-sizing/domain/cable-sizing-contracts.js";
|
||||
import {
|
||||
calculateCableSizing,
|
||||
buildCableSizingAlerts,
|
||||
LAYING_METHODS,
|
||||
LAYING_METHOD_LABELS,
|
||||
LAYING_METHOD_VERIFIED,
|
||||
INSULATION_MATERIALS,
|
||||
INSULATION_MATERIAL_LABELS,
|
||||
} from "../../cable-sizing/domain/cable-sizing-calculation.js";
|
||||
import { cableSizingCalculationRepository } from "../composition/application-repositories.js";
|
||||
|
||||
// Stateless calculation, not a project command: no expectedRevision, no
|
||||
// circuit mutation here. The caller applies the result via the existing
|
||||
// circuit.update command (POST /api/projects/:projectId/commands) if the
|
||||
// user confirms it. See docs/cable-sizing-module.md.
|
||||
export async function calculateCableSizingHandler(req: Request, res: Response) {
|
||||
const parsed = cableSizingRequestSchema.safeParse(req.body);
|
||||
if (!parsed.success) {
|
||||
return res.status(400).json({ error: parsed.error.flatten() });
|
||||
}
|
||||
|
||||
const { context, ...input } = parsed.data;
|
||||
const result = calculateCableSizing(input);
|
||||
const alerts = buildCableSizingAlerts(input, result);
|
||||
|
||||
const entry = await cableSizingCalculationRepository.create({
|
||||
id: randomUUID(),
|
||||
projectId: context?.projectId ?? null,
|
||||
circuitId: context?.circuitId ?? null,
|
||||
equipmentIdentifier: context?.equipmentIdentifier ?? null,
|
||||
input,
|
||||
result,
|
||||
appliedToCircuit: 0,
|
||||
});
|
||||
|
||||
return res.status(201).json({ calculationId: entry.id, result, alerts });
|
||||
}
|
||||
|
||||
export async function listLayingMethodsHandler(_req: Request, res: Response) {
|
||||
return res.json(
|
||||
LAYING_METHODS.map((method) => ({
|
||||
method,
|
||||
label: LAYING_METHOD_LABELS[method],
|
||||
dataVerified: LAYING_METHOD_VERIFIED[method],
|
||||
}))
|
||||
);
|
||||
}
|
||||
|
||||
export async function listInsulationMaterialsHandler(_req: Request, res: Response) {
|
||||
return res.json(
|
||||
INSULATION_MATERIALS.map((insulation) => ({
|
||||
insulation,
|
||||
label: INSULATION_MATERIAL_LABELS[insulation],
|
||||
}))
|
||||
);
|
||||
}
|
||||
|
||||
export async function markCalculationAppliedHandler(req: Request, res: Response) {
|
||||
const { calculationId } = req.params;
|
||||
if (typeof calculationId !== "string") {
|
||||
return res.status(400).json({ error: "Invalid calculationId" });
|
||||
}
|
||||
const updated = await cableSizingCalculationRepository.markApplied(calculationId);
|
||||
if (!updated) {
|
||||
return res.status(404).json({ error: "Calculation not found" });
|
||||
}
|
||||
return res.json(updated);
|
||||
}
|
||||
|
||||
export async function listCalculationsForCircuitHandler(req: Request, res: Response) {
|
||||
const { circuitId } = req.params;
|
||||
if (typeof circuitId !== "string") {
|
||||
return res.status(400).json({ error: "Invalid circuitId" });
|
||||
}
|
||||
const rows = await cableSizingCalculationRepository.listByCircuit(circuitId);
|
||||
return res.json(rows);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue