From a015a8d23b46135c2e8312f68a1580f09a2afbb4 Mon Sep 17 00:00:00 2001 From: Adam Moussa Date: Thu, 27 Aug 2026 14:45:20 -0400 Subject: [PATCH] fix(3cx): preserve parking BLF IDs and fail the job on PATCH errors --- lambda/blf-sync/blf-sync-handler.ts | 3 +++ lambda/blf-sync/blf-sync.test.ts | 28 ++++++++++++++++++++++++++++ lambda/blf-sync/merge.ts | 22 +++++++++++++++------- 3 files changed, 46 insertions(+), 7 deletions(-) diff --git a/lambda/blf-sync/blf-sync-handler.ts b/lambda/blf-sync/blf-sync-handler.ts index d03a66e..39818eb 100644 --- a/lambda/blf-sync/blf-sync-handler.ts +++ b/lambda/blf-sync/blf-sync-handler.ts @@ -185,5 +185,8 @@ export async function handler(event: BlfSyncEvent = {}) { failed, }; console.log(JSON.stringify(summary)); + if (failed > 0) { + throw new Error(`blf sync patch failed for ${failed} user(s)`); + } return summary; } diff --git a/lambda/blf-sync/blf-sync.test.ts b/lambda/blf-sync/blf-sync.test.ts index f564a0c..11764bb 100644 --- a/lambda/blf-sync/blf-sync.test.ts +++ b/lambda/blf-sync/blf-sync.test.ts @@ -135,6 +135,34 @@ test("merge is a no-op when XML already matches", () => { assert.equal(blfsEqual(first.xml, second.xml), true); }); +test("merge keeps assigned shared-parking IDs so later runs are a no-op", () => { + const first = mergeDepartmentBlfs({ + currentXml: "", + selfExtension: "116", + colleagues, + contract: SLOT_CONTRACT["t54w-door-unlock-with-sp"], + }); + const assigned = serializeBlfs( + parseBlfs(first.xml).map((entry) => + entry.blfType === "SharedParking" || entry.blfType === "Line" + ? { ...entry, id: String(900 + entry.blfNo) } + : entry + ) + ); + const second = mergeDepartmentBlfs({ + currentXml: assigned, + selfExtension: "116", + colleagues, + contract: SLOT_CONTRACT["t54w-door-unlock-with-sp"], + }); + assert.equal(second.changed, false); + const parking = parseBlfs(second.xml).filter((e) => e.blfNo >= 3 && e.blfNo <= 5); + assert.deepEqual( + parking.map((e) => e.id), + ["903", "904", "905"] + ); +}); + test("serializeBlfs normalizes empty lists", () => { assert.equal(serializeBlfs([]), ""); assert.equal(blfsEqual("", serializeBlfs([])), true); diff --git a/lambda/blf-sync/merge.ts b/lambda/blf-sync/merge.ts index d8d1036..a2d2ee8 100644 --- a/lambda/blf-sync/merge.ts +++ b/lambda/blf-sync/merge.ts @@ -68,13 +68,21 @@ export function mergeDepartmentBlfs(input: { value: "", }; - const parking: BlfEntry[] = input.contract.sharedParking.map((slot) => ({ - id: "-1", - blfNo: slot.blfNo, - blfType: "SharedParking", - blfTypeId: "3", - value: slot.value, - })); + const parking: BlfEntry[] = input.contract.sharedParking.map((slot) => { + const existing = current.find( + (entry) => + entry.blfNo === slot.blfNo && + entry.blfType === "SharedParking" && + entry.value === slot.value + ); + return { + id: existing?.id ?? "-1", + blfNo: slot.blfNo, + blfType: "SharedParking", + blfTypeId: existing?.blfTypeId ?? "3", + value: slot.value, + }; + }); const managed: BlfEntry[] = placedColleagues.map((colleague, index) => ({ id: String(colleague.id),