SPB Git

spb/air Public MIT

AIR — The Language of Accounting.

Python 100%
2.5 KB · 76 lines python
Raw Blame History
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