Patterns
Catalogue produits et autoremplissage de lignes
Pré-remplir une ligne via `product_id` et enregistrer à la volée
Le registre `products` stocke des produits/services réutilisables (prix HT, TVA par défaut, unité UN/ECE Rec 20, `revenue_category` fiscale, catégorie d'organisation custom). À la création d'une facture, d'un devis ou d'un avoir, une ligne peut référencer `product_id` : l'API pré-remplit description, prix, taux de TVA et unité depuis le catalogue. Le flag `save_to_catalog=true` sur une ligne déclenche un upsert atomique du produit (dédup par SKU puis nom) DANS la transaction du document. Comme pour les buyers, le lien `line.product_id` est soft (FK `nullOnDelete`) : le snapshot de prix/description émis reste la vérité ISCA — supprimer un produit du catalogue n'altère pas les documents passés. La `revenue_category` (goods/service/accommodation) est distincte de la `product_category_id` (organisation interne, custom).
À retenir
- `products` + `product_categories`, scope (tenant_id, sub_tenant_id)
- Ligne avec `product_id` → autoremplissage desc/prix/TVA/unité
- `save_to_catalog=true` → upsert atomique dans la transaction du doc
- `line.product_id` soft (FK nullOnDelete), snapshot émis = vérité ISCA
- `revenue_category` fiscale ≠ `product_category_id` (organisation)
- Endpoints : `/api/v1/products` et `/api/v1/product-categories`
Exemple de code
import { ScellApiClient } from '@scell/sdk'; // v3.5.0
const client = new ScellApiClient({ apiKey: process.env.SCELL_API_KEY! });
// 1. Créer un produit catalogue
const product = await client.products.create({
name: 'Licence SaaS annuelle',
sku: 'SAAS-ANNUAL',
unit_price_ht: 1200,
default_tax_rate: 20,
revenue_category: 'service',
unit: 'C62', // unité par défaut UN/ECE Rec 20
});
// 2. Facturer : la ligne référence product_id (autoremplissage serveur)
const invoice = await client.invoices.create({
format: 'factur-x',
profile: 'EN16931',
currency: 'EUR',
buyer: { siret: '98765432109876', name: 'Acme SARL', address: { street: '2 av. Demo', city: 'Lyon', postal_code: '69001', country: 'FR' } },
lines: [
{ product_id: product.id, quantity: 2 }, // desc/prix/TVA repris du catalogue
// 3. Nouvelle ligne enregistrée à la volée dans le catalogue
{ description: 'Setup initial', quantity: 1, unit_price: 500, vat_rate: 20, save_to_catalog: true },
],
});
console.log('Facture :', invoice.id);