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,181 @@
1
+ -- Ekwo OS — the recapitulative statement of intra-Community supplies, as one
2
+ -- function of the core.
3
+ --
4
+ -- Every Member State asks the same question of a seller: to whom, in another
5
+ -- Member State, did you supply goods and services without charging VAT, and
6
+ -- for how much. The answer is a list of lines, one per customer VAT number and
7
+ -- per nature of supply, and every administration then wants it in a file of
8
+ -- its own shape. That split is the whole design here.
9
+ --
10
+ -- **The list is the engine. The file is a brick.** `ec_sales_list()` returns
11
+ -- flat rows and knows no country; `packages/formats/` turns those rows into
12
+ -- the XML Belgium, France, Luxembourg or Estonia expects, one package per
13
+ -- format. There is no `packs/eu/`, because what is European here is not data a
14
+ -- country fills in — it is the rule that reads the treatment of a tax and the
15
+ -- VAT number of a contact, and that rule is the same everywhere.
16
+ --
17
+ -- Four decisions are worth reading before the SQL.
18
+ --
19
+ -- **The nature of a supply comes from the treatment, and nothing is listed by
20
+ -- name.** A sale line whose tax is treated `intracom_goods` is goods,
21
+ -- `intracom_services` is services, and the nature is the treatment with its
22
+ -- `intracom_` prefix removed. So the day the enum gains `intracom_triangular`
23
+ -- — the third category every one of these forms already prints — this function
24
+ -- returns a `triangular` nature without a line of it changing. The acquisition
25
+ -- treatments are excluded by name for the same reason they are named that way:
26
+ -- they are the purchase side, and a recapitulative statement is about supplies.
27
+ --
28
+ -- **It reads the ledger, not the invoices.** The same posted `entry_lines`
29
+ -- that `vat_return()` sums, over the same dates, in the company's currency —
30
+ -- which is why the two agree to the cent and why a test can prove it. The base
31
+ -- lines of an intra-Community supply are the lines of its tax that are not tax
32
+ -- lines: such a supply is exempt, so its tax carries a `base` posting and
33
+ -- nothing else. A `tax_on_base` or a `cash_basis` posting on a tax treated as
34
+ -- an intra-Community supply would be a defect of the pack — there is no VAT on
35
+ -- the line to capitalise and none to defer — and `docs/international.md`
36
+ -- records the underlying gap: a ledger line does not say which posting wrote
37
+ -- it.
38
+ --
39
+ -- **It refuses no period.** `vat_return()` refuses a period the company does
40
+ -- not file its return on, because `companies.vat_period` records that. Nothing
41
+ -- records how often the *statement* is filed, and it is a different cadence in
42
+ -- every country read while writing this: Belgium files it monthly above a
43
+ -- threshold that counts goods only, whatever the return's cadence; France
44
+ -- files it monthly always; Luxembourg lets goods and services take different
45
+ -- cadences, both independent of the return; Estonia files it monthly with the
46
+ -- return. A guard borrowed from the return would refuse a lawful monthly
47
+ -- statement from a quarterly filer, which is the ordinary Belgian case. So
48
+ -- this function takes two dates and answers for them. The gap — a company
49
+ -- records one cadence and there is more than one — is written down in
50
+ -- `docs/international.md` rather than patched here.
51
+ --
52
+ -- **What cannot be declared comes back, it is not dropped.** A supply whose
53
+ -- customer has no VAT number, or a number whose country is the company's own,
54
+ -- is returned with the reason in `issue` rather than silently left out of the
55
+ -- total. A brick puts those rows in `violations[]` and the rest in the file,
56
+ -- which is the contract every format library here already has.
57
+
58
+ -- ---------------------------------------------------------------------------
59
+ -- ec_sales_list(company, from, to)
60
+ -- ---------------------------------------------------------------------------
61
+
62
+ create or replace function ec_sales_list(
63
+ p_company_id uuid,
64
+ p_from date,
65
+ p_to date
66
+ )
67
+ returns table (
68
+ vat_country char(2),
69
+ vat_number text,
70
+ nature text,
71
+ amount numeric,
72
+ currency_code char(3),
73
+ documents integer,
74
+ contact_ids uuid[],
75
+ contact_names text[],
76
+ issue text
77
+ )
78
+ language plpgsql
79
+ stable
80
+ as $$
81
+ declare
82
+ v_country char(2);
83
+ v_currency char(3);
84
+ v_round money_rounding;
85
+ begin
86
+ select c.fiscal_country, c.currency_code into v_country, v_currency
87
+ from companies c where c.id = p_company_id;
88
+ if not found then
89
+ raise exception 'unknown_company: %', p_company_id;
90
+ end if;
91
+ v_round := rounding_of(p_company_id);
92
+
93
+ return query
94
+ -- 1. The supplies themselves: the base lines of every tax treated as an
95
+ -- intra-Community supply, on posted entries of the period.
96
+ --
97
+ -- `credit - debit` is the amount with the sign the statement wants: a
98
+ -- sale credits the revenue account and a credit note debits it, so a
99
+ -- credit note is deducted from the customer's line without this having
100
+ -- to know what a credit note is. It is also why no total here can be
101
+ -- read off one box of the return: Belgium reports its credit notes in a
102
+ -- box of their own, France nets them into the box they came from.
103
+ with supply as (
104
+ select d.contact_id,
105
+ ct.name as contact_name,
106
+ regexp_replace(t.treatment::text, '^intracom_', '') as nature,
107
+ -- The number as somebody typed it, reduced to what an
108
+ -- administration compares: upper case, letters and digits.
109
+ upper(regexp_replace(coalesce(ct.vat_number, ''), '[^A-Za-z0-9]', '', 'g')) as vat_raw,
110
+ ct.country as contact_country,
111
+ e.document_id,
112
+ l.credit - l.debit as amount
113
+ from entry_lines l
114
+ join entries e on e.id = l.entry_id
115
+ join taxes t on t.id = l.tax_id
116
+ left join documents d on d.id = e.document_id
117
+ left join contacts ct on ct.id = d.contact_id
118
+ where l.company_id = p_company_id
119
+ and e.state = 'posted'
120
+ and e.entry_date between p_from and p_to
121
+ and not l.tax_line
122
+ and t.treatment::text like 'intracom!_%' escape '!'
123
+ and t.treatment::text not like 'intracom!_acquisition!_%' escape '!'
124
+ ),
125
+ -- 2. The identifier the statement is keyed on. A VAT number carries its own
126
+ -- country when it was recorded with one; where it was not, the country of
127
+ -- the contact answers. Nothing here knows a Member State from any other
128
+ -- country — the core holds no such list, which `docs/international.md`
129
+ -- records — so the only country this compares against is the company's.
130
+ keyed as (
131
+ select s.*,
132
+ case when s.vat_raw ~ '^[A-Z]{2}' then substring(s.vat_raw from 1 for 2)
133
+ when s.vat_raw = '' then null
134
+ else s.contact_country
135
+ end as vat_country,
136
+ case when s.vat_raw = '' then null
137
+ when s.vat_raw ~ '^[A-Z]{2}' then substring(s.vat_raw from 3)
138
+ else s.vat_raw
139
+ end as vat_number
140
+ from supply s
141
+ ),
142
+ -- 3. Why a line cannot be declared, or null when it can. Ordered from the
143
+ -- most missing to the most contradictory, so a row carries the first
144
+ -- thing somebody has to fix.
145
+ judged as (
146
+ select k.*,
147
+ case
148
+ when k.contact_id is null then 'no_customer'
149
+ when k.vat_number is null or k.vat_number = '' then 'no_vat_number'
150
+ when k.vat_country is null then 'no_vat_country'
151
+ when k.vat_country = v_country then 'vat_country_is_the_company_country'
152
+ end as issue
153
+ from keyed k
154
+ )
155
+ select j.vat_country::char(2),
156
+ j.vat_number,
157
+ j.nature,
158
+ round_amount(sum(j.amount), v_round),
159
+ v_currency,
160
+ count(distinct j.document_id)::integer,
161
+ array_agg(distinct j.contact_id) filter (where j.contact_id is not null),
162
+ array_agg(distinct j.contact_name) filter (where j.contact_name is not null),
163
+ j.issue
164
+ from judged j
165
+ -- A declarable line is keyed on the VAT number, so two contacts sharing one
166
+ -- — a site and the entity that is invoiced — become the single line the
167
+ -- form wants. A line that cannot be declared is keyed on the contact
168
+ -- instead, because the number is what is missing or wrong and the contact
169
+ -- is what somebody has to open.
170
+ group by j.vat_country, j.vat_number, j.nature, j.issue,
171
+ case when j.issue is not null then j.contact_id end
172
+ having round_amount(sum(j.amount), v_round) <> 0
173
+ order by (j.issue is not null), j.vat_country, j.vat_number, j.nature;
174
+ end;
175
+ $$;
176
+
177
+ comment on function ec_sales_list(uuid, date, date) is
178
+ 'The recapitulative statement of intra-Community supplies for a period: one line per customer VAT number and per nature — goods, services, and whatever the treatment vocabulary gains next — summed from the posted ledger in the company''s currency, credit notes deducted. A supply that cannot be declared comes back with the reason in `issue` rather than being left out. No country rule lives in this function, and it refuses no period: how often a statement is filed is not what companies.vat_period records.';
179
+
180
+ revoke execute on function ec_sales_list(uuid, date, date) from public, anon;
181
+ grant execute on function ec_sales_list(uuid, date, date) to authenticated, service_role;
@@ -0,0 +1,56 @@
1
+ -- Ekwo OS — where a country's rules come from, in the database that applies them.
2
+ --
3
+ -- `legal_reference` has been required on every tax and every box of every
4
+ -- declaration form since country packs existed, and `certification.sources`
5
+ -- listed the texts a pack as a whole was built from. Between them they said
6
+ -- which article a rule claims and which laws somebody read. What neither said
7
+ -- is where any of it can be opened: the manifest held titles and no link, the
8
+ -- rules held articles and no link, and an application that wanted to answer
9
+ -- "where do these rules come from" had a citation and a search engine.
10
+ --
11
+ -- `packs/<cc>/pack.json` now carries a register — a key, a title, the official
12
+ -- publisher, an absolute https URL and the day somebody opened it, per text —
13
+ -- and every tax and every box names a key of it beside the article it already
14
+ -- carried. Three columns bring that here:
15
+ --
16
+ -- `country_packs.sources` the register itself, in the order the
17
+ -- pack declares it. What an application
18
+ -- shows beside a chart of accounts.
19
+ -- `tax_templates.source_key` which text of that register the tax's
20
+ -- legal reference is in.
21
+ -- `tax_report_box_templates.source_key` the same, per box of the form.
22
+ --
23
+ -- Additive: three nullable columns, no constraint, no backfill. The value is
24
+ -- the pack's, and the compiled seed of every country upserts these tables, so
25
+ -- re-applying the seeds is what fills them on an installation that already
26
+ -- exists. Writing a URL for a country in a migration would put a country back
27
+ -- into the core, which is the one thing the pack format exists to prevent.
28
+ --
29
+ -- The key is deliberately *not* a foreign key onto anything. The register
30
+ -- lives in a jsonb column of another table and a pack is upserted one
31
+ -- statement at a time; a constraint between the two would fail on the order
32
+ -- the seed happens to write them in, and would say nothing an inconsistent
33
+ -- pack does not already say. `ekwo pack check` refuses a key the register does
34
+ -- not carry, which is where that check belongs: before the seed is written.
35
+
36
+ alter table country_packs
37
+ add column if not exists sources jsonb not null default '[]'::jsonb;
38
+
39
+ comment on column country_packs.sources is
40
+ 'Register of the texts this pack was built from, in the pack''s own order: [{key, title, publisher, url, consulted_on, kind}]. `kind` is one of law, regulation, form, standard, portal, guidance. Written by the generated seed; never a copy of the text itself.';
41
+
42
+ alter table tax_templates
43
+ add column if not exists source_key text;
44
+
45
+ comment on column tax_templates.source_key is
46
+ 'Key of the entry in country_packs.sources where this tax''s legal_reference can be read. Null where the pack names none.';
47
+
48
+ alter table tax_report_box_templates
49
+ add column if not exists source_key text;
50
+
51
+ comment on column tax_report_box_templates.source_key is
52
+ 'Key of the entry in country_packs.sources where this box''s legal_reference can be read. Null where the pack names none.';
53
+
54
+ -- No object is created and no function is added, so there is nothing to grant
55
+ -- and nothing to revoke: a column added to a table is reachable by whoever
56
+ -- could already select that table, under the policies it already has.
@@ -0,0 +1,45 @@
1
+ -- Ekwo OS — the schema this release defines is 0.3.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
+ -- Between 0.2.0 and here the schema gained what a company works on rather
12
+ -- than what a country prescribes, and a second reader of the books beside
13
+ -- the return. The packages of this release read all of it, and a 0.2.0
14
+ -- database has none of it: `document_shares` with `share_document()`,
15
+ -- `revoke_share()` and `shared_document()`, and `instance.public_base_url`
16
+ -- the returned link is built on; `ec_sales_list()`, the recapitulative
17
+ -- statement of intra-Community supplies; `country_packs.sources` with
18
+ -- `tax_templates.source_key` and `tax_report_box_templates.source_key`, the
19
+ -- register a pack cites its law from; `accounts.pinned` and
20
+ -- `accounts_in_use()`, the part of a chart a company actually works with;
21
+ -- `companies.vat_period` beside `tax_report_templates.periods` and
22
+ -- `country_defaults.vat_period_default`, how often a return is filed; and the
23
+ -- `foreign_services_received` value of `tax_treatment`, the general
24
+ -- business-to-business rule for a service bought from a supplier who is not
25
+ -- established here. So the packages declare 0.3.0 as their floor and refuse
26
+ -- an older database by name, rather than improvising over a column that is
27
+ -- not there.
28
+
29
+ create or replace function ekwo_schema_version()
30
+ returns text
31
+ language sql
32
+ immutable
33
+ as $$
34
+ select '0.3.0'::text;
35
+ $$;
36
+
37
+ comment on function ekwo_schema_version() is
38
+ 'Schema version of the installed release. Bumped by a migration, never by hand.';
39
+
40
+ -- `create or replace` keeps the privileges the function already had, and the
41
+ -- revoke is what every migration of this directory ends with: a function that
42
+ -- comes out with the built-in default is published by Supabase as an
43
+ -- anonymous RPC endpoint.
44
+ revoke execute on all functions in schema public from public;
45
+ grant execute on function ekwo_schema_version() to authenticated, service_role;
@@ -0,0 +1,177 @@
1
+ -- Ekwo OS — a VAT category is a code, not a two-character box.
2
+ --
3
+ -- `taxes.vat_category`, `tax_templates.vat_category` and
4
+ -- `document_lines.vat_category` have been `char(2)` since the day they were
5
+ -- created, and `char(n)` in Postgres pads to width on write. Every category of
6
+ -- EN 16931 but `AE` is one character, so the database answered `S `, `K `,
7
+ -- `E `, `G `, `Z `, `O ` — and `document_line_items` and `document_tax_summary`
8
+ -- published that as BT-151. `S ` is not a code of UNCL5305: a renderer writing
9
+ -- it straight into an invoice emits one that fails validation, a reader
10
+ -- comparing it to `'S'` finds nothing, and since `shared_document()` reads both
11
+ -- views the padded value reached whoever held the link to an invoice.
12
+ --
13
+ -- Nothing here noticed, because the only test that compared the column compared
14
+ -- two databases that pad identically, and `tests/packs.test.ts` trimmed before
15
+ -- it looked. That is written up in `docs/international.md`, where this note is
16
+ -- now closed.
17
+ --
18
+ -- The three columns become `text`. The cast is written out rather than left
19
+ -- implicit: `char` to `text` does drop the trailing blanks, but the rule that
20
+ -- makes it do so is not what anybody reading this file should have to know, and
21
+ -- `nullif` turns a column that held nothing but padding into the null it always
22
+ -- meant. The check constraint is the width made explicit — one or two capital
23
+ -- letters, which is the shape of every UNCL5305 category and of nothing else —
24
+ -- so the column now refuses what it used to manufacture.
25
+ --
26
+ -- `exemption_code` is already `text` on both tables and needs nothing. The
27
+ -- other `char(2)` columns of the schema are ISO 3166 country codes and ISO 639
28
+ -- languages, which are two characters by definition; they stay as they are.
29
+ --
30
+ -- A type change is refused while a view selects the column, so the two views
31
+ -- that publish BT-151 are dropped and recreated below, unchanged but for
32
+ -- existing: same columns in the same order, same `security_invoker`, same
33
+ -- comments, same grants. `shared_document()`, `documents_refresh_totals()` and
34
+ -- `post_document()` read them by name and are untouched — a function does not
35
+ -- record a dependency on a view, so dropping one does not drop them. No trigger
36
+ -- on `document_lines` guards a column, so nothing fires on the rewrite; the
37
+ -- snapshot the line holds keeps the value it was given, minus the space the
38
+ -- column added to it.
39
+
40
+ -- ---------------------------------------------------------------------------
41
+ -- 1. The views that select the column step aside
42
+ -- ---------------------------------------------------------------------------
43
+
44
+ drop view if exists document_line_items;
45
+ drop view if exists document_tax_summary;
46
+
47
+ -- ---------------------------------------------------------------------------
48
+ -- 2. The three columns become codes
49
+ -- ---------------------------------------------------------------------------
50
+
51
+ alter table taxes
52
+ alter column vat_category type text using nullif(rtrim(vat_category), '');
53
+
54
+ alter table taxes
55
+ add constraint taxes_vat_category_format
56
+ check (vat_category is null or vat_category ~ '^[A-Z]{1,2}$');
57
+
58
+ comment on column taxes.vat_category is
59
+ 'EN 16931 BT-118 / BT-151 category code, as UNCL5305 writes it: S, Z, E, AE, K, G, O, L, M. One or two capitals, never padded.';
60
+
61
+ alter table tax_templates
62
+ alter column vat_category type text using nullif(rtrim(vat_category), '');
63
+
64
+ alter table tax_templates
65
+ add constraint tax_templates_vat_category_format
66
+ check (vat_category is null or vat_category ~ '^[A-Z]{1,2}$');
67
+
68
+ comment on column tax_templates.vat_category is
69
+ 'EN 16931 BT-118 / BT-151 category code the pack declares for this tax, as UNCL5305 writes it.';
70
+
71
+ alter table document_lines
72
+ alter column vat_category type text using nullif(rtrim(vat_category), '');
73
+
74
+ alter table document_lines
75
+ add constraint document_lines_vat_category_format
76
+ check (vat_category is null or vat_category ~ '^[A-Z]{1,2}$');
77
+
78
+ comment on column document_lines.vat_category is
79
+ 'EN 16931 BT-151 as the line carries it, snapshotted from the tax when the line was written so a later rate change cannot rewrite history.';
80
+
81
+ -- ---------------------------------------------------------------------------
82
+ -- 3. The views come back
83
+ --
84
+ -- Recreated from their last published definitions — `document_line_items` from
85
+ -- `20260912111751`, `document_tax_summary` from `20260914121200` — with
86
+ -- nothing changed but the type they now hand back for BT-151.
87
+ -- ---------------------------------------------------------------------------
88
+
89
+ create view document_tax_summary
90
+ with (security_invoker = true) as
91
+ select l.document_id,
92
+ l.company_id,
93
+ d.doc_type,
94
+ l.tax_id,
95
+ t.code as tax_code,
96
+ t.name as tax_name,
97
+ t.vat_category,
98
+ t.amount as tax_rate,
99
+ sum(l.amount_untaxed) as base_amount,
100
+ -- Gross tax: what the VAT return reports.
101
+ round_amount(sum(l.amount_untaxed) * coalesce(t.amount, 0) / 100,
102
+ rounding_of(l.company_id, d.currency_code)) as tax_amount,
103
+ -- Charged tax: what the other party actually pays. Zero when the tax
104
+ -- postings net out, which is exactly what self-assessment means.
105
+ round_amount(
106
+ sum(l.amount_untaxed) * coalesce(t.amount, 0) / 100
107
+ * coalesce((
108
+ select sum(tp.factor_percent)
109
+ from tax_postings tp
110
+ where tp.tax_id = t.id
111
+ and tp.posting_type in ('tax', 'tax_on_base')
112
+ and tp.document_kind = case
113
+ when d.doc_type in ('sale_credit_note', 'purchase_credit_note')
114
+ then 'credit_note'::tax_document_kind
115
+ else 'invoice'::tax_document_kind
116
+ end
117
+ ), 100) / 100,
118
+ rounding_of(l.company_id, d.currency_code)) as tax_charged
119
+ from document_lines l
120
+ join documents d on d.id = l.document_id
121
+ left join taxes t on t.id = l.tax_id
122
+ where l.line_type = 'product'
123
+ group by l.document_id, l.company_id, d.doc_type, d.currency_code, l.tax_id,
124
+ t.id, t.code, t.name, t.vat_category, t.amount;
125
+
126
+ comment on view document_tax_summary is
127
+ 'VAT breakdown of a document, one row per tax, rounded on the group basis (EN 16931 BR-CO-14).';
128
+
129
+ create view document_line_items
130
+ with (security_invoker = true) as
131
+ select l.id as document_line_id,
132
+ l.document_id,
133
+ l.company_id,
134
+ l.sequence,
135
+ l.line_type,
136
+ l.name as item_name, -- BT-153
137
+ l.description as item_description, -- BT-154
138
+ p.code as seller_item_identifier, -- BT-155
139
+ l.product_id,
140
+ p.kind as product_kind,
141
+ l.quantity, -- BT-129
142
+ l.unit_code, -- BT-130
143
+ l.unit_price, -- BT-146
144
+ l.discount_percent,
145
+ l.amount_untaxed, -- BT-131
146
+ l.tax_id,
147
+ l.vat_category, -- BT-151
148
+ l.vat_rate, -- BT-152
149
+ l.account_id,
150
+ t.treatment as tax_treatment,
151
+ t.exemption_code as tax_exemption_code, -- BT-121
152
+ t.cash_basis as tax_cash_basis
153
+ from document_lines l
154
+ left join products p on p.id = l.product_id
155
+ left join taxes t on t.id = l.tax_id;
156
+
157
+ comment on view document_line_items is
158
+ 'Document lines with the EN 16931 item terms — BT-153 name, BT-154 description, BT-155 the seller identifier — and what decides a legal mention on the line: the treatment of its tax, its exemption reason (BT-121) and whether the tax falls due on collection.';
159
+
160
+ -- ---------------------------------------------------------------------------
161
+ -- 4. The grants the drop took away
162
+ --
163
+ -- A dropped view takes its privileges with it, so both are granted again by
164
+ -- name, to exactly who held them before: `authenticated` and `service_role`
165
+ -- select, `anon` nothing. Both are `security_invoker`, so the grant is only
166
+ -- half of what a reader needs — the tables below still judge them under their
167
+ -- own policies. The anonymous reader of a shared invoice never touches either:
168
+ -- `shared_document()` is `security definer` and reads them as its owner.
169
+ -- ---------------------------------------------------------------------------
170
+
171
+ revoke all on table document_tax_summary from public, anon;
172
+ revoke all on table document_line_items from public, anon;
173
+
174
+ grant select on table
175
+ document_tax_summary,
176
+ document_line_items
177
+ to authenticated, service_role;
@@ -0,0 +1,85 @@
1
+ -- Ekwo OS — the article behind what a country puts on an invoice.
2
+ --
3
+ -- `20260912111751_document_rules.sql` moved the document rules of a country
4
+ -- into the pack: whether the numbering may skip, what a number looks like,
5
+ -- the payment term the law sets, when the tax falls due, the structured
6
+ -- invoice the country expects. Every one of them arrived as a word — a
7
+ -- `gapless_per_year`, a `30`, an `invoice_date`, a `peppol-bis-3` — and not
8
+ -- one of them arrived with the article that says so.
9
+ --
10
+ -- That is a narrower gap than it looks. Two places in this schema already
11
+ -- refuse a rule nobody can trace: `legal_mention_templates.legal_reference`
12
+ -- says which article requires a sentence, and `tax_templates.source_key` and
13
+ -- `tax_report_box_templates.source_key`, added the day the register landed,
14
+ -- say which text that article is read in. A rate cites a decree and a grid
15
+ -- cites a form, while the rule that decides how every invoice of the country
16
+ -- is numbered cited nothing — and a word looks exactly the same whether
17
+ -- somebody read the decree or guessed.
18
+ --
19
+ -- Eight columns, four pairs, one per rule:
20
+ --
21
+ -- numbering the article requiring a sequential, uniquely identifying
22
+ -- number, and the shape of that number where a country
23
+ -- prescribes one — `numbering_gapless` and `number_format`
24
+ -- answer the same article, so they share one citation
25
+ -- payment_terms the article setting `legal_payment_days` in the absence
26
+ -- of an agreement. Not the interest and the recovery
27
+ -- indemnity, which are `late_payment_reference`: that one
28
+ -- is a sentence a renderer prints, this one is a citation
29
+ -- tax_point the article fixing `tax_point_rule`
30
+ -- einvoice the text making `einvoice_profile` obligatory from
31
+ -- `einvoice_mandatory_from`. The pack format has carried
32
+ -- `einvoicing.legal_reference` since the section existed
33
+ -- and all four packs write it; the compiler dropped it on
34
+ -- the floor, which is what this column ends
35
+ --
36
+ -- Four pairs and not one citation for the whole section, because they are
37
+ -- four articles of three or four different texts in every country the packs
38
+ -- cover: Belgium numbers an invoice under a royal decree of 1992, counts a
39
+ -- payment term under a law of 2002, dates its tax under the VAT code and owes
40
+ -- its e-invoice to a law of 2024. One column would have held all four in one
41
+ -- string, and then no rule would have had a citation of its own.
42
+ --
43
+ -- **Additive, and nullable without a default**, for the reason that migration
44
+ -- gave for the rules themselves: an article invented for a country that has
45
+ -- not spoken is one country's law written on another's invoice. A pack that
46
+ -- cites nothing leaves null, and `ekwo pack check` is where that is answered
47
+ -- for — it refuses a declared rule with no article on a `reviewed` pack and
48
+ -- warns about one on any other, before a seed is ever written.
49
+ --
50
+ -- `source_key` is not a foreign key, for the reason `20260915161842` gave:
51
+ -- the register lives in a jsonb column of `country_packs`, a pack is upserted
52
+ -- one statement at a time, and a constraint between the two would fail on the
53
+ -- order the seed happens to write them in. `ekwo pack check` refuses a key the
54
+ -- register does not carry, which is where that check belongs.
55
+
56
+ alter table country_defaults
57
+ add column if not exists numbering_legal_reference text,
58
+ add column if not exists numbering_source_key text,
59
+ add column if not exists payment_terms_legal_reference text,
60
+ add column if not exists payment_terms_source_key text,
61
+ add column if not exists tax_point_legal_reference text,
62
+ add column if not exists tax_point_source_key text,
63
+ add column if not exists einvoice_legal_reference text,
64
+ add column if not exists einvoice_source_key text;
65
+
66
+ comment on column country_defaults.numbering_legal_reference is
67
+ 'The article requiring a sequential, uniquely identifying invoice number, and the shape of that number where the country prescribes one. Covers numbering_gapless and number_format together: both answer the same article.';
68
+ comment on column country_defaults.numbering_source_key is
69
+ 'Key of the entry in country_packs.sources where numbering_legal_reference can be read. Null where the pack names none.';
70
+ comment on column country_defaults.payment_terms_legal_reference is
71
+ 'The article setting legal_payment_days in the absence of an agreement. Distinct from late_payment_reference, which says where the interest and the recovery indemnity come from and is written to be printed.';
72
+ comment on column country_defaults.payment_terms_source_key is
73
+ 'Key of the entry in country_packs.sources where payment_terms_legal_reference can be read. Null where the pack names none.';
74
+ comment on column country_defaults.tax_point_legal_reference is
75
+ 'The article fixing tax_point_rule. Where the value is a derogation rather than the country''s principle, the reference says which, so a reader is not left believing the pack read the wrong article.';
76
+ comment on column country_defaults.tax_point_source_key is
77
+ 'Key of the entry in country_packs.sources where tax_point_legal_reference can be read. Null where the pack names none.';
78
+ comment on column country_defaults.einvoice_legal_reference is
79
+ 'The text making einvoice_profile obligatory from einvoice_mandatory_from. Where reception and emission start on different days, the emission calendar is written out here; where a country has several registration identifiers, this is where the ones party_scheme could not hold are named.';
80
+ comment on column country_defaults.einvoice_source_key is
81
+ 'Key of the entry in country_packs.sources where einvoice_legal_reference can be read. Null where the pack names none.';
82
+
83
+ -- No object is created and no function is added, so there is nothing to grant
84
+ -- and nothing to revoke: a column added to a table is reachable by whoever
85
+ -- could already select that table, under the policies it already has.