diff --git a/backend/src/utils/tenantMergeService.ts b/backend/src/utils/tenantMergeService.ts
index 695fc91..a0b091c 100644
--- a/backend/src/utils/tenantMergeService.ts
+++ b/backend/src/utils/tenantMergeService.ts
@@ -80,6 +80,42 @@ const remapSourceTenant = (exportData: TenantFullExport, targetTenantId: number)
return tables
}
+const splitSourceTablesByAvailability = (
+ sourceTables: Record[]>,
+ metadata: Record
+) => {
+ const available: Record[]> = {}
+ const unavailable = Object.keys(sourceTables).filter((table) => {
+ if (metadata[table]) {
+ available[table] = sourceTables[table]
+ return false
+ }
+ return sourceTables[table].length > 0
+ })
+
+ return { available, unavailable }
+}
+
+const appendUnavailableTableConflicts = (plan: TenantMergePlan, unavailableTables: string[]) => {
+ for (const table of unavailableTables.sort()) {
+ plan.items.push({
+ id: `missing-target-table:${table}`,
+ table,
+ kind: "conflict",
+ sourceKey: "Zieltabelle fehlt",
+ targetKey: null,
+ label: `Tabelle ${table} ist im Zielsystem nicht vorhanden`,
+ defaultDecision: "target",
+ allowedDecisions: ["target"],
+ differences: ["Die erforderliche Tabelle fehlt im Zielschema und muss zuerst per Migration angelegt werden."],
+ sourceRow: {},
+ targetRow: null,
+ })
+ plan.summary.conflict += 1
+ }
+ return plan
+}
+
const loadTargetRows = async (
client: any,
table: string,
@@ -124,7 +160,8 @@ export const createTenantMergeDryRunWithClient = async (
targetTenantId: number
): Promise => {
const metadata = await loadMergeMetadata(client)
- const sourceTables = remapSourceTenant(exportData, targetTenantId)
+ const remappedSourceTables = remapSourceTenant(exportData, targetTenantId)
+ const { available: sourceTables, unavailable } = splitSourceTablesByAvailability(remappedSourceTables, metadata)
const targetTables: Record[]> = {}
for (const [table, sourceRows] of Object.entries(sourceTables)) {
@@ -133,7 +170,7 @@ export const createTenantMergeDryRunWithClient = async (
targetTables[table] = await loadTargetRows(client, table, sourceRows, tableMetadata, targetTenantId)
}
- return buildTenantMergePlan(sourceTables, targetTables, metadata)
+ return appendUnavailableTableConflicts(buildTenantMergePlan(sourceTables, targetTables, metadata), unavailable)
}
export const createTenantMergeDryRun = async (
@@ -214,7 +251,9 @@ const topologicalTableOrder = (tables: string[], metadata: Record
- metadata[table].foreignKeys.every((foreignKey) => !remaining.has(foreignKey.referencedTable) || foreignKey.referencedTable === table)
+ (metadata[table]?.foreignKeys || []).every((foreignKey) =>
+ !remaining.has(foreignKey.referencedTable) || foreignKey.referencedTable === table
+ )
)
const next = ready.length ? ready.sort() : [Array.from(remaining).sort()[0]]
for (const table of next) {
@@ -240,7 +279,8 @@ export const executeTenantMergeWithClient = async (
decisions: Record
): Promise => {
const metadata = await loadMergeMetadata(client)
- const sourceTables = remapSourceTenant(rawExportData, targetTenantId)
+ const remappedSourceTables = remapSourceTenant(rawExportData, targetTenantId)
+ const { available: sourceTables } = splitSourceTablesByAvailability(remappedSourceTables, metadata)
const preparedExport: TenantFullExport = prepareTenantFullExportRowsForImport({
...rawExportData,
tenantId: targetTenantId,
diff --git a/frontend/pages/administration/tenant-imports/[importId].vue b/frontend/pages/administration/tenant-imports/[importId].vue
index 4ecc953..5137bc9 100644
--- a/frontend/pages/administration/tenant-imports/[importId].vue
+++ b/frontend/pages/administration/tenant-imports/[importId].vue
@@ -217,12 +217,14 @@ onMounted(async () => {
Ziel behalten