Aller au contenu principal

Patterns

Devis, acomptes et facture de solde

Du devis signé à la facture acompte (TVA exigible) puis au solde

Le cycle devis → acompte → solde est un pattern fiscal sensible. Un devis (`quotes`) est hors chaîne ISCA (audit trail SHA-256 séparé). Une fois accepté, il se convertit en facture d'acompte (`invoice_type='deposit'`, code Factur-X 386) : la TVA devient immédiatement exigible (CGI art. 289). Le solde (`invoice_type='balance'`, code 380) déduit automatiquement les acomptes émis via le groupe BG-22 code '80', et sa TVA n'est plus due. Anti-pattern : émettre deux fois le même acompte ou re-numéroter au submit (trou dans la séquence ISCA). Le SDK numérote en DRAFT- provisoire et n'attribue le numéro définitif qu'à l'émission. On convertit autant d'acomptes que nécessaire (`convertToDeposit`, N fois) mais un seul solde (`convertToBalance`).

À retenir

  • Devis : chaîne d'audit SHA-256 séparée de l'ISCA fiscale
  • Acompte = type Factur-X 386, TVA exigible immédiatement (CGI 289)
  • Solde = type 380, déduction auto des acomptes (BG-22 code '80')
  • N acomptes possibles, 1 seul solde par devis
  • Lien public signable : `quotes.send()` / `regeneratePublicLink()` → `public_link`
  • Aperçu PDF sans persistance : `POST /quotes/preview`

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 devis (hors chaîne ISCA)
const { data: quote } = await client.quotes.create({
  issue_date: '2026-06-15',
  valid_until: '2026-07-15',
  currency: 'EUR',
  buyer_name: 'Acme SARL',
  buyer_siret: '98765432109876',
  buyer_country: 'FR',
  buyer_address: { line1: '2 av. Demo', postal_code: '69001', city: 'Lyon', country: 'FR' },
  total_ht: 5000, total_tax: 1000, total_ttc: 6000,
  signature_required: true,
  lines: [{ description: 'Prestation conseil', quantity: 1, unit_price: 5000, vat_rate: 20, total_ht: 5000, total_tax: 1000, total_ttc: 6000 }],
});

// 2. Aperçu PDF non persisté (avant envoi)
const pdf = await client.quotes.preview({
  issue_date: '2026-06-15', valid_until: '2026-07-15',
  buyer_name: 'Acme SARL', buyer_country: 'FR',
  total_ht: 5000, total_tax: 1000, total_ttc: 6000,
  lines: [{ description: 'Conseil', quantity: 1, unit_price: 5000, vat_rate: 20, total_ht: 5000, total_tax: 1000, total_ttc: 6000 }],
});

// 3. Envoyer le devis → lien public signable
const { public_link } = await client.quotes.send(quote.id, { send_email: true });
console.log('Lien client :', public_link);

// 4. Acompte 30 % (TVA exigible — Factur-X 386)
const { data: deposit } = await client.quotes.convertToDeposit(quote.id, {
  deposit_percent: 30,
  output_format: 'facturx',
  due_date: '2026-07-01',
});
console.log('Acompte :', deposit.invoice_number);

// 5. Solde (déduit l'acompte — Factur-X 380)
const { data: balance } = await client.quotes.convertToBalance(quote.id, {
  due_date: '2026-08-01',
  output_format: 'facturx',
});
console.log('Solde :', balance.invoice_number);

Voir aussi

Vos préférences cookies

Nous utilisons des cookies pour améliorer votre expérience. Les cookies essentiels sont toujours actifs. Politique cookies.