Il s’agit de la plongée profonde en version longue. Pour une version plus rapide et lisible, consultez le article de blog compagnon.
1. Pourquoi j'ai construit ça
Chaque petite entreprise britannique dont le chiffre d'affaires imposable dépasse le seuil d'enregistrement VAT doit calculer et soumettre une déclaration VAT - généralement trimestrielle - via le service Making Tax Digital (MTD) de HMRC. Neuf cases numérotées. Sortie VAT moins entrée VAT. Payez le montant net ou demandez le remboursement. Facile en théorie ; punissant en pratique lorsque vos factures résident dans Postgres, vos reçus de dépenses sont des PDF provenant d'une vingtaine de fournisseurs différents, vos relevés bancaires sont au format CSV de Wise et Revolut et vos lignes en devises doivent être retraitées en livres au bon taux mensuel.
Pendant quelques années, je me suis débrouillé avec une feuille de calcul géante, un rappel de calendrier et un petit acte de foi. Chaque trimestre prenait environ une demi-journée, dont la majeure partie était consacrée à la gestion des données : exporter un fichier CSV à partir de la base de données des factures, le coller dans Excel, classer manuellement quelques centaines de lignes, revérifier les formules, copier neuf nombres dans un pont MTD tiers, cliquer sur Soumettre. La piste d'audit était "croyez-moi, j'avais une feuille de calcul". Les changements de taux au milieu du trimestre l’ont brisé. Les reçus ont disparu. Un classement mal placé pourrait pousser Box 5 de plusieurs centaines de livres.
J'ai reconstruit le pipeline cette année en tant que petit Claude Code projet qui communique directement avec ma base de données de factures et de dépenses, classe chaque ligne, calcule Box 1 en Box 9 avec un moteur Python déterministe, exécute à sec le retour sous forme de rapport Markdown, et seulement après la signature d'un humain, le soumet à HMRC MTD. Le trimestre entier me prend maintenant environ une heure, dont la majeure partie est consacrée à la révision des essais avec mon comptable. La piste d'audit est un dépôt git. Les mathématiques sont testées unitairement. Le classificateur est un fichier Markdown documenté. La soumission est fermée.
Cet article est la version longue. Invites, Python, schéma, flux HMRC OAuth, cas extrêmes. Si vous voulez d'abord la version courte, lisez le blog compagnon.
2. Introduction à HMRC MTD (et clause de non-responsabilité)
Making Tax Digital pour VAT est l'exigence de HMRC selon laquelle les entreprises enregistrées sous VAT conservent des enregistrements numériques et soumettent leurs déclarations via un logiciel compatible via un API documenté plutôt que de saisir des chiffres dans le formulaire Web gov.uk. Le API est OAuth2, nécessite des en-têtes HTTP anti-fraude identifiant le périphérique d'origine et est disponible dans un bac à sable gratuit avant même de toucher à la production en direct.
Le retour lui-même est de neuf cases : Box 1 est VAT dû sur les ventes et autres sorties ; Box 2 est VAT dû sur les acquisitions de biens en provenance des États membres de l'UE (pertinent pour les entreprises d'Irlande du Nord dans le cadre du protocole NI) ; Box 3 est le total de VAT dû (Box 1 + Box 2) ; Box 4 est VAT récupérable sur les achats (saisissez VAT) ; Box 5 est le VAT net à payer ou à récupérer (Box 3 - Box 4) ; Box 6 correspond aux ventes totales hors VAT ; Box 7 correspond au total des achats hors VAT ; Box 8 représente la valeur totale des marchandises fournies aux États membres de l'UE (encore une fois, NI uniquement) ; Box 9 correspond à la valeur totale des acquisitions provenant des États membres de l'UE (NI uniquement). Il existe des variantes de régime - régime forfaitaire, comptabilité de caisse, comptabilité annuelle - qui changent comment vous arrivez aux chiffres mais pas à la forme de la boîte.
Clause de non-responsabilité. Je suis ingénieur logiciel, pas expert-comptable. Cet article est pas de conseils fiscaux. Les règles exactes de la classification VAT, de l'exonération partielle, du régime forfaitaire, des règles sur le lieu de fourniture des services numériques, du traitement post-Brexit des biens et services de l'UE et du protocole NI changent toutes au fil du temps et dépendent de votre situation spécifique. Avant d'exécuter quelque chose de ce genre sur un vrai compte HMRC, demandez à un comptable enregistré au Royaume-Uni d'examiner votre première déclaration de bout en bout. Pour connaître la règle faisant autorité sur tout cas limite spécifique, consultez l'avis HMRC VAT 700 et les avis associés sur le site Web gov.uk. Le coût d'une heure du temps de votre comptable est bien inférieur au coût d'une mauvaise soumission.
3. Le modèle de données
Tout en aval dépend de la forme de deux tableaux : les factures émises (ventes) et les dépenses enregistrées (achats). Je garde le mien dans Postgres mais la même forme fonctionne sur MySQL ou SQLite. Le schéma minimum utile :
CREATE TABLE invoices (
id BIGSERIAL PRIMARY KEY,
invoice_number TEXT NOT NULL UNIQUE,
issued_at DATE NOT NULL,
customer_name TEXT NOT NULL,
customer_vat_no TEXT,
customer_country CHAR(2) NOT NULL,
net_amount NUMERIC(14,2) NOT NULL,
vat_amount NUMERIC(14,2) NOT NULL,
gross_amount NUMERIC(14,2) NOT NULL,
currency CHAR(3) NOT NULL DEFAULT 'GBP',
fx_rate_to_gbp NUMERIC(18,8) NOT NULL DEFAULT 1,
vat_rate NUMERIC(5,2) NOT NULL,
vat_treatment TEXT NOT NULL,
status TEXT NOT NULL,
paid_at DATE,
notes TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE expenses (
id BIGSERIAL PRIMARY KEY,
supplier_name TEXT NOT NULL,
supplier_vat_no TEXT,
supplier_country CHAR(2) NOT NULL,
incurred_at DATE NOT NULL,
net_amount NUMERIC(14,2) NOT NULL,
vat_amount NUMERIC(14,2) NOT NULL,
gross_amount NUMERIC(14,2) NOT NULL,
currency CHAR(3) NOT NULL DEFAULT 'GBP',
fx_rate_to_gbp NUMERIC(18,8) NOT NULL DEFAULT 1,
vat_rate NUMERIC(5,2) NOT NULL,
vat_treatment TEXT NOT NULL,
category TEXT NOT NULL,
receipt_url TEXT,
notes TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
Les colonnes non évidentes sont vat_treatment, fx_rate_to_gbp, et les codes pays. Le traitement est une petite énumération utilisée à la fois par le classificateur et par le moteur ; le code du pays détermine la logique d'autoliquidation et d'acquisition dans l'UE ; Le taux de change vous permet de conserver les factures en devises dans leur devise d'origine tout en les ré-étatisant dans GBP pour les totaux des boîtes.
| Colonne | But | Utilisé par |
|---|---|---|
vat_treatment | standard / réduit / zéro / exonéré / hors champ d'application / autoliquidation / biens européens / services européens / importation reportée | classificateur + moteur |
vat_rate | 0,00, 5,00, 20,00 (ou tarif spécifique au régime) | moteur + somme de contrôle |
currency + fx_rate_to_gbp | retraitement multidevises | normalisateur |
customer_country / supplier_country | autoliquidation, protocole NI, lieu de fourniture | classificateur |
paid_at | branche du système de comptabilité de caisse | moteur |
Le remplissage de ces colonnes sur une ancienne table de factures est la partie la plus lente du projet. Claude Code peut générer la migration ; vous devez toujours classer manuellement les cas extrêmes délicats.
4. Pourquoi Claude Code (et non Xero/QuickBooks/FreeAgent)
Pour la plupart des petites entreprises britanniques, la réponse est – véritablement – d’utiliser des logiciels packagés. Xero, QuickBooks, FreeAgent, Sage ont tous une soumission MTD certifiée HMRC, des interfaces utilisateur décentes et des comptables qui les connaissent déjà. Vous ne devez pas déployer votre propre système VAT sauf si vous avez une raison claire.
Mes raisons étaient étroites mais réelles. J'utilise déjà Claude Code tous les jours pour le travail logiciel, donc l'effort marginal pour l'utiliser également pour VAT était faible. Ma base de données de factures réside sur ma propre machine ; Je préfère qu'il ne soit pas reflété dans un locataire SaaS. Ma combinaison de fournisseurs est délicate (services de l'UE avec autoliquidation, importation VAT reportée, cas extrêmes occasionnels détaxés) et l'encodage des règles dans un seul fichier Markdown plus un module Python s'est avéré plus rapide que la configuration d'un SaaS pour les gérer. Et la piste d'audit que je reçois d'un dépôt git - chaque invite de classificateur, chaque différence, chaque instantané de période signé - est exactement la piste d'audit que je souhaite.
Claude Code s’y prête bien pour trois raisons. Premièrement, il fonctionne directement sur un projet sur disque : il peut lire mon schéma, les rapports d'exécution à sec du trimestre précédent, le fichier de règles et le moteur Python, et proposer des modifications en contexte. Deuxièmement, il est bon pour les échafaudages ennuyeux : scripts de migration, importateurs CSV, rapports de réconciliation, appareils pytest. Troisièmement, lorsqu'il classe une ligne, il explique son raisonnement dans un anglais simple, ce qui est exactement ce que je souhaite revoir avant de signer la déclaration. La matrice de décision au bas du diagramme de flux de travail ci-dessous est la version honnête de ce compromis.
5. Architecture et flux de travail
Le pipeline comporte cinq couloirs de nage. Source est un accès en lecture seule aux factures et aux tableaux de dépenses ainsi qu'à un dossier de dépôt pour CSV à partir de Stripe, Wise et des flux bancaires. Ingérer + Normaliser est un petit script Python généré par Claude qui mappe chaque schéma source en une seule vue canonique, convertit les devises étrangères en GBP au taux mensuel HMRC, applique un filtre de plage de dates et marque chaque ligne avec un idempotent. run_key les rediffusions sont donc sûres. Catégoriser + Réconcilier est le classificateur Claude Code : il parcourt chaque ligne canonique, sélectionne un vat_treatment à partir de l'énumération documentée en utilisant les règles dans vat-rules.md, rapproche les factures avec les paiements et signale les anomalies (net négatif, numéro VAT du fournisseur manquant, incompatibilité de code de pays, fournisseurs qui devraient être enregistrés VAT mais ne le sont pas). Moteur VAT est un module Python pur qui lit les lignes classées et calcule Box 1 en Box 9 de manière déterministe ; les branches des régimes forfaitaires, en espèces et annuels sont des chemins de codes explicites. Soumettre + Audit est l'appel HMRC MTD API (OAuth2, en-têtes de prévention de la fraude, bac à sable d'abord), contrôlé par une étape d'approbation humaine, avec l'instantané de la période signé et le journal complet du classificateur écrit dans un dossier d'audit en annexe uniquement conservé pendant six ans.
6. Construction étape par étape avec Claude Code
C'est le flux de travail que j'ai réellement utilisé. Cinq invites. Je les ai nettoyés pour cet article ; les originaux sont plus compliqués.
Invite 1 - normalisateur. "Regardez le invoices et expenses tableaux dans schema.sql. Générer un module Python normalise.py qui lit les deux tables en utilisant psycopg (rôle en lecture seule vat_reader), se limite à la plage de dates 2026-01-01 à 2026-03-31, et émet une liste de dictées canoniques avec des clés : id, source, date, party, gross, net, vat_amount, vat_rate, vat_treatment, country, currency, fx_rate, run_key. Utiliser Decimal, pas flotter. Incluez une docstring et un __main__ bloc qui imprime un résumé."
Claude a renvoyé un module propre avec Decimal, SQL paramétré, un build_run_key() qui hache (period_start, period_end, Schema, schema_version) en une chaîne hexadécimale stable et une CLI basée sur les clics. J'ai édité deux noms de champs et accepté le reste.
Invite 2 - classificateur. "Lire vat-rules.md et écrire classify.py. Pour chaque ligne canonique de normalise.py, ensemble vat_treatment à l'un des : standard, réduit, zéro, exempter, hors-portée, autoliquidation, produits européens, services européens, importation reportée. Si la ligne a déjà un non vide vat_treatment, laissez-le tranquille et enregistrez-le comme conservé. Sinon, choisissez le code du pays, le numéro VAT du fournisseur, la catégorie et le montant, et écrivez une phrase. reason sur chaque rangée. Les anomalies (net négatif, fournisseur VAT manquant pour un fournisseur britannique au-dessus du seuil d'enregistrement, inadéquation des pays) sont transférées dans une section distincte. anomalies.json pour un examen humain. Ne modifiez pas la base de données source."
Le classificateur lui-même est une petite fonction, principalement basée sur des règles, avec une branche soutenue par LLM pour les catégories de dépenses ambiguës. Surtout, il n'écrit jamais dans la base de données source - il émet un fichier JSON classifié que le moteur lit. Si je ne suis pas d'accord avec une classification, j'édite le JSON ; le prochain essai à sec le récupère.
Invite 3 - moteur. "Écrire engine.py en fonction pure : def compute_boxes(rows: list[Row], scheme: Scheme) -> BoxTotals. Aucune E/S. Pas de LLM. BoxTotals est une classe de données gelée avec Box 1 à Box 9 comme Decimal valeurs à 2 dp. Ajouter des branches explicites pour standard, flat_rate, cash, et annual schémas. Le schéma standard est la comptabilité d'exercice : les ventes de VAT contribuent à Box 1, l'achat de VAT à Box 4. Les factures d'autoliquidation s'ajoutent à la fois au Box 1 et au Box 4. L'importation reportée de VAT s'ajoute à la fois à Box 1 et à Box 4. Les acquisitions européennes pour les activités NI se font dans Box 2 et Box 9. Arrondissez aux totaux de la boîte, jamais par ligne. Écrivez une doctrine reliant chaque branche à sa règle.
Invite 4 - rapport d'essai à sec. "Écrire dryrun.py qui appelle compute_boxes() et émet un rapport Markdown : en-tête avec période et schéma, un tableau de Box 1 à Box 9 avec les étiquettes canoniques, une section par compartiment de classificateur répertoriant les 10 premières lignes par brut, une section d'anomalies et un pied de page avec le run_key et un SHA-256 du JSON classifié. Enregistrer dans ./audit/<period>/dryrun.md."
Invite 5 - émetteur. "Écrire submit.py contre le HMRC MTD VAT API v1.0. Utilisez le flux OAuth2 authorisation_code avec PKCE. Lire le jeton d'accès depuis ~/.vat/token.json; actualiser si expiré. En-têtes de prévention de la fraude requis tels que documentés par HMRC ; tire-les de fraud_headers.py. Par défaut, le bac à sable https://test-api.service.hmrc.gov.uk. Mesures: GET /organisations/vat/{vrn}/obligations?status=O, rechercher la période correspondante, demander à l'opérateur de confirmer en affichant le résumé de la simulation, puis POST /organisations/vat/{vrn}/returns avec finalised: true. Imprimez le receiptId. N'appelez jamais en direct à moins que HMRC_ENV=live est défini et les types d'opérateurs SOUMETTRE."
Cinq invites, quatre fichiers et un petit document de règles Markdown. Le temps total de construction était peut-être d'une semaine de soirées ciblées, dont la plupart étaient les règles du classificateur et la danse HMRC OAuth.
7. Le moteur VAT
Le moteur est la partie délibérément ennuyeuse. C'est une fonction pure avec des tests unitaires et sans IA. Voici la forme réelle :
from dataclasses import dataclass
from decimal import Decimal, ROUND_HALF_UP
D2 = Decimal("0.01")
@dataclass(frozen=True)
class BoxTotals:
box1: Decimal
box2: Decimal
box3: Decimal
box4: Decimal
box5: Decimal
box6: Decimal
box7: Decimal
box8: Decimal
box9: Decimal
def _q(x: Decimal) -> Decimal:
return x.quantize(D2, rounding=ROUND_HALF_UP)
def compute_boxes(rows, scheme="standard", is_ni_business=False) -> BoxTotals:
box1 = box2 = box4 = Decimal(0)
box6 = box7 = box8 = box9 = Decimal(0)
for r in rows:
gbp_net = r.net * r.fx_rate
gbp_vat = r.vat_amount * r.fx_rate
if r.source == "invoice":
box6 += gbp_net
if r.vat_treatment in ("standard", "reduced"):
box1 += gbp_vat
elif r.vat_treatment == "eu-goods" and is_ni_business:
box8 += gbp_net
else:
box7 += gbp_net
if r.vat_treatment in ("standard", "reduced"):
box4 += gbp_vat
elif r.vat_treatment == "reverse-charge":
notional = gbp_net * (r.vat_rate / Decimal(100))
box1 += notional
box4 += notional
elif r.vat_treatment == "postponed-import":
notional = gbp_net * (r.vat_rate / Decimal(100))
box1 += notional
box4 += notional
elif r.vat_treatment == "eu-goods" and is_ni_business:
notional = gbp_net * (r.vat_rate / Decimal(100))
box2 += notional
box4 += notional
box9 += gbp_net
box3 = box1 + box2
box5 = box3 - box4
return BoxTotals(
_q(box1), _q(box2), _q(box3), _q(box4), _q(box5),
_q(box6), _q(box7), _q(box8), _q(box9),
)
Deux choses à noter. Tout d’abord, le total de chaque boîte est quantifié une fois à la fin. L'arrondi par ligne perd des centimes et HMRC ne pardonne pas les totaux qui ne se rapprochent pas. Deuxièmement, le moteur est entièrement déterministe : même entrée, même sortie, à chaque fois. C'est la propriété qui me permet de le tester unitairement et de faire confiance au test à sec.
def test_simple_quarter():
rows = [
Row("invoice", net=Decimal("24500.00"), vat_amount=Decimal("4900.00"),
vat_rate=Decimal("20"), vat_treatment="standard", fx_rate=Decimal(1), source="invoice"),
Row("expense", net=Decimal("3000.00"), vat_amount=Decimal("600.00"),
vat_rate=Decimal("20"), vat_treatment="standard", fx_rate=Decimal(1), source="expense"),
]
t = compute_boxes(rows)
assert t.box1 == Decimal("4900.00")
assert t.box4 == Decimal("600.00")
assert t.box5 == Decimal("4300.00")
assert t.box6 == Decimal("24500.00")
assert t.box7 == Decimal("3000.00")
Une fois cela en place, chaque régression est capturée dans CI avant même qu'elle ne touche le rapport d'essai à sec. Claude peut m'aider à passer d'autres tests ; il ne peut pas changer le moteur sans que ces tests soient réussis.
8. Vidéo de démonstration
Vous trouverez ci-dessous une brève présentation du pipeline exécuté de bout en bout sur une base de données réelle (anonymisée) de factures et de dépenses pour un trimestre : normalisation, classification, essai à sec, puis soumission MTD au bac à sable. La boucle entière dure quelques minutes.
9. Soumission HMRC MTD
C’est la partie que la plupart des articles passent sous silence. Le MTD VAT API lui-même est bien documenté et gratuit, mais il y a trois choses que vous devez faire avant d'appeler POST returns.
OAuth2 et jetons. Enregistrez une application dans le hub des développeurs HMRC ; vous obtenez un ID client, un secret client et un URI de redirection. Le flux est autorisation_code avec PKCE : ouvrez le navigateur sur la page de consentement HMRC, l'utilisateur se connecte avec ses informations d'identification Government Gateway et autorise votre application par rapport à son numéro d'enregistrement VAT (VRN), HMRC redirige avec un code d'autorisation, vous l'échangez contre un jeton d'accès + un jeton d'actualisation. Mettez-les en cache avec des autorisations raisonnables sur le disque. Le jeton d'accès est de courte durée ; le jeton d'actualisation est beaucoup plus long.
En-têtes de prévention de la fraude. HMRC nécessite un ensemble documenté d'en-têtes HTTP identifiant le périphérique d'origine à chaque appel API : fuseau horaire, géométrie de l'écran, identifiants utilisateur, adresse IP publique, adresses MAC, méthode de connexion client, etc. La liste exacte et le format se trouvent dans la documentation du développeur HMRC (voir l'avis HMRC VAT 700 et les spécifications de prévention de la fraude associées pour la règle faisant autorité). Si vous vous trompez, vous obtenez un 403 avec une vague erreur. Faites-les bien et l’appel passe. Je les garde dedans fraud_headers.py et affirmer leur présence dans les tests.
Bac à sable d'abord. HMRC fournit un bac à sable gratuit sur test-api.service.hmrc.gov.uk avec des stub VRN et des obligations de stub. Exécutez l’intégralité de votre pipeline de bout en bout sur le bac à sable jusqu’à ce que vous ayez soumis une fausse déclaration, reçu un faux identifiant de reçu et confirmé le déplacement de vos obligations. Alors seulement tu retournes HMRC_ENV=live. Mon émetteur refuse d'appeler en direct à moins que la variable d'environnement ne soit définie et que l'opérateur tape SUBMIT à l'invite. Il n'y a pas de chemin d'exécution automatique pour vivre. Le coût d’une seule mauvaise soumission en direct est bien plus élevé que le coût d’une itération sandbox supplémentaire.
L’appel du chemin heureux est court : GET obligations avec status=O pour connaître la période ouverte, afficher le rapport de marche à sec, demander à l'opérateur de confirmer, puis POST returns avec les neuf numéros de boîte, le periodKey de l'obligation, et finalised: true. Enregistrez la réponse, écrivez l’ID du reçu dans le dossier d’audit et vous avez terminé.
10. Sécurité, audit et conformité
Trois règles sur lesquelles je ne m'éloignerai pas. D'abord, Claude n'est pas dans l'arithmétique. Le classificateur suggère des traitements et le LLM peut éditer Python et les règles, mais les totaux des cases sont produits par une fonction pure avec des tests unitaires. "L'IA l'a fait" n'est pas une défense sous MTD. Deuxième, chaque soumission est contrôlée par un humain. Le rapport d’essais à sec est la source de vérité pour l’approbation. Si je ne peux pas expliquer un numéro des lignes classées et le code moteur, je ne le soumets pas. Troisième, la piste d'audit est en annexe uniquement. Chaque JSON classifié, chaque rapport d'essai, chaque invite, chaque différence et l'ID de reçu HMRC final pour la période sont écrits dans ./audit/<period>/ et engagé dans un dépôt git privé. HMRC nécessite six années d'enregistrement ; les miens sont des instantanés signés.
Deux autres pratiques que je vous recommanderais même si vous n'adoptez pas le reste. Exécuter la connexion à la base de données source en tant que rôle en lecture seule avec le moindre privilège : non UPDATE, Non DELETE, Non DROP. Conservez le secret du client HMRC et les jetons d'accès hors du référentiel à l'aide d'un gestionnaire de secrets ou d'un fichier 0600 dans votre répertoire personnel. Le but est de rendre les accidents impossibles par la construction, et pas seulement par la politique.
11. Cas extrêmes
VAT est une taxe réglementée qui a été éditée par tous les gouvernements britanniques depuis 1973, avec une superposition post-Brexit et un protocole d'Irlande du Nord en plus. Les cas limites sont réels. Une liste non exhaustive de ceux gérés par mon moteur :
- Brexit et Irlande du Nord. Les entreprises britanniques ne remplissent plus Box 8 ou Box 9. Les entreprises NI le font toujours pour les biens (et non les services) sous le protocole NI. Le moteur prend
is_ni_businesscomme paramètre et se branche en conséquence. Voir l'avis HMRC VAT 700 pour connaître la règle faisant autorité. - Charge inversée. Les services achetés auprès d'un fournisseur en dehors du Royaume-Uni (et certains services nationaux du secteur de la construction) sont comptabilisés en autoliquidation : vous ajoutez une production notionnelle VAT à Box 1 et récupérez le même montant dans Box 4. L'effet net sur la trésorerie est nul ; l'effet net sur le rendement est celui de deux cases qui bougent ensemble.
- Importation VAT reportée. Pour les marchandises importées de l'extérieur du Royaume-Uni, vous reportez l'importation VAT à votre prochain retour plutôt que de la payer à la frontière. Le traitement ressemble à l’autoliquidation au retour.
- Exonération partielle. Si vous effectuez à la fois des fournitures taxables et exonérées, vous pouvez récupérer l'intrant VAT uniquement dans la mesure où il se rapporte à des fournitures taxables. Il existe des méthodes standards et spéciales ; c'est le coin qui a le plus souvent besoin d'un comptable. N'essayez pas d'encoder des règles d'exemption partielle dans un fichier Markdown.
- Régime forfaitaire. Vous facturez VAT au tarif standard mais payez à HMRC un pourcentage fixe du chiffre d'affaires brut, et vous ne pouvez généralement pas récupérer l'entrée VAT. Le moteur a une branche distincte pour cela et ignore la plupart de la classification par ligne.
- Factures multidevises. Convertissez chaque ligne en GBP au taux en vigueur à la date concernée. HMRC publie les tarifs moyens mensuels ; vous pouvez également utiliser le taux au comptant. Soyez cohérent. Le
fx_rate_to_gbpLa colonne stocke le taux réel appliqué par ligne. - Notes de crédit. Un avoir est une facture négative. Il réduit Box 1 et Box 6 (ou Box 4 et Box 7 s'il s'agit d'un crédit d'achat). Assurez-vous que votre
net_amountetvat_amountpeuvent devenir négatifs et que le moteur les additionne correctement. - Dépôts et paiements échelonnés. Le point d'impôt peut être calculé au moment de la réception de l'acompte et non au moment de l'émission de la facture finale. La comptabilité de caisse peut simplifier cela.
- Modifications des taux au milieu du trimestre. Historiquement rare, mais possible. Stockez le taux par ligne, et non comme une constante globale.
12. Coût
Des chiffres honnêtes. Temps de construction c'était environ une semaine de soirées ciblées - appelez ça 25 à 30 heures. La majeure partie de cela concernait la normalisation des schémas, les règles du classificateur et la rédaction des tests du moteur ; la danse HMRC OAuth était le deuxième plus gros morceau. Coût de fonctionnement par trimestre est petit : mon abonnement Claude Code existant (déjà payé pour d'autres travaux logiciels), quelques centimes d'utilisation du jeton de classificateur et zéro livre pour le HMRC API. Le moteur et le journal d'audit s'exécutent localement sur mon Mac. Temps de révision par trimestre Cela dure environ une heure, principalement consacrée à la lecture des essais avec mon comptable. Comparez cela à environ une demi-journée de travail sur des feuilles de calcul avec l'ancien flux de travail et le temps gagné rembourse le coût de construction au cours de la première année.
Si vous évaluiez cela comme un projet pour lequel vous payiez quelqu'un d'autre, vous seriez dans la fourchette à quatre chiffres en termes de tarifs de conseil - c'est pourquoi un SaaS packagé de vingt à cinquante livres par mois est presque toujours la bonne réponse pour la plupart des entreprises. La question intéressante n’est pas « est-ce moins cher que Xero ? - ce n'est généralement pas le cas - mais "est-ce plus précis, plus vérifiable et plus facile pour moi de raisonner ?". Pour moi, la réponse est oui.
13. Quelle est la prochaine étape et conclusion
Les prochains éléments que je souhaite ajouter sont : l'importation automatique de flux bancaires (Open Banking AISP), l'OCR pour les PDF des fournisseurs afin que l'URL du reçu devienne une véritable ligne numérisée, un flux d'approbation cron + Slack planifié pour que je n'aie pas à me souvenir des délais et une extension d'auto-facturation pour les vendeurs du marché. Aucun de ces éléments ne modifie la forme centrale du pipeline. Ce sont toutes des décorations sur le même diagramme à cinq voies.
La plus grande leçon, du moins pour moi, est la capacité d'un petit projet Claude Code à gérer la moitié ennuyeuse d'un flux de travail réglementé. La moitié ennuyeuse représente l'essentiel du travail : normalisation des schémas, importateurs CSV, rapports de rapprochement, paramètres, règles de cas extrêmes, journalisation d'audit. Claude est excellent dans tout ça. La moitié déterministe - les calculs réels, la soumission réelle - reste en Python simple avec des tests unitaires et une porte d'approbation humaine, exactement à sa place.
Avertissement, encore une fois. Cet article ne constitue pas un conseil fiscal. Avant de pointer quelque chose comme ça sur un vrai compte HMRC, demandez à un comptable enregistré au Royaume-Uni d'examiner votre première déclaration de bout en bout. Exécutez le bac à sable HMRC MTD jusqu'à ce que vous et votre comptable soyez tous les deux confiants. Pour connaître la règle faisant autorité sur tout traitement VAT spécifique, consultez l'avis HMRC VAT 700 et les avis associés sur le site Web gov.uk. Si vous souhaitez la version courte de tout cela, le article de blog compagnon est une lecture de cinq minutes ; sinon, abonnez-vous et je continuerai à écrire à mesure que la pile mûrira.
Aperçu SEO pour cet article
- Titre SEO : Construisez un système de retour VAT avec Claude Code
- Méta description : Utilisez Claude Code pour lire la base de données de vos factures et dépenses, classer VAT, calculer HMRC Box 1 à 9, effectuer un essai à sec, puis soumettre à MTD - moteur déterministe, approbation humaine.
- Mots-clés principaux : claude-code, tva, hmrc, mtd, comptabilité, automatisation, python, ai-agent, finops, petites entreprises
- Twitter / X (moins de 280 caractères) : J'ai reconstruit mon retour VAT au Royaume-Uni en tant que projet Claude Code : factures Postgres + dépenses DB vers HMRC Box 1 vers 9, moteur Python déterministe, soumission MTD en premier bac à sable, porte d'approbation humaine. Rédaction complète + workflow SVG + vidéo de démonstration. Pas de conseils fiscaux. #ClaudeCode #VAT #HMRC #MTD
- Publication LinkedIn : J'ai reconstruit mon retour trimestriel VAT au Royaume-Uni en tant que petit projet Claude Code cette année. Il lit ma base de données de factures et de dépenses en lecture seule, classe chaque ligne par traitement VAT à l'aide d'un fichier de règles documenté, calcule HMRC Box 1 à 9 avec un moteur Python déterministe (pas de LLM dans l'arithmétique), et seulement après avoir signé l'essai à sec, il le soumet via le HMRC MTD API - sandbox d'abord, les en-têtes de prévention de la fraude, le flux OAuth2 complet. Le quart entier prend désormais environ une heure. Un article complet avec les invites, le schéma, le code du moteur, les cas extrêmes et l'histoire honnête des coûts se trouve sur Workstation. Pas de conseils fiscaux ; demandez à un comptable d’examiner votre première déclaration.
