Add Linear XLSX follow-up import

This commit is contained in:
Julian Appel 2026-09-30 20:40:40 +02:00
parent 1a4c8cad8c
commit 2581beee3c
28 changed files with 1114 additions and 31 deletions

View file

@ -1,6 +1,7 @@
import type { Request, Response } from "express";
import { randomUUID } from "node:crypto";
import { createExternalObjectPlanningUpdateProjectCommand } from "../../domain/models/external-object-planning-project-command.model.js";
import { createExternalObjectDeleteMissingProjectCommand } from "../../domain/models/external-object-delete-missing-project-command.model.js";
import { createExternalObjectRowAssignmentProjectCommand } from "../../domain/models/external-object-row-assignment-project-command.model.js";
import type { CircuitDeviceRowSnapshot } from "../../domain/models/circuit-device-row-structure-project-command.model.js";
import type { ExternalModelObjectPlanningValues } from "../../external-model/domain/external-model-contracts.js";
@ -57,6 +58,39 @@ export function updateExternalObjects(req: Request, res: Response) {
} catch (error) { return respondWithProjectCommandError(error, res); }
}
export async function deleteMissingExternalObjects(req: Request, res: Response) {
const projectId = String(req.params.projectId ?? "");
try {
const expectedRevision = parseExpectedRevision(req.body?.expectedRevision);
const objectIds = parseObjectIds(req.body?.objectIds);
if (req.body?.confirmed !== true) throw new Error("Das Löschen fehlender Revit-Objekte muss bestätigt werden.");
const { state, projectExists } = externalModelStateRepository.getByProject(projectId);
if (!projectExists) return res.status(404).json({ error: "Projekt nicht gefunden." });
const byId = new Map(state.objects.map((object) => [object.id, object]));
const selected = objectIds.map((id) => {
const object = byId.get(id);
if (!object || object.presenceStatus !== "missing") throw new Error("Nur im letzten Import fehlende Revit-Objekte dürfen gelöscht werden.");
return object;
});
const treeResult = await buildProjectCircuitTrees(projectId);
const quantitiesByRowId = new Map<string, number>();
for (const object of selected) if (object.circuitDeviceRowId) quantitiesByRowId.set(object.circuitDeviceRowId, (quantitiesByRowId.get(object.circuitDeviceRowId) ?? 0) + object.planningValues.effectiveQuantity);
const rows = [...quantitiesByRowId].map(([rowId, removedQuantity]) => {
const location = findRow(treeResult, rowId);
if (!location) throw new Error("Eine verknüpfte Gerätezeile wurde nicht gefunden.");
const expected = toRowSnapshot(location.row, location.circuitId);
return { expected, target: { ...expected, quantity: expected.quantity - removedQuantity } };
});
const result = projectCommandService.executeUser({
projectId,
expectedRevision,
description: `${selected.length} fehlende Revit-Objekte gelöscht`,
command: createExternalObjectDeleteMissingProjectCommand({ objects: selected.map((expected) => ({ expected, target: null })), rows }),
});
return res.json(result);
} catch (error) { return respondWithProjectCommandError(error, res); }
}
export async function assignExternalObjectsToRow(req: Request, res: Response) {
const projectId = String(req.params.projectId ?? "");
try {