Add Revit initial import apply API

This commit is contained in:
Julian Appel 2026-08-02 17:42:29 +02:00
parent c9e5fdd876
commit 8646f346e6
9 changed files with 370 additions and 2 deletions

View file

@ -0,0 +1,130 @@
import type { ExternalCsvConfiguration, ExternalCsvDocument } from "../csv/external-csv-contracts.js";
import type { ExternalModelStateSnapshot } from "../domain/external-model-contracts.js";
import type { createExternalInitialImportPlan } from "./external-initial-import-plan.js";
type ExternalInitialImportPlan = ReturnType<typeof createExternalInitialImportPlan>;
export interface ExternalRoomDecision {
sourceRoomKey: string;
roomId: string | null;
defaultDistributionBoardId: string | null;
}
export interface ExternalFamilyProjectDeviceDecision {
familyAndType: string;
projectDeviceId: string | null;
}
export function buildExternalInitialImportTarget(input: {
projectId: string;
expectedRevision: number;
sourceName: string;
importedAtIso: string;
configurationVersion: number;
configuration: ExternalCsvConfiguration;
originalContentBase64: string;
document: ExternalCsvDocument;
plan: ExternalInitialImportPlan;
roomDecisions: ExternalRoomDecision[];
familyProjectDeviceDecisions: ExternalFamilyProjectDeviceDecision[];
createId: () => string;
}): ExternalModelStateSnapshot {
if (input.plan.familyGroups.some((group) => !group.classified)) {
throw new Error("Alle Familie-und-Typ-Werte müssen vor dem Erstimport klassifiziert sein.");
}
const roomDecisionByKey = exactDecisionMap(
input.plan.sourceRooms.map((room) => room.sourceRoomKey),
input.roomDecisions,
(decision) => decision.sourceRoomKey,
"Quellraum"
);
const familyDecisionByName = exactDecisionMap(
input.plan.familyGroups.map((group) => group.familyAndType),
input.familyProjectDeviceDecisions,
(decision) => decision.familyAndType,
"Familie und Typ"
);
const sourceId = input.createId();
const batchId = input.createId();
const roomMappingIdByKey = new Map(
input.plan.sourceRooms.map((room) => [room.sourceRoomKey, input.createId()])
);
return {
source: {
id: sourceId,
projectId: input.projectId,
name: input.sourceName.trim(),
sourceType: "revit_csv",
},
importBatches: [{
id: batchId,
projectId: input.projectId,
sourceId,
importKind: "initial",
importedAtIso: input.importedAtIso,
fileName: input.plan.fileName,
sha256: input.plan.sha256,
appliedProjectRevision: input.expectedRevision + 1,
configurationVersion: input.configurationVersion,
configurationSnapshot: input.configuration,
originalContentBase64: input.originalContentBase64,
document: input.document,
}],
roomMappings: input.plan.sourceRooms.map((room) => {
const decision = roomDecisionByKey.get(room.sourceRoomKey)!;
return {
id: roomMappingIdByKey.get(room.sourceRoomKey)!,
projectId: input.projectId,
sourceId,
normalizedSourceRoomKey: room.sourceRoomKey,
sourceFloorName: null,
sourceRoomNumber: room.roomNumber,
sourceRoomName: room.roomName,
roomId: decision.roomId,
defaultDistributionBoardId: decision.defaultDistributionBoardId,
};
}),
objects: input.plan.objects.map((object) => ({
id: input.createId(),
projectId: input.projectId,
sourceId,
ifcGuid: object.ifcGuid,
lastSeenImportBatchId: batchId,
lastAcceptedImportBatchId: batchId,
acceptedSourceValues: object.sourceValues,
planningValues: object.suggestedPlanningValues,
overriddenFields: [],
externalRoomMappingId:
object.sourceRoomKey === null
? null
: roomMappingIdByKey.get(object.sourceRoomKey)!,
distributionBoardId: null,
linkedProjectDeviceId:
familyDecisionByName.get(object.sourceValues.familyAndType)!
.projectDeviceId,
circuitDeviceRowId: null,
presenceStatus: "present",
})),
};
}
function exactDecisionMap<T>(
expectedKeys: string[],
decisions: T[],
keyOf: (decision: T) => string,
label: string
) {
const expected = new Set(expectedKeys);
const result = new Map<string, T>();
for (const decision of decisions) {
const key = keyOf(decision);
if (!expected.has(key) || result.has(key)) {
throw new Error(`${label}-Entscheidungen sind unvollständig oder doppelt.`);
}
result.set(key, decision);
}
if (result.size !== expected.size) {
throw new Error(`${label}-Entscheidungen sind unvollständig oder doppelt.`);
}
return result;
}