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,144 @@
1
+ -- Ekwo OS — the words a country with no value added tax needed.
2
+ --
3
+ -- The first pack of a country outside the common system of VAT — sales tax
4
+ -- and use tax, `kind` `sales_tax`, nothing recoverable at any stage — asked
5
+ -- the vocabulary three questions it could not answer. Two of them are here;
6
+ -- the third is a rule of `ekwo pack check` and touches no table.
7
+ --
8
+ -- ## A tax the buyer assesses on themselves, which is not a reverse charge
9
+ --
10
+ -- `tax_treatment` had `domestic_reverse_charge` for the case where national
11
+ -- law moves the liability for **the value added tax** from a supplier
12
+ -- established in the buyer's country to the buyer, and
13
+ -- `foreign_services_received` for the general business-to-business rule of
14
+ -- articles 44 and 196 of Directive 2006/112/EC. Both are operations of a
15
+ -- system in which the buyer, having charged themselves, deducts the same
16
+ -- amount at the other end; both sit behind an invoice a supplier issued and
17
+ -- was relieved on.
18
+ --
19
+ -- California's use tax is none of that. Section 6201 of the Revenue and
20
+ -- Taxation Code imposes an excise tax on the storage, use or other consumption
21
+ -- in the State of tangible personal property purchased from any retailer, and
22
+ -- section 6202(a) makes the person storing, using or consuming it liable for
23
+ -- it. There is no exempt supply behind it, no supplier who was relieved of
24
+ -- anything, no recapitulative statement, and nothing at all is recovered: the
25
+ -- tax is a cost, which is why the same document carries a `tax_on_base`
26
+ -- posting. `packs/us/` said `domestic_reverse_charge` because that was the
27
+ -- only word for a liability sitting with the buyer, and wrote into its own
28
+ -- `legal_reference` that it was not one — a pack contradicting itself in
29
+ -- prose, which `docs/international.md` recorded as a gap the day the pack
30
+ -- landed.
31
+ --
32
+ -- `self_assessed` is that word: **a tax a buyer owes directly to an
33
+ -- administration under that administration's own law, and computes and
34
+ -- declares themselves.** It says nothing about a supplier, because there may
35
+ -- be no supplier the levying State can reach, and nothing about recovery,
36
+ -- because that is what the postings say.
37
+ --
38
+ -- It is not refused inside the common system, and the restraint is
39
+ -- deliberate: a Member State levying a duty of its own that a buyer
40
+ -- self-assesses would be describing this and not article 194. What tells the
41
+ -- two apart is the law each tax cites, which every tax already carries.
42
+ --
43
+ -- The value is placed beside `domestic_reverse_charge` so that the two
44
+ -- mechanisms in which a buyer charges themselves read together, in the enum,
45
+ -- in `TAX_TREATMENTS` and in the pack schema — the one ordering
46
+ -- `tests/vat_codes.test.ts` holds across the three — and so that the four
47
+ -- intra-Community supplies stay contiguous after it.
48
+ --
49
+ -- Nothing in the ledger branches on a treatment, here or anywhere. What a tax
50
+ -- *does* is said by its postings. What this value changes is what a pack is
51
+ -- allowed to say about the tax's EN 16931 category — a buyer assessing a tax
52
+ -- on themselves under a State's own law holds no invoice the standard
53
+ -- governs, so there is no category of a supplier's to record.
54
+ --
55
+ -- ## What an exemption depends on
56
+ --
57
+ -- A sale for resale is untaxed because the seller holds a resale certificate:
58
+ -- section 6091 presumes every receipt taxable until they take one from the
59
+ -- purchaser, and Regulation 1668 says what it has to contain. A seller must
60
+ -- collect in a State where they have economic nexus, which since *South
61
+ -- Dakota v. Wayfair* is a running total of sales into it. A sale of food is
62
+ -- untaxed under section 6359 unless it is hot, or carbonated, or alcoholic, or
63
+ -- eaten where admission was charged.
64
+ --
65
+ -- Three exemptions, three answers that are not in the books, and one column of
66
+ -- `tax_templates` that carried none of it: a pack could state the code a
67
+ -- bookkeeper reaches for **once the answer is known** and could not say what
68
+ -- the question was. A reader of the chart saw three zero-rated codes and one
69
+ -- long sentence each.
70
+ --
71
+ -- `conditions` is the smallest thing that says it: **what the exemption turns
72
+ -- on, and never how to evaluate it.** A closed vocabulary of five words, no
73
+ -- value beside any of them — no threshold amount, no certificate number, no
74
+ -- operator and no expression — because a pack that could carry the test would
75
+ -- be a pack that executes, which is the one thing this format exists not to
76
+ -- be. The amount of a threshold and the contents of a certificate are in the
77
+ -- article the tax already cites; what is recorded here is that there **is** a
78
+ -- certificate, and that there **is** a threshold, so that an application can
79
+ -- put the question to a human being instead of pretending to answer it.
80
+ --
81
+ -- `buyer_certificate` the buyer hands the seller a document the seller has
82
+ -- to hold and be able to produce.
83
+ -- `buyer_status` a quality of the buyer the statute names — a
84
+ -- government, a body the law exempts as such.
85
+ -- `transport_evidence` proof that what was sold went where the exemption
86
+ -- requires it to have gone.
87
+ -- `seller_threshold` a running total the seller crossed, or has not.
88
+ -- `supply_nature` what is supplied, classified more finely than any
89
+ -- ledger holds it.
90
+ --
91
+ -- It stops at `tax_templates` and does not reach `taxes`, exactly as
92
+ -- `source_key` does and for the same reason: this is the pack's transcription
93
+ -- of a country's rule, not a property of the tax a company went on to edit.
94
+ -- A company's `taxes` row carries `country` and `code`, which is the join, and
95
+ -- nothing in the ledger reads either column.
96
+ --
97
+ -- Two halves of the American note are **not** closed by this and are written
98
+ -- up in `docs/international.md`: there is still no place on a contact for a
99
+ -- certificate and its validity, and no place anywhere for a rolling total per
100
+ -- territory. Both are larger than the pack format — one is document
101
+ -- management and the other is reporting — and neither is invented here.
102
+ --
103
+ -- ## Which entry of a register is the list BT-121 comes from
104
+ --
105
+ -- The third change is one line of a comment. `vatRegime()` used to take the
106
+ -- **first** entry of `certification.sources` whose `kind` was `standard` and
107
+ -- treat its title as the published list an exemption reason code outside the
108
+ -- Union may be taken from. `standard` means "a technical norm or code list",
109
+ -- which the FASB Accounting Standards Codification and FRS 102 both are, so
110
+ -- naming an accounting standard silently authorised a reason code on any tax
111
+ -- of the pack. No pack carries one and nothing wrong was ever emitted; the
112
+ -- mechanism was a trap all the same. An entry now says so of itself, with
113
+ -- `reason_codes`, and `ekwo pack check` refuses a second one and refuses the
114
+ -- flag on an entry that is not a `standard`. The register is a jsonb column,
115
+ -- so the shape it documents is the only thing here that moves.
116
+ --
117
+ -- A value added to an enum cannot be used in the transaction that adds it.
118
+ -- Nothing below uses `self_assessed`; the seeds that do are applied after.
119
+
120
+ alter type tax_treatment add value 'self_assessed' after 'domestic_reverse_charge';
121
+
122
+ -- What an exemption or a rate turns on, where the answer is not in the books.
123
+ -- A closed vocabulary and never a test: no value, no operator, no expression.
124
+ create type tax_condition as enum (
125
+ 'buyer_certificate',
126
+ 'buyer_status',
127
+ 'transport_evidence',
128
+ 'seller_threshold',
129
+ 'supply_nature'
130
+ );
131
+
132
+ alter table tax_templates
133
+ add column if not exists conditions tax_condition[] not null default '{}'::tax_condition[];
134
+
135
+ comment on column tax_templates.conditions is
136
+ 'What this tax turns on that the ledger cannot see, from a closed vocabulary: buyer_certificate, buyer_status, transport_evidence, seller_threshold, supply_nature. It says what the question is, never how to answer it — there is no value, no operator and no expression here, and the article that sets a threshold or prescribes a certificate is in legal_reference. Written by the generated seed; read by nothing in the ledger.';
137
+
138
+ comment on column country_packs.sources is
139
+ 'Register of the texts this pack was built from, in the pack''s own order: [{key, title, publisher, url, consulted_on, kind, reason_codes}]. `kind` is one of law, regulation, form, standard, portal, guidance. `reason_codes` is true on the one entry — at most one, and a `standard` — that publishes the list an exemption reason code of this country comes from; absent everywhere else. Written by the generated seed; never a copy of the text itself.';
140
+
141
+ -- No table, view or function is created. A type is reachable by whoever can
142
+ -- already read the column that uses it, and a column added to a table is
143
+ -- reachable by whoever could already select that table, under the policies it
144
+ -- already has. So there is nothing to grant and nothing to revoke.
@@ -0,0 +1,525 @@
1
+ -- Ekwo OS — a box of a declaration can be a rate applied to another box, and
2
+ -- the order a form is printed in stops deciding the order it is worked out in.
3
+ --
4
+ -- Two changes, and they are one change: the second is what the first needs to
5
+ -- be safe.
6
+ --
7
+ -- ---------------------------------------------------------------------------
8
+ -- 1. `rate` and `rate_of_box`
9
+ -- ---------------------------------------------------------------------------
10
+ --
11
+ -- Until now a computed box was a list of boxes to add and a list to subtract.
12
+ -- That covers every European return this repository carries, because a
13
+ -- European return reports a tax the ledger already holds: the amount was
14
+ -- worked out document by document, posted, and the form only adds it up.
15
+ --
16
+ -- A form that is not a value added tax return does not work that way.
17
+ -- CDTFA-401-A states four of its lines as a multiplication in as many words:
18
+ -- line 13 is line 12 times 0.06, line 14 is line 12 times 0.0025, line 15 is
19
+ -- line 12 times 0.01, and Sections C and D are a base times 0.05 and times
20
+ -- 0.039375. The taxable total is worked out once, for the period, and the
21
+ -- rates are applied to it.
22
+ --
23
+ -- **A rate is not an expression.** It is the one arithmetic a declaration form
24
+ -- actually writes out, and it is said here with two named fields and no
25
+ -- syntax: `rate` is a percentage and `rate_of_box` is the box it applies to.
26
+ -- There is still nothing a pack can execute, nothing to parse, and a reviewer
27
+ -- reads `6.00 of box 12` in the diff. The alternative — an expression language
28
+ -- — is the thing `20260912090407` refused and this does not reopen it.
29
+ --
30
+ -- Three rules hold it in place, as constraints rather than as conventions:
31
+ --
32
+ -- * a rate names a box, and a box named by a rate needs a rate: the pair is
33
+ -- declared together or not at all;
34
+ -- * only a computed box carries one, which is the rule `plus` and `minus`
35
+ -- already follow — `kind` says how a box gets its amount, and a box the
36
+ -- ledger fills cannot also be derived;
37
+ -- * a rate and a list are two ways of computing one box, so a box takes one
38
+ -- or the other. A box that was both would be a formula, quietly.
39
+ --
40
+ -- A box that names itself is refused here too, by name, rather than left to
41
+ -- the evaluator's cycle detection: `rate_of_box` is one reference, so the
42
+ -- shortest cycle is visible to a `check`.
43
+ --
44
+ -- ---------------------------------------------------------------------------
45
+ -- 2. `print_sequence`
46
+ -- ---------------------------------------------------------------------------
47
+ --
48
+ -- `sequence` has meant two things at once since the boxes became data: the
49
+ -- order a form prints its boxes in, and the order they are worked out in.
50
+ -- Three packs have now paid for that. Luxembourg's eCDF return prints a
51
+ -- subtotal above the boxes it adds up; Estonia escaped it by luck; and
52
+ -- CDTFA-401-A prints line 11 on page 1 and computes it from Sections A and B
53
+ -- on page 3, so `packs/us` orders its form by dependency and the order the
54
+ -- administration prints it in is lost.
55
+ --
56
+ -- `evaluate_totals()` has worked the totals out in the order they depend on
57
+ -- each other since `20260912104719`, so the evaluation half of the conflation
58
+ -- was already fiction: what remained was a rule in `ekwo pack check` refusing
59
+ -- a total that names a total declared after it, which forced a pack to spend
60
+ -- its one ordering field on the evaluator. That rule goes, replaced by the
61
+ -- cycle check the statements already have, and `print_sequence` carries the
62
+ -- order the form is printed in where it differs from the order the pack
63
+ -- declares its boxes in.
64
+ --
65
+ -- Null means "the same as `sequence`", which is what every pack written before
66
+ -- this said, and `vat_return()` answers the resolved value so a renderer has
67
+ -- one column to order by and never two.
68
+ --
69
+ -- A rate makes the separation necessary rather than merely tidy: a box worked
70
+ -- out from another box has a dependency the form's own print order knows
71
+ -- nothing about, and a pack should not have to choose which of the two it
72
+ -- writes down.
73
+
74
+ -- ---------------------------------------------------------------------------
75
+ -- The columns
76
+ -- ---------------------------------------------------------------------------
77
+
78
+ alter table tax_report_box_templates
79
+ add column if not exists rate numeric,
80
+ add column if not exists rate_of_box text,
81
+ add column if not exists print_sequence integer;
82
+
83
+ comment on column tax_report_box_templates.rate is
84
+ 'Percentage this box applies to the box named by rate_of_box. The one arithmetic a declaration form writes out; not an expression, and never a second way to say plus.';
85
+ comment on column tax_report_box_templates.rate_of_box is
86
+ 'The box the rate is applied to, bare or qualified with its kind (`12:total`), resolved the way a plus reference is.';
87
+ comment on column tax_report_box_templates.print_sequence is
88
+ 'Where the administration prints this box, when that is not where the pack declares it. Null means the same as sequence: a form prints a subtotal above what it adds up, and the evaluation order is the dependencies and never this.';
89
+
90
+ alter table tax_report_box_templates
91
+ add constraint tax_report_box_templates_rate_names_a_box
92
+ check ((rate is null) = (rate_of_box is null)),
93
+ add constraint tax_report_box_templates_rate_is_a_total
94
+ check (rate is null or kind = 'total'),
95
+ add constraint tax_report_box_templates_rate_or_a_list
96
+ check (rate is null or (plus_boxes = '{}'::text[] and minus_boxes = '{}'::text[])),
97
+ add constraint tax_report_box_templates_rate_is_not_itself
98
+ check (rate_of_box is null or split_part(rate_of_box, ':', 1) <> box);
99
+
100
+ -- ---------------------------------------------------------------------------
101
+ -- evaluate_totals — the one evaluator, which now knows one more shape
102
+ -- ---------------------------------------------------------------------------
103
+ --
104
+ -- Replaced whole, because a function is replaced whole in PostgreSQL. The
105
+ -- signature does not move, so there is nothing to drop and nothing to grant
106
+ -- again. Everything but the rate is `20260914121200` unchanged.
107
+ --
108
+ -- A formula may now carry `rate` and `rate_of` instead of `plus` and `minus`.
109
+ -- It is the same machine either way: the reference set decides when the
110
+ -- formula is ready, and a pass that settles nothing is still a cycle that says
111
+ -- which keys are in it. A statement passes neither field and reads exactly as
112
+ -- it did.
113
+
114
+ create or replace function evaluate_totals(
115
+ p_values jsonb,
116
+ p_formulas jsonb,
117
+ p_rounding money_rounding,
118
+ p_keep_zero boolean default false
119
+ )
120
+ returns jsonb
121
+ language plpgsql
122
+ immutable
123
+ as $$
124
+ declare
125
+ v_values jsonb := coalesce(p_values, '{}'::jsonb);
126
+ v_out jsonb := '{}'::jsonb;
127
+ v_done jsonb := '{}'::jsonb;
128
+ v_all jsonb := coalesce(p_formulas, '[]'::jsonb);
129
+ v_left integer;
130
+ v_settled integer;
131
+ v_ready boolean;
132
+ v_amount numeric;
133
+ v_part numeric;
134
+ v_refs text[];
135
+ v_ref text;
136
+ v_key text;
137
+ v_rate numeric;
138
+ v_of text;
139
+ v_stuck text;
140
+ f jsonb;
141
+ begin
142
+ select count(*) into v_left from jsonb_array_elements(v_all);
143
+
144
+ while v_left > 0 loop
145
+ v_settled := 0;
146
+
147
+ for f in
148
+ select t.x from jsonb_array_elements(v_all) with ordinality as t(x, ord)
149
+ order by coalesce((t.x ->> 'sequence')::integer, 0), t.ord
150
+ loop
151
+ v_key := f ->> 'key';
152
+ if v_done ? v_key then
153
+ continue;
154
+ end if;
155
+
156
+ v_rate := (f ->> 'rate')::numeric;
157
+ v_of := f ->> 'rate_of';
158
+
159
+ -- Every reference this formula reads, whichever shape it is written in.
160
+ -- A rate has exactly one, and it is held to the same readiness rule as a
161
+ -- member of a plus list: a box worked out from a box has to wait for it.
162
+ select coalesce(array_agg(e.value), '{}'::text[]) into v_refs
163
+ from (
164
+ select jsonb_array_elements_text(coalesce(f -> 'plus', '[]'::jsonb)) as value
165
+ union all
166
+ select jsonb_array_elements_text(coalesce(f -> 'minus', '[]'::jsonb))
167
+ union all
168
+ select v_of where v_of is not null
169
+ ) as e;
170
+
171
+ -- Ready when every reference that names another formula has been worked
172
+ -- out already.
173
+ v_ready := true;
174
+ foreach v_ref in array v_refs loop
175
+ if exists (
176
+ select 1 from jsonb_array_elements(v_all) as g(x)
177
+ where (g.x ->> 'key') <> v_key
178
+ and not (v_done ? (g.x ->> 'key'))
179
+ and case when strpos(v_ref, ':') > 0
180
+ then (g.x ->> 'key') = replace(v_ref, ':', '|')
181
+ else split_part((g.x ->> 'key'), '|', 1) = v_ref
182
+ end
183
+ ) then
184
+ v_ready := false;
185
+ end if;
186
+ end loop;
187
+ if not v_ready then
188
+ continue;
189
+ end if;
190
+
191
+ if v_of is not null then
192
+ -- A rate: one reference, resolved exactly as a plus reference is, and
193
+ -- a percentage applied to it.
194
+ select coalesce(sum(e.value::numeric), 0) into v_part
195
+ from jsonb_each_text(v_values) as e(key, value)
196
+ where case when strpos(v_of, ':') > 0
197
+ then e.key = replace(v_of, ':', '|')
198
+ else split_part(e.key, '|', 1) = v_of
199
+ end;
200
+ v_amount := v_part * v_rate / 100;
201
+ else
202
+ v_amount := 0;
203
+ for v_ref in
204
+ select jsonb_array_elements_text(coalesce(f -> 'plus', '[]'::jsonb))
205
+ loop
206
+ select coalesce(sum(e.value::numeric), 0) into v_part
207
+ from jsonb_each_text(v_values) as e(key, value)
208
+ where case when strpos(v_ref, ':') > 0
209
+ then e.key = replace(v_ref, ':', '|')
210
+ else split_part(e.key, '|', 1) = v_ref
211
+ end;
212
+ v_amount := v_amount + v_part;
213
+ end loop;
214
+ for v_ref in
215
+ select jsonb_array_elements_text(coalesce(f -> 'minus', '[]'::jsonb))
216
+ loop
217
+ select coalesce(sum(e.value::numeric), 0) into v_part
218
+ from jsonb_each_text(v_values) as e(key, value)
219
+ where case when strpos(v_ref, ':') > 0
220
+ then e.key = replace(v_ref, ':', '|')
221
+ else split_part(e.key, '|', 1) = v_ref
222
+ end;
223
+ v_amount := v_amount - v_part;
224
+ end loop;
225
+ end if;
226
+
227
+ -- The floor belongs to the pair it splits — the Belgian 71 and 72, the
228
+ -- French 25 and 28 — so it applies before the sign the caller reads the
229
+ -- line with.
230
+ if coalesce((f ->> 'floor_zero')::boolean, false) then
231
+ v_amount := greatest(v_amount, 0);
232
+ end if;
233
+ v_amount := round_amount(v_amount * coalesce((f ->> 'factor')::numeric, 1), p_rounding);
234
+
235
+ v_values := v_values || jsonb_build_object(v_key, v_amount);
236
+ v_done := v_done || jsonb_build_object(v_key, true);
237
+ if p_keep_zero or v_amount <> 0 then
238
+ v_out := v_out || jsonb_build_object(v_key, v_amount);
239
+ end if;
240
+ v_settled := v_settled + 1;
241
+ v_left := v_left - 1;
242
+ end loop;
243
+
244
+ if v_settled = 0 then
245
+ select string_agg(t.x ->> 'key', ', ' order by t.x ->> 'key') into v_stuck
246
+ from jsonb_array_elements(v_all) as t(x)
247
+ where not (v_done ? (t.x ->> 'key'));
248
+ raise exception 'formula_cycle: these totals depend on each other and on nothing else: %', v_stuck;
249
+ end if;
250
+ end loop;
251
+
252
+ return v_out;
253
+ end;
254
+ $$;
255
+
256
+ comment on function evaluate_totals(jsonb, jsonb, money_rounding, boolean) is
257
+ 'Works out the totals of a declaration form or of a financial statement — a plus/minus list, or a rate applied to one other key — in the order they depend on each other. The one place that calculation lives: vat_return() and financial_statement() both call it.';
258
+
259
+ -- ---------------------------------------------------------------------------
260
+ -- vat_return — passes the rate through, and answers the print order
261
+ -- ---------------------------------------------------------------------------
262
+ --
263
+ -- Dropped and recreated rather than replaced, because the returned table gains
264
+ -- a column and PostgreSQL will not change that in place. The three-argument
265
+ -- call every client makes keeps working: `p_report_code` still defaults.
266
+ --
267
+ -- Two changes, and everything else is `20260916094500` unchanged:
268
+ --
269
+ -- * the formulas handed to the evaluator carry `rate` and `rate_of`, so a
270
+ -- box stated as a percentage of another box is worked out by the same
271
+ -- function as every other total;
272
+ -- * every row answers `print_sequence`, resolved — the box's own where it
273
+ -- declares one, `sequence` where it does not — so a renderer orders by one
274
+ -- column. The rows themselves still come back in `sequence` order, which
275
+ -- is the order the pack declares and what every caller reads today.
276
+
277
+ drop function if exists vat_return(uuid, date, date, text);
278
+
279
+ create or replace function vat_return(
280
+ p_company_id uuid,
281
+ p_from date,
282
+ p_to date,
283
+ p_report_code text default null
284
+ )
285
+ returns table (
286
+ box text,
287
+ kind text,
288
+ amount numeric,
289
+ computed boolean,
290
+ name text,
291
+ sequence integer,
292
+ print_sequence integer,
293
+ hidden boolean,
294
+ report_code text
295
+ )
296
+ language plpgsql
297
+ stable
298
+ as $$
299
+ declare
300
+ -- 'box|kind' -> amount, for every box summed from the ledger, then the
301
+ -- totals `evaluate_totals()` derives from them. The key carries the kind
302
+ -- because the French CA3 puts a base and a tax on line 08 and a formula has
303
+ -- to be able to name one of them.
304
+ v_values jsonb := '{}'::jsonb;
305
+ v_formulas jsonb := '[]'::jsonb;
306
+ v_totals jsonb := '{}'::jsonb;
307
+ v_rows jsonb := '[]'::jsonb;
308
+ v_country char(2);
309
+ v_report text;
310
+ v_in char(2);
311
+ v_count integer;
312
+ v_codes text;
313
+ -- How often this company files, what the form accepts, and what the two
314
+ -- dates asked for actually are.
315
+ v_files declaration_period;
316
+ v_accepts declaration_period[];
317
+ v_asked declaration_period;
318
+ -- A declaration figure is not a ledger figure, but it is written in the
319
+ -- same currency and with the same decimals.
320
+ v_round money_rounding;
321
+ r record;
322
+ begin
323
+ select c.fiscal_country into v_country
324
+ from companies c where c.id = p_company_id;
325
+ if not found then
326
+ raise exception 'unknown_company: %', p_company_id;
327
+ end if;
328
+ v_round := rounding_of(p_company_id);
329
+
330
+ -- Which form. The caller names one, or the country files exactly one on
331
+ -- that date. Two and no name is a question only the caller can answer — a
332
+ -- Canadian company files the federal return and the Québec one at once — so
333
+ -- this asks instead of guessing.
334
+ if p_report_code is not null then
335
+ select t.country, t.code into v_in, v_report
336
+ from tax_report_templates t
337
+ where t.code = p_report_code
338
+ and t.valid_from <= p_to
339
+ and (t.valid_to is null or t.valid_to >= p_to)
340
+ order by t.country
341
+ limit 1;
342
+ if v_report is null then
343
+ raise exception 'unknown_tax_report: % is not a declaration form in force on %',
344
+ p_report_code, p_to;
345
+ end if;
346
+ else
347
+ select count(*), min(t.code), string_agg(t.code, ', ' order by t.code)
348
+ into v_count, v_report, v_codes
349
+ from tax_report_templates t
350
+ where t.country = v_country
351
+ and t.is_periodic_return
352
+ and t.valid_from <= p_to
353
+ and (t.valid_to is null or t.valid_to >= p_to);
354
+ if v_count > 1 then
355
+ raise exception 'ambiguous_tax_report: % files several declarations on % (%); name one',
356
+ v_country, p_to, v_codes;
357
+ end if;
358
+ v_in := v_country;
359
+ if v_count = 0 then
360
+ v_report := null; -- no pack for this country: the ledger boxes, and no total.
361
+ end if;
362
+ end if;
363
+
364
+ -- The period asked for against the one this company files **this form** on.
365
+ -- Four things have to hold before this refuses, and the fourth is what keeps
366
+ -- it out of everybody's way: the company has recorded a cadence for this
367
+ -- declaration, the form is filed on that cadence, the dates are themselves a
368
+ -- whole cadence of that form, and the two are not the same. A fortnight, a
369
+ -- half-year, a form the company has recorded nothing about — none of those is
370
+ -- a filing on the wrong cadence, and none of them is refused.
371
+ if v_report is not null then
372
+ v_files := filing_period(p_company_id, v_report);
373
+ if v_files is not null then
374
+ select t.periods into v_accepts
375
+ from tax_report_templates t
376
+ where t.country = v_in and t.code = v_report;
377
+ v_asked := declaration_period_of(p_from, p_to);
378
+ if v_asked is not null
379
+ and v_files = any(v_accepts)
380
+ and v_asked = any(v_accepts)
381
+ and v_asked <> v_files then
382
+ raise exception
383
+ 'wrong_declaration_period: this company files % returns on %; % to % is a %',
384
+ v_files, v_report, p_from, p_to, v_asked;
385
+ end if;
386
+ end if;
387
+ end if;
388
+
389
+ -- 1. What the tax postings wrote on the ledger, in every box each of them
390
+ -- names. A line carries the box it is known by; the posting behind it
391
+ -- carries the whole list, which is one box for all but the handful of
392
+ -- forms that print a figure twice. No country rule here either: the
393
+ -- expansion is `unnest`, and which boxes there are is the pack's answer.
394
+ for r in
395
+ with lines as (
396
+ select l.declaration_box as lbox,
397
+ case when l.tax_line then 'tax' else 'base' end as lkind,
398
+ l.tax_id as ltax,
399
+ l.box_amount as lamount
400
+ from entry_lines l
401
+ join entries e on e.id = l.entry_id
402
+ where l.company_id = p_company_id
403
+ and e.state = 'posted'
404
+ and e.entry_date between p_from and p_to
405
+ and l.declaration_box is not null
406
+ ),
407
+ -- The posting that wrote the line: which form it is on, and every box it
408
+ -- prints in. A line with no posting behind it — an entry keyed by hand,
409
+ -- a tax a company wrote itself — is on this form and in the one box it
410
+ -- names, which is what the left join leaves.
411
+ sourced as (
412
+ select ln.lbox, ln.lkind, ln.lamount,
413
+ coalesce(p.boxes, array[ln.lbox]) as lboxes
414
+ from lines ln
415
+ left join lateral (
416
+ select min(tp.report_code) as report_code,
417
+ array_agg(distinct b.box) as boxes
418
+ from tax_postings tp
419
+ cross join lateral unnest(tp.declaration_boxes) as b(box)
420
+ where tp.tax_id = ln.ltax
421
+ and tp.declaration_box = ln.lbox
422
+ and tp.posting_type = ln.lkind::tax_posting_type
423
+ ) p on true
424
+ -- A box number belongs to one form. A line whose posting names
425
+ -- another form is not on this declaration; one that names none is
426
+ -- the single-return case every European company is in.
427
+ where v_report is null or coalesce(p.report_code, v_report) = v_report
428
+ ),
429
+ ledger as (
430
+ select x.box as lbox, s.lkind,
431
+ round_amount(sum(s.lamount), v_round) as lamount
432
+ from sourced s
433
+ cross join lateral unnest(s.lboxes) as x(box)
434
+ group by 1, 2
435
+ having round_amount(sum(s.lamount), v_round) <> 0
436
+ )
437
+ select g.lbox, g.lkind, g.lamount, b.name as lname,
438
+ b.sequence as lsequence,
439
+ coalesce(b.print_sequence, b.sequence) as lprint,
440
+ coalesce(b.hidden, false) as lhidden
441
+ from ledger g
442
+ left join tax_report_box_templates b
443
+ on b.country = v_in and b.report_code = v_report
444
+ and b.box = g.lbox and b.kind = g.lkind
445
+ order by coalesce(b.sequence, 2147483647), g.lbox, g.lkind
446
+ loop
447
+ v_values := v_values || jsonb_build_object(r.lbox || '|' || r.lkind, r.lamount);
448
+ v_rows := v_rows || jsonb_build_array(jsonb_build_object(
449
+ 'box', r.lbox, 'kind', r.lkind, 'amount', r.lamount, 'computed', false,
450
+ 'name', r.lname, 'sequence', r.lsequence, 'print_sequence', r.lprint,
451
+ 'hidden', r.lhidden, 'report_code', v_report));
452
+ end loop;
453
+
454
+ -- 2. The totals of the form, through the evaluator the statements use. A
455
+ -- return prints what it has, so a nil total is left out of the answer —
456
+ -- and kept in the working set, so a later total that names it reads a
457
+ -- zero rather than a gap.
458
+ if v_report is not null then
459
+ select coalesce(jsonb_agg(jsonb_build_object(
460
+ 'key', b.box || '|total', 'plus', to_jsonb(b.plus_boxes),
461
+ 'minus', to_jsonb(b.minus_boxes), 'floor_zero', b.floor_zero,
462
+ 'rate', b.rate, 'rate_of', b.rate_of_box,
463
+ 'sequence', b.sequence
464
+ ) order by b.sequence, b.box), '[]'::jsonb)
465
+ into v_formulas
466
+ from tax_report_box_templates b
467
+ where b.country = v_in
468
+ and b.report_code = v_report
469
+ and b.kind = 'total'
470
+ and (b.valid_from is null or b.valid_from <= p_to)
471
+ and (b.valid_to is null or b.valid_to >= p_to);
472
+
473
+ v_totals := evaluate_totals(v_values, v_formulas, v_round, false);
474
+
475
+ for r in
476
+ select b.box as tbox, b.name as tname, b.sequence as tsequence,
477
+ coalesce(b.print_sequence, b.sequence) as tprint, b.hidden as thidden
478
+ from tax_report_box_templates b
479
+ where b.country = v_in
480
+ and b.report_code = v_report
481
+ and b.kind = 'total'
482
+ and (b.valid_from is null or b.valid_from <= p_to)
483
+ and (b.valid_to is null or b.valid_to >= p_to)
484
+ and v_totals ? (b.box || '|total')
485
+ order by b.sequence, b.box
486
+ loop
487
+ v_rows := v_rows || jsonb_build_array(jsonb_build_object(
488
+ 'box', r.tbox, 'kind', 'total',
489
+ 'amount', (v_totals ->> (r.tbox || '|total'))::numeric, 'computed', true,
490
+ 'name', r.tname, 'sequence', r.tsequence, 'print_sequence', r.tprint,
491
+ 'hidden', r.thidden, 'report_code', v_report));
492
+ end loop;
493
+ end if;
494
+
495
+ return query
496
+ select (x ->> 'box')::text,
497
+ (x ->> 'kind')::text,
498
+ (x ->> 'amount')::numeric,
499
+ (x ->> 'computed')::boolean,
500
+ (x ->> 'name')::text,
501
+ (x ->> 'sequence')::integer,
502
+ (x ->> 'print_sequence')::integer,
503
+ (x ->> 'hidden')::boolean,
504
+ (x ->> 'report_code')::text
505
+ from jsonb_array_elements(v_rows) as x;
506
+ end;
507
+ $$;
508
+
509
+ comment on function vat_return(uuid, date, date, text) is
510
+ 'Declaration boxes for a period: summed from the ledger, then the totals of the country''s form — a plus/minus list or a rate of another box — worked out by evaluate_totals(), the same evaluator financial_statement() uses. Answers print_sequence beside sequence, because the order a form is printed in is not the order it is worked out in. No country rule lives in this function.';
511
+
512
+ -- Rule 6 of supabase/migrations/README.md: a function created here comes out
513
+ -- executable by PUBLIC otherwise.
514
+ revoke execute on all functions in schema public from public;
515
+
516
+ -- And rule 7: the object this file creates names the roles that may reach it.
517
+ revoke execute on function vat_return(uuid, date, date, text) from public, anon;
518
+ grant execute on function vat_return(uuid, date, date, text) to authenticated, service_role;
519
+
520
+ -- `evaluate_totals()` was replaced in place and keeps the grants
521
+ -- `20260914121200` gave it; the blanket revoke above is never aimed at `anon`,
522
+ -- which holds explicit grants on the policy helpers, so naming it here takes
523
+ -- nothing else away.
524
+ revoke execute on function evaluate_totals(jsonb, jsonb, money_rounding, boolean) from public, anon;
525
+ grant execute on function evaluate_totals(jsonb, jsonb, money_rounding, boolean) to authenticated, service_role;