11. Cycle de vie d’une facture
Observé — journal de solde / prévisualisation & paiement d’une facture sur compte locatif (createRentalAccountInvoice → gel → paiement → rattachement → verrouillage).
Pourquoi
Facturer un terme de loyer (et charges), enregistrer l’encaissement, rattacher le paiement à la facture, puis verrouiller le document une fois payé.
Prérequis
- Compte locatif (
accountId/rentalAccountId) - Modèle de facture (
accountingInvoiceConfigId) - Opérations comptables pour les lignes (
operationId) - Codes TVA :
vatCodeIdetvatExemptionCodeIdsur chaqueinvoiceItem(aujourd’hui optionnels dans le schéma, prévus obligatoires — résolvez-les vialistVatCodes/listVatExemptionCodes) - Montants en centimes d’euro (ex.
60000= 600,00 €)
Résoudre les codes TVA
query listVatCodes {
listVatCodes { id code label }
}
query listVatExemptionCodes($vatCodeId: UUID) {
listVatExemptionCodes(vatCodeId: $vatCodeId) { id code legalReason }
}
11.1 Créer la facture (createRentalAccountInvoice)
- GraphQL
- Node.js
- curl
mutation createRentalAccountInvoice($accountId: UUID!, $rentalAccountInvoice: RentalAccountInvoiceInput!) {
createRentalAccountInvoice(accountId: $accountId, rentalAccountInvoice: $rentalAccountInvoice) {
id
invoices {
id
insertedAt
}
}
}
{
"accountId": "00000000-0000-4000-8000-000000000001",
"rentalAccountInvoice": {
"accountingInvoiceConfigId": "00000000-0000-4000-8000-000000000002",
"dueDate": "2026-08-03",
"term": "2026-08",
"nature": "standard",
"invoiceItems": [
{
"amount": 60000,
"operationId": "00000000-0000-4000-8000-000000000003",
"vatCodeId": "00000000-0000-4000-8000-000000000201",
"vatExemptionCodeId": "00000000-0000-4000-8000-000000000202",
"vatRate": 0,
"vatMention": "not_applicable",
"vatSpecific": "accounting"
},
{
"amount": 5000,
"operationId": "00000000-0000-4000-8000-000000000004",
"vatCodeId": "00000000-0000-4000-8000-000000000203",
"vatExemptionCodeId": "00000000-0000-4000-8000-000000000204",
"vatRate": 1000,
"vatMention": "intermediate",
"vatSpecific": "accounting"
}
],
"referencedCreditNoteId": null,
"referencedInvoiceId": null,
"referencedDocumentIdentifier": null,
"type": "invoice"
}
}
import { ublo } from '../ubloClient.mjs';
const data = await ublo(
`mutation createRentalAccountInvoice($accountId: UUID!, $rentalAccountInvoice: RentalAccountInvoiceInput!) {
createRentalAccountInvoice(accountId: $accountId, rentalAccountInvoice: $rentalAccountInvoice) {
id
invoices { id }
}
}`,
{
accountId: '00000000-0000-4000-8000-000000000001',
rentalAccountInvoice: {
accountingInvoiceConfigId: '00000000-0000-4000-8000-000000000002',
dueDate: '2026-08-03',
term: '2026-08',
nature: 'standard',
invoiceItems: [
{
amount: 60000,
operationId: '00000000-0000-4000-8000-000000000003',
vatCodeId: '00000000-0000-4000-8000-000000000201',
vatExemptionCodeId: '00000000-0000-4000-8000-000000000202',
vatRate: 0,
vatMention: 'not_applicable',
vatSpecific: 'accounting',
},
{
amount: 5000,
operationId: '00000000-0000-4000-8000-000000000004',
vatCodeId: '00000000-0000-4000-8000-000000000203',
vatExemptionCodeId: '00000000-0000-4000-8000-000000000204',
vatRate: 1000,
vatMention: 'intermediate',
vatSpecific: 'accounting',
},
],
type: 'invoice',
},
},
);
const invoiceId = data.createRentalAccountInvoice.invoices[0].id;
- Bearer
- Cookie session
curl -sS -X POST "$UBLO_GRAPHQL_URL" \
-H "Authorization: Bearer $UBLO_API_TOKEN" \
-H 'Content-Type: application/json' \
-d @- <<'EOF'
{
"query": "mutation createRentalAccountInvoice($accountId: UUID!, $rentalAccountInvoice: RentalAccountInvoiceInput!) { createRentalAccountInvoice(accountId: $accountId, rentalAccountInvoice: $rentalAccountInvoice) { id invoices { id } } }",
"variables": {
"accountId": "00000000-0000-4000-8000-000000000001",
"rentalAccountInvoice": {
"accountingInvoiceConfigId": "00000000-0000-4000-8000-000000000002",
"dueDate": "2026-08-03",
"term": "2026-08",
"nature": "standard",
"invoiceItems": [
{
"amount": 60000,
"operationId": "00000000-0000-4000-8000-000000000003",
"vatCodeId": "00000000-0000-4000-8000-000000000201",
"vatExemptionCodeId": "00000000-0000-4000-8000-000000000202",
"vatRate": 0,
"vatMention": "not_applicable",
"vatSpecific": "accounting"
},
{
"amount": 5000,
"operationId": "00000000-0000-4000-8000-000000000004",
"vatCodeId": "00000000-0000-4000-8000-000000000203",
"vatExemptionCodeId": "00000000-0000-4000-8000-000000000204",
"vatRate": 1000,
"vatMention": "intermediate",
"vatSpecific": "accounting"
}
],
"type": "invoice"
}
}
}
EOF
curl -sS -X POST "$UBLO_GRAPHQL_URL" \
-H 'Content-Type: application/json' \
-b cookies.txt \
-d @- <<'EOF'
{
"query": "mutation createRentalAccountInvoice($accountId: UUID!, $rentalAccountInvoice: RentalAccountInvoiceInput!) { createRentalAccountInvoice(accountId: $accountId, rentalAccountInvoice: $rentalAccountInvoice) { id invoices { id } } }",
"variables": {
"accountId": "00000000-0000-4000-8000-000000000001",
"rentalAccountInvoice": {
"accountingInvoiceConfigId": "00000000-0000-4000-8000-000000000002",
"dueDate": "2026-08-03",
"term": "2026-08",
"nature": "standard",
"invoiceItems": [
{
"amount": 60000,
"operationId": "00000000-0000-4000-8000-000000000003",
"vatCodeId": "00000000-0000-4000-8000-000000000201",
"vatExemptionCodeId": "00000000-0000-4000-8000-000000000202",
"vatRate": 0,
"vatMention": "not_applicable",
"vatSpecific": "accounting" },
{
"amount": 5000,
"operationId": "00000000-0000-4000-8000-000000000004",
"vatCodeId": "00000000-0000-4000-8000-000000000203",
"vatExemptionCodeId": "00000000-0000-4000-8000-000000000204", "vatRate": 1000,
"vatMention": "intermediate", "vatSpecific": "accounting"
}
],
"type": "invoice"
}
}
}
EOF
11.2 Geler la facture (freezeRentalAccountInvoiceV2)
remarque
Dans l’UI admin, le document GraphQL peut s’appeler autrement.
mutation freezeRentalAccountInvoiceV2($id: UUID!, $accountId: UUID!) {
freezeRentalAccountInvoiceV2(id: $id, accountId: $accountId) {
id
}
}
{
"id": "00000000-0000-4000-8000-000000000005",
"accountId": "00000000-0000-4000-8000-000000000001"
}
- Bearer
- Cookie session
# payload.json = query + variables ci-dessus
curl -sS -X POST "$UBLO_GRAPHQL_URL" \
-H "Authorization: Bearer $UBLO_API_TOKEN" \
-H 'Content-Type: application/json' \
-d @payload.json
curl -sS -X POST "$UBLO_GRAPHQL_URL" \
-H 'Content-Type: application/json' \
-b cookies.txt \
-d @payload.json
11.3 Créer la transaction de paiement (createTransaction)
Montant observé : 65500 (650,00 € TTC des deux lignes).
- GraphQL
- Node.js
- curl
mutation createTransaction($accountId: UUID!, $rentalAccountTransaction: RentalAccountTransactionInput!) {
createTransaction(accountId: $accountId, rentalAccountTransaction: $rentalAccountTransaction) {
id
transactions {
id
amount
remainingAmount
state
}
}
}
{
"accountId": "00000000-0000-4000-8000-000000000001",
"rentalAccountTransaction": {
"sourceAccountId": "00000000-0000-4000-8000-000000000006",
"operationId": "00000000-0000-4000-8000-000000000007",
"paymentMethod": "bank_transfer",
"amount": 65500,
"date": "2026-08-03"
}
}
const { createTransaction: account } = await ublo(
`mutation createTransaction($accountId: UUID!, $rentalAccountTransaction: RentalAccountTransactionInput!) {
createTransaction(accountId: $accountId, rentalAccountTransaction: $rentalAccountTransaction) {
id
transactions { id amount remainingAmount state }
}
}`,
{
accountId: '00000000-0000-4000-8000-000000000001',
rentalAccountTransaction: {
sourceAccountId: '00000000-0000-4000-8000-000000000006',
operationId: '00000000-0000-4000-8000-000000000007',
paymentMethod: 'bank_transfer',
amount: 65500,
date: '2026-08-03',
},
},
);
const transactionId = account.transactions.at(-1).id;
- Bearer
- Cookie session
# payload.json = query + variables de l’onglet GraphQL
curl -sS -X POST "$UBLO_GRAPHQL_URL" \
-H "Authorization: Bearer $UBLO_API_TOKEN" \
-H 'Content-Type: application/json' \
-d @payload.json
curl -sS -X POST "$UBLO_GRAPHQL_URL" \
-H 'Content-Type: application/json' \
-b cookies.txt \
-d @payload.json
11.4 Rattacher le paiement à la facture (updateInvoiceTransactions)
remarque
Dans l’UI admin, le document GraphQL peut s’appeler autrement.
mutation updateInvoiceTransactions(
$accountId: UUID!
$invoiceId: UUID!
$content: RentalAccountInvoiceTransactionsInput!
) {
updateInvoiceTransactions(accountId: $accountId, invoiceId: $invoiceId, content: $content) {
id
}
}
{
"accountId": "00000000-0000-4000-8000-000000000001",
"invoiceId": "00000000-0000-4000-8000-000000000005",
"content": {
"invoiceTransactions": [
{
"transactionId": "00000000-0000-4000-8000-000000000008",
"amount": 65500
}
]
}
}
11.5 Verrouiller la facture payée (lockPaidInvoice)
mutation lockPaidInvoice($id: UUID!, $accountId: UUID!) {
lockPaidInvoice(accountId: $accountId, id: $id) {
id
}
}
{
"id": "00000000-0000-4000-8000-000000000005",
"accountId": "00000000-0000-4000-8000-000000000001"
}
11.6 Optionnel — Déverrouiller (unlockInvoice)
mutation unlockInvoice($id: UUID!, $accountId: UUID!) {
unlockInvoice(accountId: $accountId, id: $id) {
id
}
}