seahaven-door-unlock-api/lambda/blf-sync/slot-contract.ts
Adam Moussa bbc113497a
Some checks failed
Deploy / deploy (push) Has been cancelled
feat(3cx): sync office department blfs via xapi (PLAT-116) (#80)
* feat(3cx): sync office department BLFs via XAPI

Keep unlock and lockdown keys in the templates and write colleague plus shared-parking BLFs per extension so phones skip their own line.

* fix(3cx): preserve parking BLF IDs and fail the job on PATCH errors
2026-08-27 14:58:55 -04:00

80 lines
2.2 KiB
TypeScript

export type TemplateId =
| "t54w-door-unlock"
| "t54w-door-unlock-with-sp"
| "t58w-door-unlock";
export interface SharedParkingSlot {
readonly blfNo: number;
readonly value: string;
}
export interface SlotContract {
readonly reserved: readonly number[];
readonly sharedParking: readonly SharedParkingSlot[];
readonly ownLine: number;
readonly managedStart: number;
readonly managedEnd: number;
}
export const SLOT_CONTRACT: Record<TemplateId, SlotContract> = {
"t54w-door-unlock": {
reserved: [2],
sharedParking: [],
ownLine: 1,
managedStart: 3,
managedEnd: 12,
},
"t54w-door-unlock-with-sp": {
reserved: [2],
sharedParking: [
{ blfNo: 3, value: "SP1" },
{ blfNo: 4, value: "SP2" },
{ blfNo: 5, value: "SP3" },
],
ownLine: 1,
managedStart: 6,
managedEnd: 15,
},
"t58w-door-unlock": {
reserved: [2, 3, 4],
sharedParking: [],
ownLine: 1,
managedStart: 5,
managedEnd: 14,
},
};
const TEMPLATE_MATCHERS: { id: TemplateId; needle: string }[] = [
{ id: "t54w-door-unlock-with-sp", needle: "yealinkT54W-door-unlock-with-sp" },
{ id: "t54w-door-unlock", needle: "yealinkT54W-door-unlock" },
{ id: "t58w-door-unlock", needle: "yealinkT58W-door-unlock" },
];
export function resolveTemplateId(...candidates: Array<string | undefined | null>): TemplateId | undefined {
const haystack = candidates.filter(Boolean).join(" ");
if (!haystack) {
return undefined;
}
for (const matcher of TEMPLATE_MATCHERS) {
if (haystack.includes(matcher.needle)) {
return matcher.id;
}
}
return undefined;
}
export function isManagedSlot(contract: SlotContract, blfNo: number): boolean {
return blfNo >= contract.managedStart && blfNo <= contract.managedEnd;
}
export function isReservedSlot(contract: SlotContract, blfNo: number): boolean {
return contract.reserved.includes(blfNo);
}
export function isSharedParkingSlot(contract: SlotContract, blfNo: number): boolean {
return contract.sharedParking.some((slot) => slot.blfNo === blfNo);
}
export function managedSlotCount(contract: SlotContract): number {
return contract.managedEnd - contract.managedStart + 1;
}