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,801 @@
1
+ /**
2
+ * The compiler: a pack in, one seed file out.
3
+ *
4
+ * The SQL is a build artefact, like `docs/schema.md`. The source is the pack,
5
+ * the output is committed so that `supabase db push` and `psql -f` install a
6
+ * country without this CLI ever running, and `ekwo pack check` refuses an
7
+ * output that is no longer what its pack says. The order of every row is
8
+ * fixed here, so the same pack always compiles to the same bytes.
9
+ *
10
+ * Every insert **upserts on the template tables and on nothing else**. The
11
+ * seeds used to say `on conflict do nothing`, which meant an instance
12
+ * installed last month never received a single pack change — not even for a
13
+ * company created afterwards, since a company copies the templates at
14
+ * install. A template is reference data and a seed is allowed to re-state it;
15
+ * a row that belongs to a company is never touched here, and moving a company
16
+ * from one pack version to the next is `ekwo pack upgrade`, still to come, which
17
+ * shows the diff first.
18
+ *
19
+ * What an upsert cannot do is remove: a template dropped from a pack stays in
20
+ * the database. That is the rule anyway — nothing is ever deleted from a
21
+ * pack, an account is deprecated and a tax gets a `valid_to`.
22
+ */
23
+ import { describeCertification } from './certification.js';
24
+ import { sourcesOf } from './read.js';
25
+ /**
26
+ * Which number each pack's compiled seed carries, by slug.
27
+ *
28
+ * **The number is the pack's own, and a number that has shipped never moves.**
29
+ * The seeds are applied in file-name order and are listed by name in
30
+ * `supabase/config.toml`, so a release that renamed one would rename a file an
31
+ * installation already holds — harmless, because the seeds upsert, and
32
+ * inexplicable to whoever reads the list a year later.
33
+ *
34
+ * It used to be the pack's rank in the alphabetical list of slugs, which is
35
+ * stable exactly until a country is added in the middle of it: inserting `ee`
36
+ * between `be` and `fr` moved France and Luxembourg one place each. So a pack
37
+ * **declares** its number, in `seed_sequence`, and nothing here sorts anything.
38
+ */
39
+ export function seedFileNames(allSlugs, sequences) {
40
+ const names = new Map();
41
+ const taken = new Map();
42
+ for (const slug of allSlugs) {
43
+ const own = sequences.get(slug);
44
+ if (own === undefined) {
45
+ throw new Error(`seed_sequence_missing: packs/${slug} declares no seed_sequence`);
46
+ }
47
+ const other = taken.get(own);
48
+ if (other !== undefined) {
49
+ throw new Error(`seed_sequence_conflict: packs/${other} and packs/${slug} both declare ${own}`);
50
+ }
51
+ taken.set(own, slug);
52
+ names.set(slug, `${own}_pack_${slug}.sql`);
53
+ }
54
+ return names;
55
+ }
56
+ /** `packs/be` → `10_pack_be.sql`, `packs/ee` → `13_pack_ee.sql`. */
57
+ export function seedFileName(slug, allSlugs, sequences) {
58
+ const file = seedFileNames(allSlugs, sequences).get(slug);
59
+ if (file === undefined)
60
+ throw new Error(`unknown_pack: ${slug}`);
61
+ return file;
62
+ }
63
+ export function compilePack(pack) {
64
+ const { manifest } = pack;
65
+ const country = manifest.country;
66
+ const out = [];
67
+ out.push(...header(pack));
68
+ out.push(...manifestRow(pack, country));
69
+ out.push(...charts(pack, country));
70
+ out.push(...accounts(pack, country));
71
+ out.push(...journals(pack, country));
72
+ out.push(...taxes(pack, country));
73
+ out.push(...postings(pack, country));
74
+ out.push(...taxReport(pack, country));
75
+ out.push(...statements(pack.statements, pack.labels.statement_lines, country));
76
+ out.push(...defaults(pack, country));
77
+ out.push(...documentRules(pack, country));
78
+ return `${out.join('\n')}\n`;
79
+ }
80
+ /**
81
+ * The country data of one module, for one pack:
82
+ * `supabase/seed/modules/assets/10_pack_be.sql`.
83
+ *
84
+ * It is a seed of its own, under the module's own folder, and deliberately not
85
+ * part of the pack seed. The pack seed is applied by every installation;
86
+ * `assets.category_templates` does not exist on one that does not carry the
87
+ * module, and a seed that half fails is a seed nobody can re-run. So the
88
+ * module migration runner applies these, and only for the modules it installed.
89
+ *
90
+ * The numbering is the pack's own — `10_pack_be`, `13_pack_ee` — so the file
91
+ * of a country is recognisable wherever it sits.
92
+ */
93
+ export function moduleSeedFileName(slug, allSlugs, sequences) {
94
+ return seedFileName(slug, allSlugs, sequences);
95
+ }
96
+ /**
97
+ * `packs/<cc>/assets.json` → the two reference tables of the `assets` module.
98
+ *
99
+ * Returns `undefined` when the pack says nothing about fixed assets, which is
100
+ * not a gap to fill: `assets.generate_schedule` refuses by name where it needs
101
+ * a prorata convention nobody has declared, rather than taking another
102
+ * country's.
103
+ */
104
+ export function compileAssetsSeed(pack) {
105
+ const assets = pack.assets;
106
+ if (assets === null)
107
+ return undefined;
108
+ const country = pack.manifest.country;
109
+ const out = [
110
+ `-- Ekwo OS — ${pack.manifest.name}: how this country depreciates and derecognises a fixed asset.`,
111
+ '--',
112
+ `-- Generated from packs/${pack.slug}/assets.json at version ${pack.manifest.version}, do not edit.`,
113
+ `-- Change the pack and run \`ekwo pack build ${pack.slug}\`; \`ekwo pack check --all\``,
114
+ '-- refuses a seed that is not the exact output of its pack, and the CI runs it.',
115
+ '--',
116
+ '-- Applied by the module migration runner — `ekwo migrate`, or `ekwo module',
117
+ '-- migrate` — and never by the socle seed step: these tables exist only on an',
118
+ '-- installation that carries the `assets` module.',
119
+ '--',
120
+ '-- The accounts a disposal lands on are not here. They are roles of the chart,',
121
+ '-- in `country_defaults`, written by the pack seed beside every other role.',
122
+ '',
123
+ 'insert into assets.country_rules',
124
+ ' (country, prorata_straight_line, prorata_declining, day_count,',
125
+ ' declining_cap_percent, declining_switch_to_linear, disposal_style, legal_reference)',
126
+ 'values',
127
+ ` (${text(country)}, ${text(assets.prorata_straight_line)}, ${text(assets.prorata_declining)}, ` +
128
+ `${text(assets.day_count)}, ${orNull(assets.declining_cap_percent, number)}, ` +
129
+ `${bool(assets.declining_switch_to_linear)}, ${text(assets.disposal_style)}, ` +
130
+ `${text(assets.legal_reference)})`,
131
+ 'on conflict (country) do update set',
132
+ ' prorata_straight_line = excluded.prorata_straight_line,',
133
+ ' prorata_declining = excluded.prorata_declining,',
134
+ ' day_count = excluded.day_count,',
135
+ ' declining_cap_percent = excluded.declining_cap_percent,',
136
+ ' declining_switch_to_linear = excluded.declining_switch_to_linear,',
137
+ ' disposal_style = excluded.disposal_style,',
138
+ ' legal_reference = excluded.legal_reference;',
139
+ '',
140
+ ];
141
+ if (assets.categories.length === 0)
142
+ return `${out.join('\n')}\n`;
143
+ const values = [...assets.categories]
144
+ .sort((a, b) => a.sequence - b.sequence || (a.code < b.code ? -1 : 1))
145
+ .map((c) => ` (${text(country)}, ${text(c.code)}, ${text(c.name)}, ${json(c.name_i18n)}, ` +
146
+ `${text(c.method)}, ${number(c.duration_months)}, ${orNull(c.coefficient, number)}, ` +
147
+ `${text(c.prorata)}, ${text(c.account_type)}, ${number(c.sequence)}, ` +
148
+ `${text(c.legal_reference)})`);
149
+ out.push('insert into assets.category_templates', ' (country, code, name, name_i18n, method, duration_months, coefficient,', ' prorata, account_type, sequence, legal_reference)', 'select v.country::char(2), v.code, v.name, v.name_i18n::jsonb,', ' v.method::assets.depreciation_method, v.duration_months::integer,', ' v.coefficient::numeric, v.prorata::assets.prorata_rule,', ' v.account_type::account_type, v.sequence::integer, v.legal_reference', ' from (values', values.join(',\n'), ' ) as v (country, code, name, name_i18n, method, duration_months, coefficient,', ' prorata, account_type, sequence, legal_reference)', 'on conflict (country, code) do update set', ' name = excluded.name,', ' name_i18n = excluded.name_i18n,', ' method = excluded.method,', ' duration_months = excluded.duration_months,', ' coefficient = excluded.coefficient,', ' prorata = excluded.prorata,', ' account_type = excluded.account_type,', ' sequence = excluded.sequence,', ' legal_reference = excluded.legal_reference;', '');
150
+ return `${out.join('\n')}\n`;
151
+ }
152
+ /** Every module seed a pack compiles to, by module code. */
153
+ export function compileModuleSeeds(pack) {
154
+ const seeds = new Map();
155
+ const assets = compileAssetsSeed(pack);
156
+ if (assets !== undefined)
157
+ seeds.set('assets', assets);
158
+ return seeds;
159
+ }
160
+ /** `packs/generic` → `05_framework_generic.sql`. It sorts before every pack. */
161
+ export function frameworkSeedFileName(slug) {
162
+ return `05_framework_${slug}.sql`;
163
+ }
164
+ /**
165
+ * The framework pack: statements with no country, and nothing else. They are
166
+ * seeded before the country packs because a chart may name one, and because a
167
+ * company whose country has no pack at all still gets a balance sheet.
168
+ */
169
+ export function compileFrameworkPack(pack) {
170
+ const { manifest } = pack;
171
+ const out = [
172
+ `-- Ekwo OS — ${manifest.name}: financial statements by account type, for any chart of any country.`,
173
+ '--',
174
+ `-- Generated from packs/${pack.slug} at version ${manifest.version}, do not edit.`,
175
+ `-- Change the pack and run \`ekwo pack build ${pack.slug}\`; \`ekwo pack check --all\``,
176
+ '-- refuses a seed that is not the exact output of its pack, and the CI runs it.',
177
+ '--',
178
+ ];
179
+ if (manifest.certification !== undefined) {
180
+ out.push(`-- ${capitalise(describeCertification(manifest.certification))}.`);
181
+ out.push('-- Written from:');
182
+ for (const source of manifest.certification.sources ?? [])
183
+ out.push(...citation(source));
184
+ out.push('--');
185
+ }
186
+ out.push('-- Reference data with no country and no chart: `financial_statement()` reads it', '-- directly, and nothing here is copied into a company.', '');
187
+ out.push(...statements(pack.statements, {}, null));
188
+ return `${out.join('\n')}\n`;
189
+ }
190
+ function header(pack) {
191
+ const { manifest } = pack;
192
+ const lines = [
193
+ `-- Ekwo OS — ${manifest.name}: chart of accounts, journals, taxes and defaults.`,
194
+ '--',
195
+ `-- Generated from packs/${pack.slug} at version ${manifest.version}, do not edit.`,
196
+ `-- Change the pack and run \`ekwo pack build ${pack.slug}\`; \`ekwo pack check --all\``,
197
+ '-- refuses a seed that is not the exact output of its pack, and the CI runs it.',
198
+ '--',
199
+ ];
200
+ const certification = manifest.certification;
201
+ if (certification !== undefined) {
202
+ lines.push(`-- ${capitalise(describeCertification(certification))}.`);
203
+ lines.push('-- Written from:');
204
+ for (const source of certification.sources ?? [])
205
+ lines.push(...citation(source));
206
+ lines.push('--');
207
+ }
208
+ if (pack.deferred.length > 0) {
209
+ lines.push('-- In the pack, not compiled by this release:');
210
+ for (const section of pack.deferred)
211
+ lines.push(`-- ${section}`);
212
+ lines.push('--');
213
+ }
214
+ lines.push('-- Reference data: `install_country_template()` copies it into a company,', '-- nothing here belongs to a company.', '');
215
+ return lines;
216
+ }
217
+ /**
218
+ * The charts this country offers. They come before the accounts: a template
219
+ * account points at its chart, so the chart has to exist first.
220
+ */
221
+ function charts(pack, country) {
222
+ const values = pack.charts.map((c) => ` (${text(country)}, ${text(c.code)}, ${text(c.name)}, ${json(c.name_i18n)}, ` +
223
+ `${c.is_default ? 'true' : 'false'}, ${text(c.audience)}, ${array([...c.statements].sort())}, ` +
224
+ `${text(c.certification?.status ?? null)}, ${text(c.legal_reference)}, ${text(c.source)})`);
225
+ return [
226
+ 'insert into chart_templates',
227
+ ' (country, code, name, name_i18n, is_default, audience, statements,',
228
+ ' certification_status, legal_reference, source_key)',
229
+ 'values',
230
+ values.join(',\n'),
231
+ 'on conflict (country, code) do update set',
232
+ ' name = excluded.name,',
233
+ ' name_i18n = excluded.name_i18n,',
234
+ ' is_default = excluded.is_default,',
235
+ ' audience = excluded.audience,',
236
+ ' statements = excluded.statements,',
237
+ ' certification_status = excluded.certification_status,',
238
+ ' legal_reference = excluded.legal_reference,',
239
+ ' source_key = excluded.source_key;',
240
+ '',
241
+ ];
242
+ }
243
+ function accounts(pack, country) {
244
+ const values = [];
245
+ for (const chart of pack.charts) {
246
+ for (const a of [...chart.accounts].sort(byCode)) {
247
+ values.push(` (${text(country)}, ${text(chart.code)}, ${text(a.code)}, ${text(a.name)}, ` +
248
+ `${json(pack.labels.accounts[a.code])}, ${text(a.type)}, ` +
249
+ `${a.reconcilable ? 'true' : 'false'}, ${text(a.parent)}, ${a.sequence})`);
250
+ }
251
+ }
252
+ return [
253
+ 'insert into account_templates',
254
+ ' (country, chart_code, code, name, name_i18n, account_type, reconcilable,',
255
+ ' parent_code, sequence)',
256
+ 'values',
257
+ values.join(',\n'),
258
+ 'on conflict (country, chart_code, code) do update set',
259
+ ' name = excluded.name,',
260
+ ' name_i18n = excluded.name_i18n,',
261
+ ' account_type = excluded.account_type,',
262
+ ' reconcilable = excluded.reconcilable,',
263
+ ' parent_code = excluded.parent_code,',
264
+ ' sequence = excluded.sequence;',
265
+ '',
266
+ ];
267
+ }
268
+ /**
269
+ * The statements and their lines and rules. The order is the order the scheme
270
+ * declares, because that is the order `financial_statement()` evaluates the
271
+ * totals in.
272
+ */
273
+ function statements(list, labels, country) {
274
+ if (list.length === 0)
275
+ return [];
276
+ const out = [];
277
+ out.push('insert into statement_templates', ' (code, country, chart_code, name, kind, framework, valid_from, valid_to, legal_reference,', ' source_key)', 'values', [...list]
278
+ .sort(byCode)
279
+ .map((s) => ` (${text(s.code)}, ${text(country)}, ${text(s.chart_code)}, ${text(s.name)}, ` +
280
+ `${text(s.kind)}, ${text(s.framework)}, ${date(s.valid_from)}, ${date(s.valid_to)}, ` +
281
+ `${text(s.legal_reference)}, ${text(s.source)})`)
282
+ .join(',\n'), 'on conflict (code) do update set', ' country = excluded.country,', ' chart_code = excluded.chart_code,', ' name = excluded.name,', ' kind = excluded.kind,', ' framework = excluded.framework,', ' valid_from = excluded.valid_from,', ' valid_to = excluded.valid_to,', ' legal_reference = excluded.legal_reference,', ' source_key = excluded.source_key;', '');
283
+ const lines = [];
284
+ const rules = [];
285
+ for (const statement of [...list].sort(byCode)) {
286
+ for (const line of [...statement.lines].sort((a, b) => a.sequence - b.sequence || (a.code < b.code ? -1 : 1))) {
287
+ lines.push(` (${text(statement.code)}, ${text(line.code)}, ${text(line.parent)}, ${text(line.name)}, ` +
288
+ `${json(labels[`${statement.code}:${line.code}`])}, ${line.sequence}, ${line.sign}, ` +
289
+ `${line.is_total ? 'true' : 'false'}, ${array(line.plus)}, ${array(line.minus)}, ` +
290
+ `${text(line.xbrl)}, ${text(line.legal_reference)}, ${text(line.source)})`);
291
+ for (const rule of [...line.rules].sort((a, b) => a.sequence - b.sequence)) {
292
+ rules.push(` (${text(statement.code)}, ${text(line.code)}, ${rule.sequence}, ${text(rule.kind)}, ` +
293
+ `${text(rule.code_from)}, ${text(rule.code_to)}, ${text(rule.account_type)}, ${text(rule.side)})`);
294
+ }
295
+ }
296
+ }
297
+ out.push('insert into statement_line_templates', ' (statement_code, code, parent_code, name, name_i18n, sequence, sign, is_total,', ' plus_lines, minus_lines, xbrl_element, legal_reference, source_key)', 'values', lines.join(',\n'), 'on conflict (statement_code, code) do update set', ' parent_code = excluded.parent_code,', ' name = excluded.name,', ' name_i18n = excluded.name_i18n,', ' sequence = excluded.sequence,', ' sign = excluded.sign,', ' is_total = excluded.is_total,', ' plus_lines = excluded.plus_lines,', ' minus_lines = excluded.minus_lines,', ' xbrl_element = excluded.xbrl_element,', ' legal_reference = excluded.legal_reference,', ' source_key = excluded.source_key;', '');
298
+ if (rules.length > 0) {
299
+ out.push('insert into statement_line_rules', ' (statement_code, line_code, sequence, rule_kind, code_from, code_to,', ' account_type, balance_side)', 'select v.statement_code, v.line_code, v.sequence, v.rule_kind, v.code_from,', ' v.code_to, v.account_type::account_type, v.balance_side', ' from (values', rules.map((row) => ` ${row}`).join(',\n'), ' ) as v (statement_code, line_code, sequence, rule_kind, code_from, code_to,', ' account_type, balance_side)', 'on conflict (statement_code, line_code, sequence) do update set', ' rule_kind = excluded.rule_kind,', ' code_from = excluded.code_from,', ' code_to = excluded.code_to,', ' account_type = excluded.account_type,', ' balance_side = excluded.balance_side;', '');
300
+ }
301
+ return out;
302
+ }
303
+ function journals(pack, country) {
304
+ const rows = [...pack.manifest.journals].sort((a, b) => a.code.localeCompare(b.code));
305
+ const values = rows.map((j, index) => ` (${text(country)}, ${text(j.code)}, ${text(j.name)}, ${json(pack.labels.journals[j.code])}, ` +
306
+ `${text(j.type)}, ${j.sequence ?? (index + 1) * 10})`);
307
+ return [
308
+ 'insert into journal_templates (country, code, name, name_i18n, journal_type, sequence) values',
309
+ values.join(',\n'),
310
+ 'on conflict (country, code) do update set',
311
+ ' name = excluded.name,',
312
+ ' name_i18n = excluded.name_i18n,',
313
+ ' journal_type = excluded.journal_type,',
314
+ ' sequence = excluded.sequence;',
315
+ '',
316
+ ];
317
+ }
318
+ function taxes(pack, country) {
319
+ const rows = [...pack.taxes].sort(byCode);
320
+ const values = rows.map((t) => ` (${text(country)}, ${text(t.code)}, ${text(t.name)}, ${json(pack.labels.taxes[t.code])}, ` +
321
+ `${text(t.description)}, ` +
322
+ `${text(t.amount_type)}, ${number(t.rate)}, ${text(t.scope)}, ${text(t.treatment)}, ` +
323
+ `${date(t.valid_from)}, ${date(t.valid_to)}, ${text(t.legal_reference)}, ` +
324
+ `${text(t.vat_category)}, ${text(t.exemption_code)}, ${t.sequence}, ` +
325
+ `${text(t.kind)}, ${bool(t.recoverable)}, ${conditions(t.conditions)}, ` +
326
+ `${text(t.jurisdiction)}, ` +
327
+ `${bool(t.price_include)}, ${bool(t.cash_basis)}, ${text(t.cash_basis_transition_account)}, ` +
328
+ `${text(t.source)}, ${text(t.applies_seller_territory)}, ${text(t.applies_buyer_territory)}, ` +
329
+ `${text(t.applies_supply_territory)})`);
330
+ return [
331
+ 'insert into tax_templates',
332
+ ' (country, code, name, name_i18n, description, amount_type, amount, applies_to, treatment,',
333
+ ' valid_from, valid_to, legal_reference, vat_category, exemption_code, sequence,',
334
+ ' tax_kind, recoverable, conditions, jurisdiction, price_include, cash_basis,',
335
+ ' cash_basis_transition_account_code, source_key,',
336
+ ' applies_seller_territory, applies_buyer_territory, applies_supply_territory)',
337
+ 'values',
338
+ values.join(',\n'),
339
+ 'on conflict (country, code) do update set',
340
+ ' name = excluded.name,',
341
+ ' name_i18n = excluded.name_i18n,',
342
+ ' description = excluded.description,',
343
+ ' amount_type = excluded.amount_type,',
344
+ ' amount = excluded.amount,',
345
+ ' applies_to = excluded.applies_to,',
346
+ ' treatment = excluded.treatment,',
347
+ ' valid_from = excluded.valid_from,',
348
+ ' valid_to = excluded.valid_to,',
349
+ ' legal_reference = excluded.legal_reference,',
350
+ ' vat_category = excluded.vat_category,',
351
+ ' exemption_code = excluded.exemption_code,',
352
+ ' sequence = excluded.sequence,',
353
+ ' tax_kind = excluded.tax_kind,',
354
+ ' recoverable = excluded.recoverable,',
355
+ ' conditions = excluded.conditions,',
356
+ ' jurisdiction = excluded.jurisdiction,',
357
+ ' price_include = excluded.price_include,',
358
+ ' cash_basis = excluded.cash_basis,',
359
+ ' cash_basis_transition_account_code = excluded.cash_basis_transition_account_code,',
360
+ ' source_key = excluded.source_key,',
361
+ ' applies_seller_territory = excluded.applies_seller_territory,',
362
+ ' applies_buyer_territory = excluded.applies_buyer_territory,',
363
+ ' applies_supply_territory = excluded.applies_supply_territory;',
364
+ '',
365
+ ];
366
+ }
367
+ function postings(pack, country) {
368
+ const values = [];
369
+ for (const tax of [...pack.taxes].sort(byCode)) {
370
+ for (const kind of ['invoice', 'credit_note']) {
371
+ const rows = [...tax.postings[kind]].sort((a, b) => a.sequence - b.sequence || a.type.localeCompare(b.type));
372
+ for (const posting of rows) {
373
+ values.push(` (${text(tax.code)}, ${text(kind)}, ${text(posting.type)}, ` +
374
+ `${number(posting.factor)}, ${text(posting.account)}, ${text(posting.box)}, ` +
375
+ `${posting.boxes.length === 0 ? 'null' : array(posting.boxes)}, ` +
376
+ `${number(posting.box_factor)}, ${text(posting.report)}, ${posting.sequence})`);
377
+ }
378
+ }
379
+ }
380
+ if (values.length === 0)
381
+ return [];
382
+ return [
383
+ 'insert into tax_posting_templates',
384
+ ' (tax_template_id, document_kind, posting_type, factor_percent, account_code,',
385
+ ' declaration_box, declaration_boxes, box_factor_percent, report_code, sequence)',
386
+ 'select t.id,',
387
+ ' v.document_kind::tax_document_kind,',
388
+ ' v.posting_type::tax_posting_type,',
389
+ ' v.factor_percent::numeric,',
390
+ ' v.account_code::text,',
391
+ ' v.declaration_box::text,',
392
+ ' v.declaration_boxes::text[],',
393
+ ' v.box_factor_percent::numeric,',
394
+ ' v.report_code::text,',
395
+ ' v.sequence::integer',
396
+ ' from (values',
397
+ values.join(',\n'),
398
+ ' ) as v (tax_code, document_kind, posting_type, factor_percent, account_code,',
399
+ ' declaration_box, declaration_boxes, box_factor_percent, report_code, sequence)',
400
+ ` join tax_templates t on t.country = ${text(country)} and t.code = v.tax_code`,
401
+ 'on conflict (tax_template_id, document_kind, posting_type, sequence) do update set',
402
+ ' factor_percent = excluded.factor_percent,',
403
+ ' account_code = excluded.account_code,',
404
+ ' declaration_box = excluded.declaration_box,',
405
+ ' declaration_boxes = excluded.declaration_boxes,',
406
+ ' box_factor_percent = excluded.box_factor_percent,',
407
+ ' report_code = excluded.report_code;',
408
+ '',
409
+ ];
410
+ }
411
+ /**
412
+ * The declaration form and its boxes. Not copied into a company: a chart of
413
+ * accounts is customisable and a form is not. The rows are written in the
414
+ * order the pack declares them, which is the order `vat_return()` answers in;
415
+ * `print_sequence` carries the order the administration prints, and the order
416
+ * the totals are worked out in is their dependencies and neither of the two.
417
+ */
418
+ function taxReport(pack, country) {
419
+ const report = pack.report;
420
+ if (report === null)
421
+ return [];
422
+ const out = [
423
+ 'insert into tax_report_templates',
424
+ ' (country, code, name, periods, period_default, valid_from, valid_to, legal_reference,',
425
+ ' is_periodic_return, deadline_rule, deadline_day, deadline_plus_days,',
426
+ ' deadline_reference, deadline_source_key, file_format)',
427
+ 'values',
428
+ ` (${text(country)}, ${text(report.code)}, ${text(report.name)}, ${periods(report.periods)}, ` +
429
+ `${enumeration(report.period_default, 'declaration_period')}, ` +
430
+ `${date(report.valid_from)}, ${date(report.valid_to)}, ${text(report.legal_reference)}, true,` +
431
+ `${enumeration(report.deadline?.rule ?? null, 'filing_deadline_rule')}, ` +
432
+ `${number(report.deadline?.day ?? null)}, ${number(report.deadline?.plus_days ?? null)}, ` +
433
+ `${text(report.deadline?.legal_reference ?? null)}, ${text(report.deadline?.source ?? null)}, ` +
434
+ `${text(report.file_format)})`,
435
+ 'on conflict (country, code) do update set',
436
+ ' name = excluded.name,',
437
+ ' periods = excluded.periods,',
438
+ ' period_default = excluded.period_default,',
439
+ ' valid_from = excluded.valid_from,',
440
+ ' valid_to = excluded.valid_to,',
441
+ ' legal_reference = excluded.legal_reference,',
442
+ ' is_periodic_return = excluded.is_periodic_return,',
443
+ ' deadline_rule = excluded.deadline_rule,',
444
+ ' deadline_day = excluded.deadline_day,',
445
+ ' deadline_plus_days = excluded.deadline_plus_days,',
446
+ ' deadline_reference = excluded.deadline_reference,',
447
+ ' deadline_source_key = excluded.deadline_source_key,',
448
+ ' file_format = excluded.file_format;',
449
+ '',
450
+ ];
451
+ const boxes = [...report.boxes].sort((a, b) => a.sequence - b.sequence || (a.box < b.box ? -1 : 1));
452
+ const values = boxes.map((b) => ` (${text(country)}, ${text(report.code)}, ${text(b.box)}, ${text(b.kind)}, ${text(b.name)}, ` +
453
+ `${json(pack.labels.tax_report_boxes[`${b.box}|${b.kind}`])}, ${b.sequence}, ` +
454
+ `${b.print_sequence === null ? 'null' : number(b.print_sequence)}, ` +
455
+ `${array(b.plus)}, ${array(b.minus)}, ` +
456
+ `${b.rate === null ? 'null' : number(b.rate)}, ${text(b.rate_of)}, ` +
457
+ `${b.floor_zero ? 'true' : 'false'}, ` +
458
+ `${b.hidden ? 'true' : 'false'}, ${text(b.xml_element)}, ${text(b.legal_reference)}, ` +
459
+ `${text(b.source)})`);
460
+ out.push('insert into tax_report_box_templates', ' (country, report_code, box, kind, name, name_i18n, sequence, print_sequence,', ' plus_boxes, minus_boxes, rate, rate_of_box, floor_zero, hidden, xml_element,', ' legal_reference, source_key)', 'values', values.join(',\n'), 'on conflict (country, report_code, box, kind) do update set', ' name = excluded.name,', ' name_i18n = excluded.name_i18n,', ' sequence = excluded.sequence,', ' print_sequence = excluded.print_sequence,', ' plus_boxes = excluded.plus_boxes,', ' minus_boxes = excluded.minus_boxes,', ' rate = excluded.rate,', ' rate_of_box = excluded.rate_of_box,', ' floor_zero = excluded.floor_zero,', ' hidden = excluded.hidden,', ' xml_element = excluded.xml_element,', ' legal_reference = excluded.legal_reference,', ' source_key = excluded.source_key;', '');
461
+ return out;
462
+ }
463
+ function defaults(pack, country) {
464
+ const { roles, journal_roles: journalRoles = {} } = pack.manifest.defaults;
465
+ const row = [
466
+ text(country),
467
+ text(pack.manifest.name),
468
+ json(pack.labels.pack_name),
469
+ // The pack's own language first: it is the one every label is written in,
470
+ // and an installer that offered the translations before it would put the
471
+ // country's own wording last on its own chart of accounts.
472
+ array([
473
+ ...(pack.manifest.defaults.language === undefined ? [] : [pack.manifest.defaults.language]),
474
+ ...(pack.manifest.languages ?? []),
475
+ ]),
476
+ text(pack.manifest.defaults.currency),
477
+ text(roles['receivable'] ?? null),
478
+ text(roles['payable'] ?? null),
479
+ text(roles['suspense'] ?? null),
480
+ text(roles['rounding'] ?? null),
481
+ text(roles['retained_earnings'] ?? null),
482
+ text(roles['sales'] ?? null),
483
+ text(roles['purchase'] ?? null),
484
+ text(roles['bank'] ?? null),
485
+ text(roles['cash'] ?? null),
486
+ text(journalRoles['sales'] ?? 'SAL'),
487
+ text(journalRoles['purchase'] ?? 'PUR'),
488
+ text(journalRoles['miscellaneous'] ?? 'MISC'),
489
+ text(pack.manifest.defaults.language ?? null),
490
+ // No fallback: a pack that says nothing about closing writes null, and
491
+ // close_fiscal_year refuses by name. A default here would be one
492
+ // country's mechanism given to every country that has not spoken.
493
+ text(pack.manifest.defaults['closing_style'] ?? null),
494
+ text(roles['current_year_result_profit'] ?? null),
495
+ text(roles['current_year_result_loss'] ?? null),
496
+ text(roles['retained_earnings_loss'] ?? null),
497
+ text(journalRoles['opening'] ?? null),
498
+ // The same rule for rounding, which has a column default where closing has
499
+ // none: the pack's value, or `default` so the column decides. Writing one
500
+ // here would make the CLI a second place where a country model lives.
501
+ defaulted(pack.manifest.defaults['rounding_method'], text),
502
+ defaulted(pack.manifest.defaults['cash_rounding_unit'], number),
503
+ // Where a realised exchange difference lands. No fallback, for the reason
504
+ // above: an account number is a fact about a chart.
505
+ text(roles['fx_gain'] ?? null),
506
+ text(roles['fx_loss'] ?? null),
507
+ // Where the disposal of a fixed asset lands. Four, because two countries
508
+ // present a disposal differently and neither is a variant of the other:
509
+ // one gain-or-loss line, or the value sold and the proceeds in full. Which
510
+ // of the two a country follows is in `assets.json`, with the rest of that
511
+ // module's country model; these are the accounts, and an account that
512
+ // plays a part is a role, so it is named where every other role is.
513
+ text(roles['asset_disposal_gain'] ?? null),
514
+ text(roles['asset_disposal_loss'] ?? null),
515
+ text(roles['asset_disposal_proceeds'] ?? null),
516
+ text(roles['asset_disposal_value'] ?? null),
517
+ // Where a declared period lands once its tax accounts are cleared: what is
518
+ // owed to the administration, and — where the chart keeps the two apart —
519
+ // what it owes back. No fallback for the same reason as every other
520
+ // account code, and the second one falls back to the first inside the
521
+ // database, for a chart that keeps one control account for both signs.
522
+ text(roles['tax_payable'] ?? null),
523
+ text(roles['tax_receivable'] ?? null),
524
+ // The wording the computed opening lines of an export carry, in the
525
+ // language the administration of this country reads. No fallback here
526
+ // either, but for the opposite reason to an account code: the schema keeps
527
+ // a neutral one, because a format that fixes no wording has no wrong
528
+ // answer to give, and a missing label is not a reason to refuse a file.
529
+ text(pack.manifest.defaults['opening_entry_label'] ?? null),
530
+ // How often a company of this country files its periodic return, when the
531
+ // law gives one answer for everybody. Deprecated by
532
+ // `tax_report_templates.period_default` and written from it, so the two can
533
+ // never disagree: the proposal is stated once, on the form, and this column
534
+ // carries a copy for the readers that already have it. Null where the law
535
+ // makes the cadence depend on a fact about the company — `ekwo init` asks
536
+ // rather than this file choosing.
537
+ enumeration(pack.report?.period_default ?? null, 'declaration_period'),
538
+ ];
539
+ return [
540
+ 'insert into country_defaults',
541
+ ' (country, name, name_i18n, languages, currency_code, receivable_code, payable_code, suspense_code,',
542
+ ' rounding_code, retained_earnings_code, sales_account_code, purchase_account_code,',
543
+ ' bank_account_code, cash_account_code, sales_journal_code, purchase_journal_code,',
544
+ ' misc_journal_code, language_default, closing_style, current_year_result_profit_code,',
545
+ ' current_year_result_loss_code, retained_earnings_loss_code, opening_journal_code,',
546
+ ' rounding_method, cash_rounding_unit, fx_gain_code, fx_loss_code,',
547
+ ' asset_disposal_gain_code, asset_disposal_loss_code,',
548
+ ' asset_disposal_proceeds_code, asset_disposal_value_code,',
549
+ ' tax_payable_code, tax_receivable_code, opening_entry_label,',
550
+ ' vat_period_default)',
551
+ 'values',
552
+ ` (${row.join(', ')})`,
553
+ 'on conflict (country) do update set',
554
+ ' name = excluded.name,',
555
+ ' name_i18n = excluded.name_i18n,',
556
+ ' languages = excluded.languages,',
557
+ ' currency_code = excluded.currency_code,',
558
+ ' receivable_code = excluded.receivable_code,',
559
+ ' payable_code = excluded.payable_code,',
560
+ ' suspense_code = excluded.suspense_code,',
561
+ ' rounding_code = excluded.rounding_code,',
562
+ ' retained_earnings_code = excluded.retained_earnings_code,',
563
+ ' sales_account_code = excluded.sales_account_code,',
564
+ ' purchase_account_code = excluded.purchase_account_code,',
565
+ ' bank_account_code = excluded.bank_account_code,',
566
+ ' cash_account_code = excluded.cash_account_code,',
567
+ ' sales_journal_code = excluded.sales_journal_code,',
568
+ ' purchase_journal_code = excluded.purchase_journal_code,',
569
+ ' misc_journal_code = excluded.misc_journal_code,',
570
+ ' language_default = excluded.language_default,',
571
+ ' closing_style = excluded.closing_style,',
572
+ ' current_year_result_profit_code = excluded.current_year_result_profit_code,',
573
+ ' current_year_result_loss_code = excluded.current_year_result_loss_code,',
574
+ ' retained_earnings_loss_code = excluded.retained_earnings_loss_code,',
575
+ ' opening_journal_code = excluded.opening_journal_code,',
576
+ ' rounding_method = excluded.rounding_method,',
577
+ ' cash_rounding_unit = excluded.cash_rounding_unit,',
578
+ ' fx_gain_code = excluded.fx_gain_code,',
579
+ ' fx_loss_code = excluded.fx_loss_code,',
580
+ ' asset_disposal_gain_code = excluded.asset_disposal_gain_code,',
581
+ ' asset_disposal_loss_code = excluded.asset_disposal_loss_code,',
582
+ ' asset_disposal_proceeds_code = excluded.asset_disposal_proceeds_code,',
583
+ ' asset_disposal_value_code = excluded.asset_disposal_value_code,',
584
+ ' tax_payable_code = excluded.tax_payable_code,',
585
+ ' tax_receivable_code = excluded.tax_receivable_code,',
586
+ ' opening_entry_label = excluded.opening_entry_label,',
587
+ ' vat_period_default = excluded.vat_period_default;',
588
+ ];
589
+ }
590
+ /**
591
+ * What a country requires on a document, how the document is exchanged, and
592
+ * the formats its banks speak: twenty columns of `country_defaults` and the
593
+ * sentences of `legal_mention_templates`.
594
+ *
595
+ * Eight of the twenty are citations — the article behind the numbering, the
596
+ * payment term, the tax point and the e-invoicing profile, and the register
597
+ * key each of them is read at. They ride in the same update as the rule they
598
+ * belong to, because a rule and the text that imposes it going into the
599
+ * database by two different routes is how one of them gets left behind.
600
+ *
601
+ * An `update` rather than a second `insert`. The row exists — `defaults()`
602
+ * writes it immediately above — and an insert would have to restate the name,
603
+ * the currency and the two account roles that its not-null columns need, which
604
+ * is the same values twice in one generated file. The update touches only the
605
+ * columns this section owns, so it stays independent of the row above, and a
606
+ * pack that declares nothing writes null where null already was.
607
+ *
608
+ * None of these columns has a default, so `null` is written literally rather
609
+ * than the `default` keyword the rounding columns use: there is nothing for
610
+ * the schema to decide.
611
+ */
612
+ function documentRules(pack, country) {
613
+ const rules = pack.documents;
614
+ const out = [
615
+ '',
616
+ 'update country_defaults set',
617
+ ` numbering_gapless = ${orNull(rules.numbering_gapless, bool)},`,
618
+ ` number_format = ${text(rules.number_format)},`,
619
+ ` legal_payment_days = ${orNull(rules.legal_payment_days, number)},`,
620
+ ` late_payment_reference = ${text(rules.late_payment_reference)},`,
621
+ ` numbering_legal_reference = ${text(rules.numbering_reference.legal_reference)},`,
622
+ ` numbering_source_key = ${text(rules.numbering_reference.source)},`,
623
+ ` payment_terms_legal_reference = ${text(rules.payment_terms_reference.legal_reference)},`,
624
+ ` payment_terms_source_key = ${text(rules.payment_terms_reference.source)},`,
625
+ ` tax_point_rule = ${text(rules.tax_point_rule)},`,
626
+ ` tax_point_legal_reference = ${text(rules.tax_point_reference.legal_reference)},`,
627
+ ` tax_point_source_key = ${text(rules.tax_point_reference.source)},`,
628
+ ` einvoice_profile = ${text(rules.einvoice_profile)},`,
629
+ ` einvoice_mandatory_from = ${date(rules.einvoice_mandatory_from)},`,
630
+ ` einvoice_legal_reference = ${text(rules.einvoice_reference.legal_reference)},`,
631
+ ` einvoice_source_key = ${text(rules.einvoice_reference.source)},`,
632
+ ` party_scheme = ${text(rules.party_scheme)},`,
633
+ ` vat_scheme = ${text(rules.vat_scheme)},`,
634
+ ` bank_statement_formats = ${listOrNull(rules.bank_statement_formats)},`,
635
+ ` payment_formats = ${listOrNull(rules.payment_formats)},`,
636
+ ` fiscal_year_default = ${text(rules.fiscal_year_default)}`,
637
+ ` where country = ${text(country)};`,
638
+ ];
639
+ if (rules.mentions.length === 0)
640
+ return out;
641
+ const mentions = [...rules.mentions].sort((a, b) => a.sequence - b.sequence || (a.code < b.code ? -1 : 1));
642
+ const values = mentions.map((m) => ` (${text(country)}, ${text(m.code)}, ${text(m.applies_when)}, ${text(m.text)}, ` +
643
+ `${json(m.text_i18n)}, ${m.sequence}, ${date(m.valid_from)}, ${date(m.valid_to)}, ` +
644
+ `${text(m.legal_reference)})`);
645
+ out.push('', 'insert into legal_mention_templates', ' (country, code, applies_when, text, text_i18n, sequence, valid_from, valid_to, legal_reference)', 'values', values.join(',\n'), 'on conflict (country, code) do update set', ' applies_when = excluded.applies_when,', ' text = excluded.text,', ' text_i18n = excluded.text_i18n,', ' sequence = excluded.sequence,', ' valid_from = excluded.valid_from,', ' valid_to = excluded.valid_to,', ' legal_reference = excluded.legal_reference;');
646
+ return out;
647
+ }
648
+ /**
649
+ * `country_packs`: which pack this installation holds, and how much anyone
650
+ * has read it. `ekwo init` prints the certification status, `ekwo status`
651
+ * compares this version to what each company copied.
652
+ */
653
+ function manifestRow(pack, country) {
654
+ const { manifest } = pack;
655
+ const certification = manifest.certification;
656
+ const row = [
657
+ text(country),
658
+ text(manifest.name),
659
+ text(manifest.version),
660
+ date(manifest.released_at ?? null),
661
+ text(manifest.schema_min),
662
+ text(certification?.status ?? 'community'),
663
+ text(certification?.by ?? null),
664
+ date(certification?.on ?? null),
665
+ text(pack.checksum),
666
+ // The register, as the pack declares it and in that order. A bare title of
667
+ // the deprecated form carries no link and reaches no column: what an
668
+ // application shows under "where do these rules come from" is a list of
669
+ // things a reader can open, or it is nothing.
670
+ register(sourcesOf(certification)),
671
+ ];
672
+ return [
673
+ 'insert into country_packs',
674
+ ' (country, name, version, released_at, schema_min, certification_status,',
675
+ ' certified_by, certified_at, checksum, sources)',
676
+ 'values',
677
+ ` (${row.join(', ')})`,
678
+ 'on conflict (country) do update set',
679
+ ' name = excluded.name,',
680
+ ' version = excluded.version,',
681
+ ' released_at = excluded.released_at,',
682
+ ' schema_min = excluded.schema_min,',
683
+ ' certification_status = excluded.certification_status,',
684
+ ' certified_by = excluded.certified_by,',
685
+ ' certified_at = excluded.certified_at,',
686
+ ' checksum = excluded.checksum,',
687
+ ' sources = excluded.sources;',
688
+ '',
689
+ ];
690
+ }
691
+ /**
692
+ * One text of the register, in the header of the seed it produced.
693
+ *
694
+ * Two lines rather than one, because the link is the half a reader of the
695
+ * generated SQL cannot reconstruct: an operator who opens a seed to find out
696
+ * what their installation believes about their country should be able to go
697
+ * and read the law it came from without leaving the file.
698
+ */
699
+ function citation(source) {
700
+ if (typeof source === 'string')
701
+ return [`-- ${source}`];
702
+ return [`-- ${source.title} (${source.publisher})`, `-- ${source.url}`];
703
+ }
704
+ function capitalise(text) {
705
+ return text.charAt(0).toUpperCase() + text.slice(1);
706
+ }
707
+ function byCode(a, b) {
708
+ return a.code < b.code ? -1 : a.code > b.code ? 1 : 0;
709
+ }
710
+ function text(value) {
711
+ if (value === null || value === undefined)
712
+ return 'null';
713
+ return `'${value.replace(/'/g, "''")}'`;
714
+ }
715
+ function date(value) {
716
+ return value === null || value === undefined ? 'null' : `date '${value}'`;
717
+ }
718
+ function number(value) {
719
+ return value === null || value === undefined ? 'null' : String(value);
720
+ }
721
+ /** A `text[]` literal, empty included, in the order the pack wrote it. */
722
+ /**
723
+ * The cadences a form is filed on. Its own helper rather than `array()`,
724
+ * because the column is an enum array and a text array will not cast itself
725
+ * into one silently.
726
+ */
727
+ function periods(values) {
728
+ return `array[${values.map((value) => text(value)).join(', ')}]::declaration_period[]`;
729
+ }
730
+ function array(values) {
731
+ if (values.length === 0)
732
+ return `'{}'::text[]`;
733
+ return `array[${values.map((value) => text(value)).join(', ')}]::text[]`;
734
+ }
735
+ /** What a tax turns on, as the closed vocabulary the column is typed on. */
736
+ function conditions(values) {
737
+ if (values.length === 0)
738
+ return `'{}'::tax_condition[]`;
739
+ return `array[${values.map((value) => text(value)).join(', ')}]::tax_condition[]`;
740
+ }
741
+ /** A value of a PostgreSQL enum, or a null the column keeps as one. */
742
+ function enumeration(value, type) {
743
+ return value === null ? 'null' : `${text(value)}::${type}`;
744
+ }
745
+ function bool(value) {
746
+ return value ? 'true' : 'false';
747
+ }
748
+ /**
749
+ * The pack's value, or a literal `null`. For a column with no default, which
750
+ * is every column this release adds: nothing for the schema to fall back on,
751
+ * so "the pack said nothing" is written as the absence it is.
752
+ */
753
+ function orNull(value, render) {
754
+ return value === null || value === undefined ? 'null' : render(value);
755
+ }
756
+ /**
757
+ * A `text[]` of formats, or null. An empty list and a missing section say the
758
+ * same thing here — this country has told us nothing about its banks — and
759
+ * one of them has to reach the column, so it is null rather than `{}`, which
760
+ * would read as "explicitly no format at all".
761
+ */
762
+ function listOrNull(values) {
763
+ return values.length === 0 ? 'null' : array(values);
764
+ }
765
+ /**
766
+ * The value the pack declared, or the SQL keyword that lets the column decide.
767
+ * `default` in a `values` row is also what `excluded` carries into the upsert,
768
+ * so a pack that stops declaring something goes back to the schema's answer
769
+ * rather than keeping the last one it was given.
770
+ */
771
+ function defaulted(value, render) {
772
+ return value === null || value === undefined ? 'default' : render(value);
773
+ }
774
+ /** A jsonb literal, with its keys in a fixed order so the output is stable. */
775
+ /**
776
+ * The source register, as one jsonb array.
777
+ *
778
+ * In the order the pack declares, not sorted: a register is a reading list,
779
+ * and the text a country's chart of accounts comes from belongs at the top of
780
+ * it. The fields are written out by name rather than stringified whole, so a
781
+ * field added to the format later is a field somebody decided to compile.
782
+ */
783
+ function register(sources) {
784
+ const rows = sources.map((source) => ({
785
+ key: source.key,
786
+ title: source.title,
787
+ publisher: source.publisher,
788
+ url: source.url,
789
+ consulted_on: source.consulted_on,
790
+ kind: source.kind,
791
+ }));
792
+ return `${text(JSON.stringify(rows))}::jsonb`;
793
+ }
794
+ function json(value) {
795
+ const entries = Object.entries(value ?? {}).sort(([a], [b]) => (a < b ? -1 : 1));
796
+ const object = {};
797
+ for (const [key, item] of entries)
798
+ object[key] = item;
799
+ return `${text(JSON.stringify(object))}::jsonb`;
800
+ }
801
+ //# sourceMappingURL=compile.js.map