Context
An expense-report push used to PUT /api/v2/contacts/{id} on the member's existing Holded contact with only name, trade name and IBAN. Holded's v2 contact update is a full replacement ("any field you omit from the request body will be reset to its default value"), so supplier_record reset and the next purchase doc minted a second creditor account (40000004 → 40000060 on 2026-09-21). SetCreditorAccountNumAsync then silently rebound the member to the new number.
The fix PR stops updating linked contacts: once a member is bound (or seeded from a prior report), that contact id is used as is and Holded is not called. Consequence: a legal-name or IBAN change after the first push no longer reaches Holded.
Wanted
A periodic link-check sync in Finance that, per binding:
- verifies the Holded contact still exists and still carries the bound
SupplierAccountNum (flag drift on /Finance/Creditors, never auto-rebind);
- carries name/IBAN changes to Holded without a partial PUT — read-merge-write of the full contact, or a partial-update endpoint if Holded exposes one;
- writes an audit entry for anything it changes or finds drifted.
Also: SetCreditorAccountNumAsync should refuse to move an already-numbered binding to a different number without an admin, and log an audit entry when a binding's number changes. Today that rebind is invisible to the Board.
Leftover: HoldedClient.UpsertContactAsync's update branch (ExistingContactId) is now uncalled and unsafe under full-replacement semantics; remove or rebuild it as part of this.
Context
An expense-report push used to
PUT /api/v2/contacts/{id}on the member's existing Holded contact with only name, trade name and IBAN. Holded's v2 contact update is a full replacement ("any field you omit from the request body will be reset to its default value"), sosupplier_recordreset and the next purchase doc minted a second creditor account (40000004 → 40000060 on 2026-09-21).SetCreditorAccountNumAsyncthen silently rebound the member to the new number.The fix PR stops updating linked contacts: once a member is bound (or seeded from a prior report), that contact id is used as is and Holded is not called. Consequence: a legal-name or IBAN change after the first push no longer reaches Holded.
Wanted
A periodic link-check sync in Finance that, per binding:
SupplierAccountNum(flag drift on/Finance/Creditors, never auto-rebind);Also:
SetCreditorAccountNumAsyncshould refuse to move an already-numbered binding to a different number without an admin, and log an audit entry when a binding's number changes. Today that rebind is invisible to the Board.Leftover:
HoldedClient.UpsertContactAsync's update branch (ExistingContactId) is now uncalled and unsafe under full-replacement semantics; remove or rebuild it as part of this.