Patterns
Registre d'acheteurs réutilisables
Référencer un acheteur par `buyer_id` sans casser l'immutabilité fiscale
Le registre `buyers` permet de stocker un acheteur (SIRET, TVA, adresses de facturation et de livraison) et de le réutiliser via `buyer_id` à chaque facture. Le scope est strict par paire `(tenant_id, sub_tenant_id)` : un tenant ne voit jamais les acheteurs d'un autre (anti-IDOR via 404). Point clé de conformité : le lien `invoices.buyer_id` est un UUID soft, SANS FK cascade. Les colonnes dénormalisées `buyer_*` snapshotées sur la facture restent la source de vérité immutable — modifier un buyer plus tard n'impacte JAMAIS les factures déjà émises (ISCA). À la création de facture, on fournit soit `buyer_id` (l'API re-snapshote l'état courant), soit les champs flat `buyer_*` (l'API upsert un buyer par SIRET puis email). L'adresse de livraison (BG-13) n'est émise dans le Factur-X que si elle diffère de l'adresse de facturation.
À retenir
- Scope strict (tenant_id, sub_tenant_id) — anti-IDOR 404
- `invoices.buyer_id` soft UUID, pas de FK cascade
- Colonnes `buyer_*` dénormalisées = vérité immutable ISCA
- Upsert déterministe par SIRET (B2B) puis email (B2C)
- Adresse de livraison BG-13 omise si identique à la facturation
- Endpoints : `GET/POST/PATCH/DELETE /api/v1/buyers`
Exemple de code
import { ScellApiClient } from '@scell/sdk'; // v3.5.0
const client = new ScellApiClient({ apiKey: process.env.SCELL_API_KEY! });
// 1. Enregistrer un acheteur réutilisable
const { data: buyer } = await client.buyers.create({
name: 'Acme SARL',
country: 'FR',
siret: '98765432109876',
vat_number: 'FR98765432109',
email: 'compta@acme.fr',
billing_address: { line1: '2 av. Demo', postal_code: '69001', city: 'Lyon', country: 'FR' },
// Adresse de livraison distincte → BG-13 émise dans le Factur-X
shipping_address: { name: 'Entrepôt Lyon', line1: '10 rue du Stock', postal_code: '69007', city: 'Lyon', country: 'FR' },
});
// 2. Facturer en référençant l'acheteur (snapshot immutable côté facture)
const invoice = await client.invoices.create({
format: 'factur-x',
profile: 'EN16931',
currency: 'EUR',
buyer_id: buyer.id,
lines: [{ description: 'Licence annuelle', quantity: 1, unit_price: 1200, vat_rate: 20 }],
});
console.log('Facture :', invoice.id, '→ buyer figé sur la facture');
// 3. Modifier le buyer plus tard n'altère PAS les factures déjà émises (ISCA)
await client.buyers.update(buyer.id, { email: 'finance@acme.fr' });