ekwo-os 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (361) hide show
  1. package/README.md +873 -0
  2. package/dist/args.d.ts +57 -0
  3. package/dist/args.d.ts.map +1 -0
  4. package/dist/args.js +134 -0
  5. package/dist/args.js.map +1 -0
  6. package/dist/assets/expected-objects.json +9432 -0
  7. package/dist/assets/migrations/20260911120000_core_companies.sql +260 -0
  8. package/dist/assets/migrations/20260911120100_accounts_journals.sql +211 -0
  9. package/dist/assets/migrations/20260911120200_contacts.sql +90 -0
  10. package/dist/assets/migrations/20260911120300_taxes.sql +146 -0
  11. package/dist/assets/migrations/20260911120400_entries.sql +338 -0
  12. package/dist/assets/migrations/20260911120500_documents.sql +279 -0
  13. package/dist/assets/migrations/20260911120600_payments_reconciliation.sql +251 -0
  14. package/dist/assets/migrations/20260911120700_bank.sql +178 -0
  15. package/dist/assets/migrations/20260911120800_analytics_attachments.sql +128 -0
  16. package/dist/assets/migrations/20260911120900_post_document.sql +279 -0
  17. package/dist/assets/migrations/20260911121000_reporting.sql +235 -0
  18. package/dist/assets/migrations/20260911121100_country_templates.sql +226 -0
  19. package/dist/assets/migrations/20260911121200_fec.sql +71 -0
  20. package/dist/assets/migrations/20260911130000_instance.sql +77 -0
  21. package/dist/assets/migrations/20260911130100_instance_members.sql +224 -0
  22. package/dist/assets/migrations/20260911140000_instance_admins.sql +112 -0
  23. package/dist/assets/migrations/20260911160000_tax_posting_templates_unique.sql +17 -0
  24. package/dist/assets/migrations/20260911170000_document_amount_paid.sql +82 -0
  25. package/dist/assets/migrations/20260911173000_post_payment.sql +122 -0
  26. package/dist/assets/migrations/20260911173100_sequence_counters_under_rls.sql +84 -0
  27. package/dist/assets/migrations/20260911183000_country_journal_defaults.sql +143 -0
  28. package/dist/assets/migrations/20260911193853_line_account_defaults.sql +274 -0
  29. package/dist/assets/migrations/20260911195054_products.sql +221 -0
  30. package/dist/assets/migrations/20260911210131_anon_surface.sql +85 -0
  31. package/dist/assets/migrations/20260912074712_country_packs.sql +318 -0
  32. package/dist/assets/migrations/20260912080311_report_code_and_region.sql +198 -0
  33. package/dist/assets/migrations/20260912081014_pack_certification_maintained.sql +31 -0
  34. package/dist/assets/migrations/20260912081015_pack_certification_backfill.sql +16 -0
  35. package/dist/assets/migrations/20260912090407_tax_report_boxes.sql +329 -0
  36. package/dist/assets/migrations/20260912091917_tax_on_base_value.sql +25 -0
  37. package/dist/assets/migrations/20260912091918_tax_engine_columns.sql +776 -0
  38. package/dist/assets/migrations/20260912094412_opening_and_closing.sql +759 -0
  39. package/dist/assets/migrations/20260912095825_charts_of_accounts.sql +326 -0
  40. package/dist/assets/migrations/20260912100412_financial_statements.sql +632 -0
  41. package/dist/assets/migrations/20260912104719_one_formula_evaluator.sql +209 -0
  42. package/dist/assets/migrations/20260912105720_entry_kind_appropriation.sql +26 -0
  43. package/dist/assets/migrations/20260912105721_appropriation_entry_kind.sql +444 -0
  44. package/dist/assets/migrations/20260912111751_document_rules.sql +274 -0
  45. package/dist/assets/migrations/20260912112132_cash_basis_vat_and_fx.sql +1189 -0
  46. package/dist/assets/migrations/20260913074512_modules.sql +493 -0
  47. package/dist/assets/migrations/20260913075903_asset_disposal_roles.sql +47 -0
  48. package/dist/assets/migrations/20260913083216_capabilities.sql +637 -0
  49. package/dist/assets/migrations/20260913083901_company_invitations.sql +262 -0
  50. package/dist/assets/migrations/20260913084402_user_preferences.sql +376 -0
  51. package/dist/assets/migrations/20260913084847_company_profile.sql +261 -0
  52. package/dist/assets/migrations/20260913085436_numbering_reads_the_pack.sql +235 -0
  53. package/dist/assets/migrations/20260913085932_api_keys.sql +303 -0
  54. package/dist/assets/migrations/20260913090216_fiscal_year_bounds.sql +159 -0
  55. package/dist/assets/migrations/20260913092527_entries_import.sql +219 -0
  56. package/dist/assets/migrations/20260913101536_null_safe_guards.sql +188 -0
  57. package/dist/assets/migrations/20260913102115_installer_is_named.sql +462 -0
  58. package/dist/assets/migrations/20260913102758_no_currency_default.sql +138 -0
  59. package/dist/assets/migrations/20260913103355_cash_basis_needs_a_box.sql +453 -0
  60. package/dist/assets/migrations/20260913104014_aged_balance_named_group.sql +79 -0
  61. package/dist/assets/migrations/20260913104232_foreign_key_indexes.sql +144 -0
  62. package/dist/assets/migrations/20260913105120_declared_no_reader.sql +41 -0
  63. package/dist/assets/migrations/20260913111407_pack_languages.sql +223 -0
  64. package/dist/assets/migrations/20260913112233_schema_comments_for_a_reader.sql +27 -0
  65. package/dist/assets/migrations/20260913114535_fec_opening_balances.sql +307 -0
  66. package/dist/assets/migrations/20260914103412_audit_log.sql +509 -0
  67. package/dist/assets/migrations/20260914111907_pack_upgrade.sql +428 -0
  68. package/dist/assets/migrations/20260914120500_rounding_reads_the_currency.sql +206 -0
  69. package/dist/assets/migrations/20260914121200_amounts_round_at_the_currency.sql +2403 -0
  70. package/dist/assets/migrations/20260914134325_schema_version_0_2_0.sql +36 -0
  71. package/dist/assets/migrations/20260914143915_accounts_in_use.sql +428 -0
  72. package/dist/assets/migrations/20260914144731_account_code_frozen.sql +99 -0
  73. package/dist/assets/migrations/20260914151207_schema_grants_its_own_rights.sql +284 -0
  74. package/dist/assets/migrations/20260914152840_pack_upgrade_records_its_own_line.sql +237 -0
  75. package/dist/assets/migrations/20260914163943_declaration_periodicity.sql +349 -0
  76. package/dist/assets/migrations/20260915094000_foreign_services_received.sql +37 -0
  77. package/dist/assets/migrations/20260915094500_mentions_read_a_foreign_service.sql +72 -0
  78. package/dist/assets/migrations/20260915153000_document_shares.sql +568 -0
  79. package/dist/assets/migrations/20260915160000_ec_sales_list.sql +181 -0
  80. package/dist/assets/migrations/20260915161842_pack_sources.sql +56 -0
  81. package/dist/assets/migrations/20260915170500_schema_version_0_3_0.sql +45 -0
  82. package/dist/assets/migrations/20260915174500_a_vat_category_is_a_code.sql +177 -0
  83. package/dist/assets/migrations/20260915180000_document_rule_references.sql +85 -0
  84. package/dist/assets/migrations/20260915181000_territories.sql +342 -0
  85. package/dist/assets/migrations/20260915181500_ec_sales_list_reads_the_territories.sql +222 -0
  86. package/dist/assets/migrations/20260915182000_intracom_triangular.sql +53 -0
  87. package/dist/assets/migrations/20260915182500_a_triangular_supply_says_reverse_charge.sql +99 -0
  88. package/dist/assets/migrations/20260915191200_a_document_knows_its_language.sql +633 -0
  89. package/dist/assets/migrations/20260915195000_a_price_that_holds_its_tax.sql +649 -0
  90. package/dist/assets/migrations/20260915200000_a_posting_names_its_boxes.sql +1004 -0
  91. package/dist/assets/migrations/20260916094500_a_company_files_more_than_one_declaration.sql +795 -0
  92. package/dist/assets/migrations/20260916103000_a_ledger_line_names_its_posting.sql +902 -0
  93. package/dist/assets/migrations/20260916123000_a_vocabulary_for_a_tax_that_is_not_a_vat.sql +144 -0
  94. package/dist/assets/migrations/20260916124000_a_box_can_be_a_rate_of_a_box.sql +525 -0
  95. package/dist/assets/migrations/20260916125000_a_tax_follows_the_territory.sql +1318 -0
  96. package/dist/assets/migrations/20260916126000_a_tax_point_and_its_exception.sql +1211 -0
  97. package/dist/assets/migrations/20260917090000_a_counterparty_that_learns.sql +561 -0
  98. package/dist/assets/migrations/20260917120000_what_the_money_pays.sql +545 -0
  99. package/dist/assets/migrations/20260917150000_a_filing_is_a_row.sql +488 -0
  100. package/dist/assets/migrations/20260917170000_when_it_is_due.sql +194 -0
  101. package/dist/assets/migrations/20260917180000_a_box_is_a_number_and_a_kind.sql +213 -0
  102. package/dist/assets/migrations/20260917190000_what_a_declaration_owes.sql +486 -0
  103. package/dist/assets/migrations/20260917200000_what_moved_after_it_went.sql +227 -0
  104. package/dist/assets/migrations/20260918090000_a_form_names_its_file.sql +27 -0
  105. package/dist/assets/migrations/20260918110000_a_deposit_and_what_came_back.sql +286 -0
  106. package/dist/assets/migrations/20260918113741_a_fourth_preset_is_named.sql +9 -0
  107. package/dist/assets/migrations/20260918113807_a_client_reads_and_hands_over.sql +96 -0
  108. package/dist/assets/migrations/20260918114322_two_definer_functions_check_their_caller.sql +75 -0
  109. package/dist/assets/migrations/20260918130000_every_company_somebody_keeps.sql +177 -0
  110. package/dist/assets/migrations/20260918140000_a_session_nobody_prepared.sql +40 -0
  111. package/dist/assets/migrations/20260918141107_a_line_keeps_the_tax_it_was_posted_with.sql +256 -0
  112. package/dist/assets/migrations/20260918141342_a_company_has_an_electronic_address.sql +66 -0
  113. package/dist/assets/migrations/20260918141605_an_invoice_reads_whole_from_the_views.sql +313 -0
  114. package/dist/assets/migrations/20260918141627_a_policy_asks_once.sql +132 -0
  115. package/dist/assets/migrations/20260918143352_a_suggestion_reads_the_words_once.sql +204 -0
  116. package/dist/assets/migrations/20260918143417_a_reference_of_the_caller_and_a_rehearsal.sql +115 -0
  117. package/dist/assets/migrations/20260918150712_a_company_leaves_with_its_books.sql +1119 -0
  118. package/dist/assets/migrations/20260918150931_a_statement_is_imported_once.sql +654 -0
  119. package/dist/assets/migrations/20260918161204_a_posted_document_does_not_move.sql +437 -0
  120. package/dist/assets/migrations/20260918161538_a_posted_entry_does_not_move.sql +252 -0
  121. package/dist/assets/migrations/20260918171946_an_entry_is_posted_by_post_entry.sql +289 -0
  122. package/dist/assets/migrations/20260918174312_schema_version_0_4_0.sql +53 -0
  123. package/dist/assets/modules/assets/module.json +13 -0
  124. package/dist/assets/modules/assets/supabase/migrations/20260913081447_assets.sql +1190 -0
  125. package/dist/assets/modules/assets/supabase/migrations/20260913104234_foreign_key_indexes.sql +47 -0
  126. package/dist/assets/modules/assets/supabase/migrations/20260913104500_assets_capabilities.sql +145 -0
  127. package/dist/assets/modules/assets/supabase/migrations/20260914122100_assets_round_at_the_currency.sql +564 -0
  128. package/dist/assets/modules/assets/supabase/migrations/20260914145012_assets_accounts_in_use.sql +37 -0
  129. package/dist/assets/modules/assets/supabase/migrations/20260914151530_assets_grants_its_own_rights.sql +63 -0
  130. package/dist/assets/modules/assets/supabase/migrations/20260918113912_assets_client_reads.sql +20 -0
  131. package/dist/assets/modules/assets/supabase/migrations/20260918150801_assets_leave_with_the_company.sql +41 -0
  132. package/dist/assets/modules/budgets/module.json +12 -0
  133. package/dist/assets/modules/budgets/supabase/migrations/20260913083012_budgets.sql +210 -0
  134. package/dist/assets/modules/budgets/supabase/migrations/20260913104233_foreign_key_indexes.sql +37 -0
  135. package/dist/assets/modules/budgets/supabase/migrations/20260913104501_budgets_capabilities.sql +72 -0
  136. package/dist/assets/modules/budgets/supabase/migrations/20260914122400_budgets_round_at_the_currency.sql +68 -0
  137. package/dist/assets/modules/budgets/supabase/migrations/20260914145048_budgets_accounts_in_use.sql +30 -0
  138. package/dist/assets/modules/budgets/supabase/migrations/20260914151812_budgets_grants_its_own_rights.sql +31 -0
  139. package/dist/assets/modules/budgets/supabase/migrations/20260918113954_budgets_client_reads.sql +20 -0
  140. package/dist/assets/modules/budgets/supabase/migrations/20260918150823_budgets_leave_with_the_company.sql +37 -0
  141. package/dist/assets/modules/schema/module.1.json +69 -0
  142. package/dist/assets/seed/00_currencies.sql +15 -0
  143. package/dist/assets/seed/00_territories.sql +280 -0
  144. package/dist/assets/seed/05_framework_generic.sql +110 -0
  145. package/dist/assets/seed/10_pack_be.sql +1284 -0
  146. package/dist/assets/seed/11_pack_fr.sql +1112 -0
  147. package/dist/assets/seed/12_pack_lu.sql +2484 -0
  148. package/dist/assets/seed/13_pack_ee.sql +733 -0
  149. package/dist/assets/seed/14_pack_gb.sql +796 -0
  150. package/dist/assets/seed/15_pack_us.sql +751 -0
  151. package/dist/assets/seed/90_demo_company.sql +368 -0
  152. package/dist/assets/seed/modules/assets/10_pack_be.sql +58 -0
  153. package/dist/assets/seed/modules/assets/11_pack_fr.sql +57 -0
  154. package/dist/assets/seed/modules/assets/14_pack_gb.sql +58 -0
  155. package/dist/assets/seed/modules/assets/15_pack_us.sql +60 -0
  156. package/dist/auth.d.ts +59 -0
  157. package/dist/auth.d.ts.map +1 -0
  158. package/dist/auth.js +134 -0
  159. package/dist/auth.js.map +1 -0
  160. package/dist/bin.d.ts +6 -0
  161. package/dist/bin.d.ts.map +1 -0
  162. package/dist/bin.js +8 -0
  163. package/dist/bin.js.map +1 -0
  164. package/dist/books.d.ts +60 -0
  165. package/dist/books.d.ts.map +1 -0
  166. package/dist/books.js +168 -0
  167. package/dist/books.js.map +1 -0
  168. package/dist/bootstrap.d.ts +236 -0
  169. package/dist/bootstrap.d.ts.map +1 -0
  170. package/dist/bootstrap.js +459 -0
  171. package/dist/bootstrap.js.map +1 -0
  172. package/dist/bundle.d.ts +27 -0
  173. package/dist/bundle.d.ts.map +1 -0
  174. package/dist/bundle.js +47 -0
  175. package/dist/bundle.js.map +1 -0
  176. package/dist/checklist.d.ts +35 -0
  177. package/dist/checklist.d.ts.map +1 -0
  178. package/dist/checklist.js +64 -0
  179. package/dist/checklist.js.map +1 -0
  180. package/dist/cli.d.ts +14 -0
  181. package/dist/cli.d.ts.map +1 -0
  182. package/dist/cli.js +318 -0
  183. package/dist/cli.js.map +1 -0
  184. package/dist/commands/company.d.ts +59 -0
  185. package/dist/commands/company.d.ts.map +1 -0
  186. package/dist/commands/company.js +287 -0
  187. package/dist/commands/company.js.map +1 -0
  188. package/dist/commands/contact.d.ts +9 -0
  189. package/dist/commands/contact.d.ts.map +1 -0
  190. package/dist/commands/contact.js +82 -0
  191. package/dist/commands/contact.js.map +1 -0
  192. package/dist/commands/demo.d.ts +19 -0
  193. package/dist/commands/demo.d.ts.map +1 -0
  194. package/dist/commands/demo.js +72 -0
  195. package/dist/commands/demo.js.map +1 -0
  196. package/dist/commands/doctor.d.ts +12 -0
  197. package/dist/commands/doctor.d.ts.map +1 -0
  198. package/dist/commands/doctor.js +68 -0
  199. package/dist/commands/doctor.js.map +1 -0
  200. package/dist/commands/document.d.ts +17 -0
  201. package/dist/commands/document.d.ts.map +1 -0
  202. package/dist/commands/document.js +217 -0
  203. package/dist/commands/document.js.map +1 -0
  204. package/dist/commands/init.d.ts +31 -0
  205. package/dist/commands/init.d.ts.map +1 -0
  206. package/dist/commands/init.js +535 -0
  207. package/dist/commands/init.js.map +1 -0
  208. package/dist/commands/login.d.ts +24 -0
  209. package/dist/commands/login.d.ts.map +1 -0
  210. package/dist/commands/login.js +128 -0
  211. package/dist/commands/login.js.map +1 -0
  212. package/dist/commands/migrate.d.ts +30 -0
  213. package/dist/commands/migrate.d.ts.map +1 -0
  214. package/dist/commands/migrate.js +115 -0
  215. package/dist/commands/migrate.js.map +1 -0
  216. package/dist/commands/module.d.ts +32 -0
  217. package/dist/commands/module.d.ts.map +1 -0
  218. package/dist/commands/module.js +285 -0
  219. package/dist/commands/module.js.map +1 -0
  220. package/dist/commands/pack.d.ts +22 -0
  221. package/dist/commands/pack.d.ts.map +1 -0
  222. package/dist/commands/pack.js +481 -0
  223. package/dist/commands/pack.js.map +1 -0
  224. package/dist/commands/payment.d.ts +15 -0
  225. package/dist/commands/payment.d.ts.map +1 -0
  226. package/dist/commands/payment.js +97 -0
  227. package/dist/commands/payment.js.map +1 -0
  228. package/dist/commands/register.d.ts +20 -0
  229. package/dist/commands/register.d.ts.map +1 -0
  230. package/dist/commands/register.js +134 -0
  231. package/dist/commands/register.js.map +1 -0
  232. package/dist/commands/status.d.ts +8 -0
  233. package/dist/commands/status.d.ts.map +1 -0
  234. package/dist/commands/status.js +134 -0
  235. package/dist/commands/status.js.map +1 -0
  236. package/dist/commands/whoami.d.ts +21 -0
  237. package/dist/commands/whoami.d.ts.map +1 -0
  238. package/dist/commands/whoami.js +133 -0
  239. package/dist/commands/whoami.js.map +1 -0
  240. package/dist/company.d.ts +16 -0
  241. package/dist/company.d.ts.map +1 -0
  242. package/dist/company.js +26 -0
  243. package/dist/company.js.map +1 -0
  244. package/dist/config.d.ts +24 -0
  245. package/dist/config.d.ts.map +1 -0
  246. package/dist/config.js +50 -0
  247. package/dist/config.js.map +1 -0
  248. package/dist/connection.d.ts +79 -0
  249. package/dist/connection.d.ts.map +1 -0
  250. package/dist/connection.js +116 -0
  251. package/dist/connection.js.map +1 -0
  252. package/dist/context.d.ts +47 -0
  253. package/dist/context.d.ts.map +1 -0
  254. package/dist/context.js +93 -0
  255. package/dist/context.js.map +1 -0
  256. package/dist/doctor.d.ts +45 -0
  257. package/dist/doctor.d.ts.map +1 -0
  258. package/dist/doctor.js +448 -0
  259. package/dist/doctor.js.map +1 -0
  260. package/dist/grants.d.ts +88 -0
  261. package/dist/grants.d.ts.map +1 -0
  262. package/dist/grants.js +174 -0
  263. package/dist/grants.js.map +1 -0
  264. package/dist/identity.d.ts +54 -0
  265. package/dist/identity.d.ts.map +1 -0
  266. package/dist/identity.js +132 -0
  267. package/dist/identity.js.map +1 -0
  268. package/dist/index.d.ts +44 -0
  269. package/dist/index.d.ts.map +1 -0
  270. package/dist/index.js +43 -0
  271. package/dist/index.js.map +1 -0
  272. package/dist/inventory.d.ts +155 -0
  273. package/dist/inventory.d.ts.map +1 -0
  274. package/dist/inventory.js +303 -0
  275. package/dist/inventory.js.map +1 -0
  276. package/dist/migrations.d.ts +76 -0
  277. package/dist/migrations.d.ts.map +1 -0
  278. package/dist/migrations.js +226 -0
  279. package/dist/migrations.js.map +1 -0
  280. package/dist/module/read.d.ts +91 -0
  281. package/dist/module/read.d.ts.map +1 -0
  282. package/dist/module/read.js +172 -0
  283. package/dist/module/read.js.map +1 -0
  284. package/dist/output.d.ts +110 -0
  285. package/dist/output.d.ts.map +1 -0
  286. package/dist/output.js +173 -0
  287. package/dist/output.js.map +1 -0
  288. package/dist/pack/certification.d.ts +27 -0
  289. package/dist/pack/certification.d.ts.map +1 -0
  290. package/dist/pack/certification.js +38 -0
  291. package/dist/pack/certification.js.map +1 -0
  292. package/dist/pack/compile.d.ts +75 -0
  293. package/dist/pack/compile.d.ts.map +1 -0
  294. package/dist/pack/compile.js +801 -0
  295. package/dist/pack/compile.js.map +1 -0
  296. package/dist/pack/filing.d.ts +48 -0
  297. package/dist/pack/filing.d.ts.map +1 -0
  298. package/dist/pack/filing.js +56 -0
  299. package/dist/pack/filing.js.map +1 -0
  300. package/dist/pack/read.d.ts +766 -0
  301. package/dist/pack/read.d.ts.map +1 -0
  302. package/dist/pack/read.js +2336 -0
  303. package/dist/pack/read.js.map +1 -0
  304. package/dist/pack/schema.d.ts +26 -0
  305. package/dist/pack/schema.d.ts.map +1 -0
  306. package/dist/pack/schema.js +181 -0
  307. package/dist/pack/schema.js.map +1 -0
  308. package/dist/pack/territories.d.ts +98 -0
  309. package/dist/pack/territories.d.ts.map +1 -0
  310. package/dist/pack/territories.js +0 -0
  311. package/dist/pack/territories.js.map +1 -0
  312. package/dist/pack/upgrade.d.ts +86 -0
  313. package/dist/pack/upgrade.d.ts.map +1 -0
  314. package/dist/pack/upgrade.js +76 -0
  315. package/dist/pack/upgrade.js.map +1 -0
  316. package/dist/pack/vat-codes.d.ts +273 -0
  317. package/dist/pack/vat-codes.d.ts.map +1 -0
  318. package/dist/pack/vat-codes.js +513 -0
  319. package/dist/pack/vat-codes.js.map +1 -0
  320. package/dist/profiles.d.ts +67 -0
  321. package/dist/profiles.d.ts.map +1 -0
  322. package/dist/profiles.js +187 -0
  323. package/dist/profiles.js.map +1 -0
  324. package/dist/prompt.d.ts +40 -0
  325. package/dist/prompt.d.ts.map +1 -0
  326. package/dist/prompt.js +120 -0
  327. package/dist/prompt.js.map +1 -0
  328. package/dist/registry.d.ts +84 -0
  329. package/dist/registry.d.ts.map +1 -0
  330. package/dist/registry.js +104 -0
  331. package/dist/registry.js.map +1 -0
  332. package/dist/rest.d.ts +81 -0
  333. package/dist/rest.d.ts.map +1 -0
  334. package/dist/rest.js +245 -0
  335. package/dist/rest.js.map +1 -0
  336. package/dist/schema.d.ts +15 -0
  337. package/dist/schema.d.ts.map +1 -0
  338. package/dist/schema.js +15 -0
  339. package/dist/schema.js.map +1 -0
  340. package/dist/seeds.d.ts +27 -0
  341. package/dist/seeds.d.ts.map +1 -0
  342. package/dist/seeds.js +47 -0
  343. package/dist/seeds.js.map +1 -0
  344. package/dist/session.d.ts +39 -0
  345. package/dist/session.d.ts.map +1 -0
  346. package/dist/session.js +92 -0
  347. package/dist/session.js.map +1 -0
  348. package/dist/sql.d.ts +48 -0
  349. package/dist/sql.d.ts.map +1 -0
  350. package/dist/sql.js +112 -0
  351. package/dist/sql.js.map +1 -0
  352. package/dist/status.d.ts +94 -0
  353. package/dist/status.d.ts.map +1 -0
  354. package/dist/status.js +120 -0
  355. package/dist/status.js.map +1 -0
  356. package/dist/ui.d.ts +55 -0
  357. package/dist/ui.d.ts.map +1 -0
  358. package/dist/ui.js +114 -0
  359. package/dist/ui.js.map +1 -0
  360. package/package.json +29 -0
  361. package/schema/output.1.json +613 -0
