feat: implement manual user validation and user deletion flow

This commit is contained in:
Christian Vidal Wolf
2026-05-20 13:33:37 +02:00
parent 1d105e19ae
commit 47b9303202
22 changed files with 2613 additions and 93 deletions
+28 -5
View File
@@ -133,12 +133,17 @@ function normalizeForComparison(field, value) {
return '0';
}
if (value === null || value === undefined || value === '') return null;
if (strField.includes('date')) {
return formatDateForBc(value);
if (value === null || value === undefined || value === '') {
return '0001-01-01';
}
const normalizedDate = formatDateForBc(value);
return normalizedDate === '0001-01-01' ? '0001-01-01' : normalizedDate;
}
if (value === null || value === undefined || value === '') return null;
if (typeof value === 'string') {
return value.replace(/\r\n/g, '\n').trimEnd();
}
@@ -286,6 +291,8 @@ function makePreviewSection({
writeMethod,
writeUrlTemplate,
writeBodyTemplate,
supported = true,
supportReason = null,
}) {
const changes = buildFieldChanges(fieldPreviews, currentRecord, desiredPayload);
return {
@@ -298,7 +305,9 @@ function makePreviewSection({
writeMethod: writeMethod || null,
writeUrlTemplate: writeUrlTemplate || null,
writeBodyTemplate: writeBodyTemplate || null,
canApply: Boolean(writeUrlTemplate),
canApply: Boolean(writeUrlTemplate) && supported,
supported,
supportReason,
};
}
@@ -310,7 +319,7 @@ export function buildBusinessCentralSyncPreview(config, mapping, snapshot) {
fieldPreviews: mapping.itemsFields,
writeMethod: config.itemsWriteMethod || config.writeMethod,
writeUrlTemplate: config.itemsWriteUrlTemplate || config.writeUrlTemplate,
writeBodyTemplate: config.itemsWriteBodyTemplate || config.writeBodyTemplate || null,
writeBodyTemplate: config.itemsWriteBodyTemplate || null,
});
const itemUnitsSection = makePreviewSection({
@@ -464,6 +473,10 @@ async function applyItemUnitsSection(config, token, snapshot, preview, context)
return { applied: false, reason: 'No itemUnitsOfMeasure changes' };
}
if (!preview.itemUnitsOfMeasure.supported) {
return { applied: false, reason: preview.itemUnitsOfMeasure.supportReason || 'itemUnitsOfMeasure sync is not supported by this BC API yet; preview only' };
}
if (!config.itemUnitsWriteUrlTemplate) {
return { applied: false, reason: 'itemUnitsOfMeasure write template not configured' };
}
@@ -487,6 +500,13 @@ export async function applyBusinessCentralSync(config, token, headers, row, prev
const snapshot = await fetchBusinessCentralSnapshot(config, token, mapping.articleNo);
const preview = buildBusinessCentralSyncPreview(config, mapping, snapshot);
const hasItemUnitsChanges = preview.itemUnitsOfMeasure.changes.some(change => change.changed);
if (hasItemUnitsChanges && !snapshot.itemUnitsOfMeasure) {
const error = new Error(`BC itemUnitsOfMeasure row missing for ${mapping.articleNo}. This BC API cannot update these fields until the row exists or BC exposes an upsert action.`);
error.statusCode = 409;
throw error;
}
if (previewToken && previewToken !== preview.previewToken) {
const error = new Error('Preview token mismatch. BC data changed or preview is stale.');
error.statusCode = 409;
@@ -551,6 +571,9 @@ export async function applyBusinessCentralSync(config, token, headers, row, prev
previewToken: preview.previewToken,
results,
preview,
warning: preview.itemUnitsOfMeasure.changes.some(change => change.changed) && !preview.itemUnitsOfMeasure.supported
? (preview.itemUnitsOfMeasure.supportReason || 'itemUnitsOfMeasure sync is not supported by this BC API yet; preview only')
: undefined,
};
}