spb/air Public MIT
AIR — The Language of Accounting.
Python 100%
1# =============================================================================2# Projet : AIR — Accounting Intermediate Representation3# Auteur : Simon-Pierre Boucher4# Contact : contact@spboucher.ai5# Fichier : base.py6# Description : Common Backend interface — capabilities / compile / post / reverse.7# =============================================================================8"""Backend interface (the LLVM target abstraction).910A backend lowers a CompiledJournal into a target payload (CSV rows, QBO11JournalEntry JSON, Xero ManualJournal, the native ledger...) and posts it.12Design informed by docs/research/erp-apis.md:13- amounts are unsigned Decimals + a debit/credit side (the canonical form14 every surveyed API can be derived from);15- post() takes an idempotency key — retries must never double-post;16- reversal is a first-class operation (strategies vary by target: native,17 void, or contra entry) — posted entries are NEVER deleted.18"""19from __future__ import annotations2021import abc22from dataclasses import dataclass, field23from typing import Any2425from core.journal import CompiledJournal262728@dataclass(frozen=True, slots=True)29class BackendCapabilities:30 name: str31 posts_remotely: bool # False: file/local targets32 native_reversal: bool # target supports reversal natively33 multi_currency: bool34 idempotency: str # "native" | "external-id" | "client-side"35 notes: str = ""363738@dataclass(frozen=True, slots=True)39class TargetPayload:40 """What compile() produces: target-shaped data, not yet posted."""4142 backend: str43 format: str # e.g. "csv", "json", "qbo.journalentry"44 body: Any # backend-specific representation454647@dataclass(frozen=True, slots=True)48class PostingReceipt:49 backend: str50 reference: str # file path, remote id, ledger sequence...51 idempotency_key: str52 details: dict[str, str] = field(default_factory=dict)535455@dataclass(frozen=True, slots=True)56class ReversalReceipt:57 backend: str58 reference: str59 reversed_reference: str606162class Backend(abc.ABC):63 """Every AIR target implements this interface."""6465 @abc.abstractmethod66 def capabilities(self) -> BackendCapabilities: ...6768 @abc.abstractmethod69 def compile(self, journal: CompiledJournal) -> TargetPayload: ...7071 @abc.abstractmethod72 def post(self, payload: TargetPayload, idempotency_key: str) -> PostingReceipt: ...7374 @abc.abstractmethod75 def reverse(self, receipt: PostingReceipt) -> ReversalReceipt: ...76