@@ -0,0 +1,36 @@
1
+ -- Ekwo OS — the schema this release defines is 0.2.0.
2
+ --
3
+ -- `ekwo_schema_version()` is the one place the number lives, and a migration
4
+ -- is the only thing that moves it. A database then answers for the files it
5
+ -- has actually run rather than for what somebody believed it had run: the
6
+ -- column default and `init_instance()` both call this function, so a fresh
7
+ -- install records the new number without a second edit, and `ekwo migrate`
8
+ -- reads it back onto `instance.schema_version` for a database that was
9
+ -- installed at an older one.
10
+ --
11
+ -- 0.1.0 was the first schema of this repository and was never tagged. Between
12
+ -- it and here came the installer, the MCP server, country packs, capabilities
13
+ -- and machine keys, modules, the audit trail, the generalised tax engine,
14
+ -- financial statements, languages and currency-aware rounding. The packages
15
+ -- of this release read `audit_log`, the rounding functions and `company_packs`
16
+ -- — none of which a 0.1.0 database has — so they declare 0.2.0 as their floor
17
+ -- and refuse an older database by name, rather than improvising over a column
18
+ -- that is not there.
19
+
20
+ create or replace function ekwo_schema_version()
21
+ returns text
22
+ language sql
23
+ immutable
24
+ as $$
25
+ select '0.2.0'::text;
26
+ $$;
27
+
28
+ comment on function ekwo_schema_version() is
29
+ 'Schema version of the installed release. Bumped by a migration, never by hand.';
30
+
31
+ -- `create or replace` keeps the privileges the function already had, and the
32
+ -- revoke is what every migration of this directory ends with: a function that
33
+ -- comes out with the built-in default is published by Supabase as an
34
+ -- anonymous RPC endpoint.
35
+ revoke execute on all functions in schema public from public;
36
+ grant execute on function ekwo_schema_version() to authenticated, service_role;
@@ -0,0 +1,428 @@
1
+ -- Ekwo OS — the part of the chart a company actually works with.
2
+ --
3
+ -- A country pack is a transcription: Belgium ships 353 accounts, France 394,
4
+ -- Luxembourg 1 026, and that is deliberate — an abridged chart would be this
5
+ -- repository's opinion of which accounts matter, sitting in a file that claims
6
+ -- to be the regulation. Nothing here takes that back. Two production companies
7
+ -- measured on their 2025 books used 60 accounts out of roughly 300 and 126 out
8
+ -- of roughly 300. The chart is right; a list of three hundred lines offered to
9
+ -- somebody looking for the account a purchase invoice goes on is not.
10
+ --
11
+ -- So the chart stays whole and a second question is added beside it: which of
12
+ -- these accounts is this company working with? It is answered by reading what
13
+ -- the company already points at, and it needs no maintenance:
14
+ --
15
+ -- moved the account carries a line of a posted entry. With a period,
16
+ -- a line dated inside it; without one, ever.
17
+ -- referenced the configuration of the company names the account by foreign
18
+ -- key — a role default, a contact override, a journal, a tax
19
+ -- posting, the cash-basis transition account of a tax, a bank
20
+ -- account, a product. A reference is not dated: an account a
21
+ -- product posts to is in use before anything is booked on it, and
22
+ -- stays in use in a period nothing was booked in.
23
+ -- a module a module the company has enabled names it. Asked of the module
24
+ -- rather than read from here, see below.
25
+ -- pinned somebody said so. `accounts.pinned` is the one column an
26
+ -- operator edits to add an account the rules above cannot know
27
+ -- about, and to keep one that has stopped being referenced.
28
+ --
29
+ -- minus `deprecated`, which is already how a chart retires an account and is
30
+ -- already what the MCP server hides.
31
+ --
32
+ -- **The installation pins what it wires.** `install_country_template()` ends
33
+ -- by pinning every account it referenced — the roles, the journals' accounts,
34
+ -- the tax postings, the cash-basis transitions — around thirty on the packs
35
+ -- this release carries. The union above would find most of them anyway; what
36
+ -- pinning adds is that the set is written down. A company that later points a
37
+ -- role at a different account keeps the first one in its working chart rather
38
+ -- than watching it disappear, which is the behaviour an operator expects of a
39
+ -- list they have been reading for a year.
40
+ --
41
+ -- **The socle still ignores its modules.** `accounts_in_use` does not name
42
+ -- `assets` or `budgets`: it asks each module the company has enabled for the
43
+ -- accounts it holds, by the convention `disable_module()` already uses —
44
+ -- `<schema>.accounts_in_use(uuid)`, looked up with `to_regprocedure`, absent
45
+ -- on a module that references no account. The dependency keeps pointing one
46
+ -- way.
47
+ --
48
+ -- **Nothing is restricted by any of this.** A document line may name any
49
+ -- account of the chart that is not deprecated, exactly as before. This is a
50
+ -- reading, and the only thing it changes is what is offered first.
51
+
52
+ -- ---------------------------------------------------------------------------
53
+ -- The column
54
+ -- ---------------------------------------------------------------------------
55
+
56
+ alter table accounts
57
+ add column if not exists pinned boolean not null default false;
58
+
59
+ comment on column accounts.pinned is
60
+ 'Whether this account belongs to the working chart of the company whatever the ledger says. Set by install_country_template() on everything it wires, and by an operator afterwards. Display only: pinning restricts nothing.';
61
+
62
+ -- The index the function's `pinned` branch reads, and the one a client asking
63
+ -- for the pinned set alone reads. Partial, because the pinned accounts are the
64
+ -- few and the rest of the chart is the many.
65
+ create index accounts_pinned_idx on accounts (company_id) where pinned;
66
+
67
+ -- ---------------------------------------------------------------------------
68
+ -- accounts_in_use
69
+ --
70
+ -- Security invoker: row level security decides which company the caller may
71
+ -- read, exactly as it does for a select on `accounts`. A stranger gets an
72
+ -- empty set rather than a refusal, which is the answer the policy already
73
+ -- gives them on the table.
74
+ -- ---------------------------------------------------------------------------
75
+
76
+ create or replace function accounts_in_use(
77
+ p_company_id uuid,
78
+ p_from date default null,
79
+ p_to date default null
80
+ )
81
+ returns setof uuid
82
+ language plpgsql
83
+ stable
84
+ as $$
85
+ declare
86
+ v_module record;
87
+ v_function regprocedure;
88
+ v_from_module uuid[];
89
+ v_modules uuid[] := '{}'::uuid[];
90
+ begin
91
+ -- What the modules of this company hold. A module that names no account
92
+ -- writes no function, and `to_regprocedure` answers null rather than
93
+ -- raising — the same convention `disable_module()` reads for
94
+ -- `<schema>.can_disable(uuid)`.
95
+ for v_module in
96
+ select m.schema_name
97
+ from company_modules cm
98
+ join modules m on m.code = cm.module_code
99
+ where cm.company_id = p_company_id
100
+ loop
101
+ v_function := to_regprocedure(format('%I.accounts_in_use(uuid)', v_module.schema_name));
102
+ if v_function is not null then
103
+ execute format(
104
+ 'select coalesce(array_agg(t), ''{}''::uuid[]) from %I.accounts_in_use($1) as t',
105
+ v_module.schema_name
106
+ ) into v_from_module using p_company_id;
107
+ v_modules := v_modules || v_from_module;
108
+ end if;
109
+ end loop;
110
+
111
+ return query
112
+ select a.id
113
+ from accounts a
114
+ where a.company_id = p_company_id
115
+ and not a.deprecated
116
+ and (
117
+ a.pinned
118
+ or a.id = any (v_modules)
119
+ -- Moved, in the period when there is one.
120
+ or exists (
121
+ select 1
122
+ from entry_lines l
123
+ join entries e on e.id = l.entry_id
124
+ where l.account_id = a.id
125
+ and e.state = 'posted'
126
+ and (p_from is null or e.entry_date >= p_from)
127
+ and (p_to is null or e.entry_date <= p_to)
128
+ )
129
+ -- The roles the company keeps.
130
+ or exists (
131
+ select 1 from companies c
132
+ where c.id = p_company_id
133
+ and a.id in (c.receivable_account_id, c.payable_account_id,
134
+ c.suspense_account_id, c.rounding_account_id,
135
+ c.retained_earnings_account_id,
136
+ c.default_sales_account_id, c.default_purchase_account_id)
137
+ )
138
+ -- What a contact overrides those roles with.
139
+ or exists (
140
+ select 1 from contacts ct
141
+ where ct.company_id = p_company_id
142
+ and a.id in (ct.receivable_account_id, ct.payable_account_id)
143
+ )
144
+ -- What a journal posts to, and where its unallocated lines land.
145
+ or exists (
146
+ select 1 from journals j
147
+ where j.company_id = p_company_id
148
+ and a.id in (j.default_account_id, j.suspense_account_id)
149
+ )
150
+ -- Where a tax books, and where a cash-basis tax waits.
151
+ or exists (
152
+ select 1 from tax_postings tp
153
+ where tp.company_id = p_company_id and tp.account_id = a.id
154
+ )
155
+ or exists (
156
+ select 1 from taxes t
157
+ where t.company_id = p_company_id and t.cash_basis_transition_account_id = a.id
158
+ )
159
+ -- The ledger account behind a bank account.
160
+ or exists (
161
+ select 1 from bank_accounts b
162
+ where b.company_id = p_company_id and b.account_id = a.id
163
+ )
164
+ -- What the catalogue sells and buys on.
165
+ or exists (
166
+ select 1 from products p
167
+ where p.company_id = p_company_id
168
+ and a.id in (p.sale_account_id, p.purchase_account_id)
169
+ )
170
+ )
171
+ order by a.code;
172
+ end;
173
+ $$;
174
+
175
+ comment on function accounts_in_use(uuid, date, date) is
176
+ 'The accounts of a company that are in use: moved by a posted entry in the period — ever, when no period is given — or referenced by the configuration of the company — a role default, a contact override, a journal, a tax posting, a cash-basis transition, a bank account, a product — or held by a module the company has enabled, or pinned. Deprecated accounts are left out. A configuration reference is not dated; only the movement is. This is a reading: nothing here restricts what may be booked.';
177
+
178
+ revoke execute on function accounts_in_use(uuid, date, date) from public, anon;
179
+ grant execute on function accounts_in_use(uuid, date, date) to authenticated, service_role;
180
+
181
+ revoke execute on all functions in schema public from public;
182
+
183
+ -- ---------------------------------------------------------------------------
184
+ -- What an installation pins
185
+ --
186
+ -- The set every company gets wired to whatever its chart is: the roles of the
187
+ -- country model, the accounts its journals post to, the accounts its taxes
188
+ -- book on, and the transition account of a cash-basis tax. It is worked out
189
+ -- from what the company already points at rather than from the pack, so it
190
+ -- says the same thing after an upgrade adds a tax as it said at installation,
191
+ -- and so a chart nobody here has seen needs no case of its own.
192
+ -- ---------------------------------------------------------------------------
193
+
194
+ create or replace function pin_referenced_accounts(p_company_id uuid)
195
+ returns integer
196
+ language plpgsql
197
+ as $$
198
+ declare
199
+ v_pinned integer;
200
+ begin
201
+ with referenced as (
202
+ select unnest(array[c.receivable_account_id, c.payable_account_id,
203
+ c.suspense_account_id, c.rounding_account_id,
204
+ c.retained_earnings_account_id,
205
+ c.default_sales_account_id, c.default_purchase_account_id]) as id
206
+ from companies c where c.id = p_company_id
207
+ union
208
+ select unnest(array[j.default_account_id, j.suspense_account_id])
209
+ from journals j where j.company_id = p_company_id
210
+ union
211
+ select tp.account_id from tax_postings tp where tp.company_id = p_company_id
212
+ union
213
+ select t.cash_basis_transition_account_id from taxes t where t.company_id = p_company_id
214
+ )
215
+ update accounts a
216
+ set pinned = true
217
+ from referenced r
218
+ where a.id = r.id
219
+ and a.company_id = p_company_id
220
+ and not a.pinned;
221
+
222
+ select count(*) into v_pinned
223
+ from accounts a where a.company_id = p_company_id and a.pinned;
224
+
225
+ return v_pinned;
226
+ end;
227
+ $$;
228
+
229
+ comment on function pin_referenced_accounts(uuid) is
230
+ 'Pins every account this company points at by a role, a journal, a tax posting or a cash-basis transition, and returns how many accounts are pinned afterwards. Called by install_country_template(); callable again after an upgrade added a tax.';
231
+
232
+ revoke execute on function pin_referenced_accounts(uuid) from public, anon;
233
+ grant execute on function pin_referenced_accounts(uuid) to authenticated, service_role;
234
+
235
+ -- ---------------------------------------------------------------------------
236
+ -- install_country_template, pinning what it wired
237
+ --
238
+ -- The function is recreated whole rather than edited, because every file that
239
+ -- defined it shipped in v0.2.0 and a published migration is never touched. The
240
+ -- body below is its latest definition — `20260913111407`, which made the
241
+ -- journals and the taxes copy in the company's language — with one step added
242
+ -- at the end. Step 8 is the only line that is new.
243
+ -- ---------------------------------------------------------------------------
244
+
245
+ create or replace function install_country_template(
246
+ p_company_id uuid,
247
+ p_country char(2),
248
+ p_language char(2) default null,
249
+ p_chart_code text default null
250
+ )
251
+ returns void
252
+ language plpgsql
253
+ as $$
254
+ declare
255
+ v_defaults country_defaults%rowtype;
256
+ r record;
257
+ v_tax_id uuid;
258
+ v_language char(2);
259
+ v_version text;
260
+ v_chart text;
261
+ v_charts text;
262
+ begin
263
+ if not exists (select 1 from companies where id = p_company_id) then
264
+ raise exception 'unknown_company: %', p_company_id;
265
+ end if;
266
+
267
+ -- Which chart. The caller names one, or the pack's default stands. A named
268
+ -- chart that does not exist is an error that lists what does: guessing here
269
+ -- would install the wrong plan of accounts and nobody would notice for a
270
+ -- year.
271
+ if p_chart_code is null then
272
+ select c.code into v_chart
273
+ from chart_templates c
274
+ where c.country = p_country and c.is_default;
275
+ if v_chart is null then
276
+ -- No pack for this country, or a pack that names no default chart.
277
+ raise exception 'unknown_country_template: no chart of accounts seeded for %', p_country;
278
+ end if;
279
+ else
280
+ select c.code into v_chart
281
+ from chart_templates c
282
+ where c.country = p_country and c.code = p_chart_code;
283
+ if v_chart is null then
284
+ select string_agg(c.code, ', ' order by c.code) into v_charts
285
+ from chart_templates c where c.country = p_country;
286
+ raise exception 'unknown_chart: % has no chart %. It has: %',
287
+ p_country, p_chart_code, coalesce(v_charts, 'none');
288
+ end if;
289
+ end if;
290
+
291
+ if not exists (
292
+ select 1 from account_templates
293
+ where country = p_country and chart_code = v_chart
294
+ ) then
295
+ raise exception 'unknown_country_template: chart % of % holds no account', v_chart, p_country;
296
+ end if;
297
+
298
+ -- The language of the copy: what the caller asked for, else what the
299
+ -- company keeps its books in.
300
+ select coalesce(p_language, c.language) into v_language
301
+ from companies c where c.id = p_company_id;
302
+
303
+ -- 1. Accounts, without the hierarchy.
304
+ insert into accounts (company_id, code, name, name_i18n, statement_hint,
305
+ account_type, reconcilable)
306
+ select p_company_id, t.code,
307
+ label_for(t.name, t.name_i18n, array[v_language]),
308
+ t.name_i18n, t.statement_hint, t.account_type, t.reconcilable
309
+ from account_templates t
310
+ where t.country = p_country
311
+ and t.chart_code = v_chart
312
+ on conflict (company_id, code) do nothing;
313
+
314
+ -- 2. Hierarchy, now that every code exists.
315
+ update accounts a
316
+ set parent_id = p.id
317
+ from account_templates t
318
+ join accounts p on p.company_id = p_company_id and p.code = t.parent_code
319
+ where a.company_id = p_company_id
320
+ and a.code = t.code
321
+ and t.country = p_country
322
+ and t.chart_code = v_chart
323
+ and t.parent_code is not null
324
+ and a.parent_id is null;
325
+
326
+ -- 3. Journals. Common to every chart of the country.
327
+ insert into journals (company_id, code, name, name_i18n, journal_type)
328
+ select p_company_id, t.code,
329
+ label_for(t.name, t.name_i18n, array[v_language]),
330
+ t.name_i18n, t.journal_type
331
+ from journal_templates t
332
+ where t.country = p_country
333
+ on conflict (company_id, code) do nothing;
334
+
335
+ -- 4. Taxes and their postings. Also common: a chart changes how a company
336
+ -- presents itself, not what it owes.
337
+ for r in
338
+ select * from tax_templates where country = p_country order by sequence, code
339
+ loop
340
+ v_tax_id := null;
341
+ insert into taxes (company_id, code, name, name_i18n, description, amount_type, amount,
342
+ applies_to, treatment, country, valid_from, valid_to,
343
+ legal_reference, vat_category, exemption_code, sequence,
344
+ tax_kind, recoverable, jurisdiction, price_include,
345
+ cash_basis, cash_basis_transition_account_id)
346
+ values (p_company_id, r.code,
347
+ label_for(r.name, r.name_i18n, array[v_language]),
348
+ r.name_i18n, r.description, r.amount_type, r.amount,
349
+ r.applies_to, r.treatment, p_country, r.valid_from, r.valid_to,
350
+ r.legal_reference, r.vat_category, r.exemption_code, r.sequence,
351
+ r.tax_kind, r.recoverable, r.jurisdiction, r.price_include,
352
+ r.cash_basis, account_id_by_code(p_company_id, r.cash_basis_transition_account_code))
353
+ on conflict (company_id, code) do nothing
354
+ returning id into v_tax_id;
355
+
356
+ if v_tax_id is null then
357
+ continue;
358
+ end if;
359
+
360
+ insert into tax_postings (tax_id, company_id, document_kind, posting_type,
361
+ factor_percent, account_id, declaration_box,
362
+ box_factor_percent, report_code, sequence)
363
+ select v_tax_id, p_company_id, tp.document_kind, tp.posting_type,
364
+ tp.factor_percent, account_id_by_code(p_company_id, tp.account_code),
365
+ tp.declaration_box, tp.box_factor_percent, tp.report_code, tp.sequence
366
+ from tax_posting_templates tp
367
+ where tp.tax_template_id = r.id
368
+ order by tp.sequence;
369
+ end loop;
370
+
371
+ -- 5. Roles.
372
+ select * into v_defaults from country_defaults where country = p_country;
373
+ if found then
374
+ update companies c
375
+ set receivable_account_id = coalesce(c.receivable_account_id, account_id_by_code(p_company_id, v_defaults.receivable_code)),
376
+ payable_account_id = coalesce(c.payable_account_id, account_id_by_code(p_company_id, v_defaults.payable_code)),
377
+ suspense_account_id = coalesce(c.suspense_account_id, account_id_by_code(p_company_id, v_defaults.suspense_code)),
378
+ rounding_account_id = coalesce(c.rounding_account_id, account_id_by_code(p_company_id, v_defaults.rounding_code)),
379
+ retained_earnings_account_id = coalesce(c.retained_earnings_account_id, account_id_by_code(p_company_id, v_defaults.retained_earnings_code)),
380
+ default_sales_account_id = coalesce(c.default_sales_account_id, account_id_by_code(p_company_id, v_defaults.sales_account_code)),
381
+ default_purchase_account_id = coalesce(c.default_purchase_account_id, account_id_by_code(p_company_id, v_defaults.purchase_account_code)),
382
+ sales_journal_id = coalesce(c.sales_journal_id, (select id from journals where company_id = p_company_id and code = v_defaults.sales_journal_code)),
383
+ purchase_journal_id = coalesce(c.purchase_journal_id, (select id from journals where company_id = p_company_id and code = v_defaults.purchase_journal_code)),
384
+ miscellaneous_journal_id = coalesce(c.miscellaneous_journal_id, (select id from journals where company_id = p_company_id and code = v_defaults.misc_journal_code))
385
+ where c.id = p_company_id;
386
+
387
+ -- 6. The financial journals point at their account.
388
+ update journals j
389
+ set default_account_id = account_id_by_code(p_company_id, v_defaults.bank_account_code)
390
+ where j.company_id = p_company_id
391
+ and j.journal_type = 'bank'
392
+ and j.default_account_id is null
393
+ and v_defaults.bank_account_code is not null;
394
+
395
+ update journals j
396
+ set default_account_id = account_id_by_code(p_company_id, v_defaults.cash_account_code)
397
+ where j.company_id = p_company_id
398
+ and j.journal_type = 'cash'
399
+ and j.default_account_id is null
400
+ and v_defaults.cash_account_code is not null;
401
+ end if;
402
+
403
+ -- 7. What was copied, from which version, and on which chart.
404
+ v_version := coalesce((select version from country_packs where country = p_country), '1.0.0');
405
+
406
+ insert into company_packs (company_id, country, version, chart_code)
407
+ values (p_company_id, p_country, v_version, v_chart)
408
+ on conflict (company_id, country) do update
409
+ set version = excluded.version,
410
+ chart_code = excluded.chart_code,
411
+ upgraded_at = now()
412
+ where company_packs.version is distinct from excluded.version
413
+ or company_packs.chart_code is distinct from excluded.chart_code;
414
+
415
+ -- 8. The working chart. Everything wired above is pinned, so a company opens
416
+ -- on the accounts its country model actually points at rather than on the
417
+ -- whole transcription.
418
+ perform pin_referenced_accounts(p_company_id);
419
+ end;
420
+ $$;
421
+
422
+ comment on function install_country_template(uuid, char, char, text) is
423
+ 'Copies one chart of a country pack into a company in one language, with the country''s journals and taxes, wires the default roles, pins the accounts it wired, and records the pack version and the chart in company_packs.';
424
+
425
+ revoke execute on function install_country_template(uuid, char, char, text) from public, anon;
426
+ grant execute on function install_country_template(uuid, char, char, text) to authenticated, service_role;
427
+
428
+ revoke execute on all functions in schema public from public;
@@ -0,0 +1,99 @@
1
+ -- Ekwo OS — the code of an account stops moving once something is booked on it.
2
+ --
3
+ -- Every reference to an account inside a company is a foreign key on
4
+ -- `accounts(id)`: the roles of the company, the overrides of a contact, the
5
+ -- journals, the tax postings, the lines of a document, the lines of the
6
+ -- ledger, and the tables of the modules. Renaming an account therefore breaks
7
+ -- nothing, and renumbering one appears to break nothing either — the keys
8
+ -- follow.
9
+ --
10
+ -- The rules do not follow. A financial statement maps an account to a line by
11
+ -- its code (`statement_line_rules` carries `account_code` rules, and on the
12
+ -- Belgian chart a rubric code *is* a range of codes), a declaration box is
13
+ -- reached through a tax posting whose account is one the pack named by code,
14
+ -- and `account_id_by_code()` is how half the schema finds an account at all.
15
+ -- So moving `700000` to `701000` moves the account to a different line of the
16
+ -- balance sheet or the profit and loss account, and the year already booked
17
+ -- on it moves with it — silently, and in a statement somebody has filed.
18
+ --
19
+ -- `accounts_write` let that happen: the policy judges which company a row
20
+ -- belongs to and has nothing to say about which column changes. This adds the
21
+ -- guard the policy cannot express.
22
+ --
23
+ -- `account_code_frozen` the code may not change once the account carries a
24
+ -- line of the ledger, is named by a tax posting, or
25
+ -- plays one of the company's roles.
26
+ -- `account_type_frozen` neither may the type, for the same reason: the
27
+ -- eighteen types are what puts an account on one side
28
+ -- of the balance sheet or in the income statement,
29
+ -- and `internal_group` and `carries_forward` are
30
+ -- generated from it.
31
+ --
32
+ -- Everything else about an account stays editable at any time: its name, its
33
+ -- translations, its notes, its parent, whether it is reconcilable, whether it
34
+ -- is deprecated, whether it is pinned. Renaming an account is ordinary work —
35
+ -- it is what an operator does to a chart they have just installed — and
36
+ -- `pack_upgrade` does it too, on the `review` rule, when a pack changes a
37
+ -- label.
38
+ --
39
+ -- One consequence is deliberate: `pack_upgrade(…, p_apply => true)` now fails
40
+ -- by name rather than moving a used account between statements. A pack that
41
+ -- changes the type of an account a company has been booking on is a difference
42
+ -- a person has to look at, which is what the `review` rule was already for.
43
+ --
44
+ -- Deprecating is the way out, and it always was: an account that was wrong is
45
+ -- deprecated and a new one takes the entries from here on. Nothing is deleted
46
+ -- from a chart, for the same reason nothing is deleted from a pack.
47
+
48
+ create or replace function accounts_guard_frozen()
49
+ returns trigger
50
+ language plpgsql
51
+ as $$
52
+ declare
53
+ v_used boolean;
54
+ begin
55
+ if new.code = old.code and new.account_type = old.account_type then
56
+ return new;
57
+ end if;
58
+
59
+ select exists (select 1 from entry_lines l where l.account_id = old.id)
60
+ or exists (select 1 from tax_postings tp where tp.account_id = old.id)
61
+ or exists (
62
+ select 1 from companies c
63
+ where c.id = old.company_id
64
+ and old.id in (c.receivable_account_id, c.payable_account_id,
65
+ c.suspense_account_id, c.rounding_account_id,
66
+ c.retained_earnings_account_id,
67
+ c.default_sales_account_id, c.default_purchase_account_id)
68
+ )
69
+ into v_used;
70
+
71
+ if not v_used then
72
+ return new;
73
+ end if;
74
+
75
+ if new.code <> old.code then
76
+ raise exception 'account_code_frozen: % carries entries, a tax posting or a company role, so its code stays %. Deprecate it and open the new code instead.',
77
+ old.code, old.code
78
+ using errcode = '55006';
79
+ end if;
80
+
81
+ raise exception 'account_type_frozen: % is in use, so it stays %. Its type is what puts it on a line of the statements, and the entries already booked would move with it.',
82
+ old.code, old.account_type
83
+ using errcode = '55006';
84
+ end;
85
+ $$;
86
+
87
+ comment on function accounts_guard_frozen() is
88
+ 'Refuses a change of code or of account_type on an account that carries ledger lines, is named by a tax posting or plays a company role. The label, the translations, the parent, reconcilable, deprecated and pinned stay editable.';
89
+
90
+ create trigger accounts_guard_frozen
91
+ before update on accounts
92
+ for each row execute function accounts_guard_frozen();
93
+
94
+ -- A trigger body is invoked by its table, never called: PostgreSQL checks
95
+ -- EXECUTE when the trigger is created, so taking it away removes an RPC
96
+ -- endpoint and changes nothing else.
97
+ revoke execute on function accounts_guard_frozen() from public, anon, authenticated, service_role;
98
+
99
+ revoke execute on all functions in schema public from public;