The English Chapel Antananarivo is our home congregation — the English-speaking church the three of us attend on Sundays. It is also, quietly, the most complete thing the workshop has shipped this year: an Odoo 19 board that runs the administration, a Vue 3 website that introduces the chapel, a Nuxt cockpit and Flask API that plan the services and consolidate the slides, and an Expo companion app that puts announcements and lyrics in the congregation's pocket. Five surfaces. One community. The same family wrote them; the same family uses them.
We had to write a Madagascar accounting localisation before we could ship the board. Odoo 19 had no l10n_mg in its base, so we wrote one — the PCG chart of accounts, the taxes (TVA, IRSA, withholding, import VAT), fiscal positions, a fiscal-year model at the company level, and a post-init hook that auto-activates the whole thing for any company whose country is Madagascar. l10n_mg_report adds the statutory documents — Bilan, Compte de Résultat, Tableau des Flux de Trésorerie (direct and indirect), Variation des Capitaux Propres — as both PDF (QWeb) and XLSX (via the OCA report_xlsx engine), with a cron job refreshing the cached values nightly. l10n_mg_tax_form ships the Bordereau de Versement de l'Impôt Synthétique (HETRA TAMBATRA), filled automatically from the Bilan. The chapel needed it. Anyone else with a Malagasy company will, too.
The interesting parts sit where the surfaces meet. eca_offering records each gift against one of five Malagasy payment methods — Espèces, Virement, Mvola, Airtel Money, Orange Money — and posts a journal entry that debits the matching account (531100 / 512100 / 530002 / 530003 / 530004) and credits 756100, Libéralités perçues. References follow OFF/YYYY/NNNN from an `ir.sequence`. Once posted, the record is write-locked except for notes and state — cancellation produces a reversal, not a quiet delete. The mobile-money trio is the half of the country's giving habits a generic localisation would have missed.
The companion app and the worship cockpit close the loop. The announcement module exposes a bearer-auth JSON-RPC controller — because Odoo 19's stock `/web/dataset/call_kw` is session-only and refuses API keys outright — wired against an `ECA Bot` user whose login is `bot@english-chapel-antananarivo.org` and whose API key the mobile app carries. The Flask worship API holds the songs and, for any given service, opens each song's PowerPoint, copies the slides into a single consolidated deck — layouts, backgrounds, placeholder text, font sizes, paragraph alignment — and hands a URL back to the Nuxt cockpit. On Sunday morning the diaporama screen on the companion app projects the resulting deck. None of it requires anyone to be in the same room as a laptop.