Skip to main content

Patterns

Product catalog and line autofill

Prefill a line via `product_id` and save on the fly

The `products` registry stores reusable products/services (unit price ex-VAT, default VAT, UN/ECE Rec 20 unit, fiscal `revenue_category`, custom organisation category). On invoice, quote or credit-note creation, a line can reference `product_id`: the API prefills description, price, VAT rate and unit from the catalog. The `save_to_catalog=true` flag on a line triggers an atomic product upsert (dedup by SKU then name) WITHIN the document transaction. Like buyers, the `line.product_id` link is soft (FK `nullOnDelete`): the emitted price/description snapshot remains the ISCA truth — deleting a catalog product never alters past documents. The `revenue_category` (goods/service/accommodation) is distinct from `product_category_id` (internal custom organisation).

Key facts

  • `products` + `product_categories`, scope (tenant_id, sub_tenant_id)
  • Line with `product_id` → autofill desc/price/VAT/unit
  • `save_to_catalog=true` → atomic upsert inside the doc transaction
  • `line.product_id` soft (FK nullOnDelete), emitted snapshot = ISCA truth
  • Fiscal `revenue_category` ≠ `product_category_id` (organisation)
  • Endpoints: `/api/v1/products` and `/api/v1/product-categories`

Code example

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);

See also

Your cookie preferences

We use cookies to improve your experience. Essential cookies are always active. Cookie policy.