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,178 @@
1
+ -- Ekwo OS — bank accounts, statements and transactions.
2
+
3
+ create type bank_transaction_state as enum ('pending', 'reconciled', 'ignored');
4
+ create type bank_statement_state as enum ('draft', 'confirmed');
5
+
6
+ create table bank_accounts (
7
+ id uuid primary key default gen_random_uuid(),
8
+ company_id uuid not null references companies(id) on delete cascade,
9
+ name text not null,
10
+ iban text,
11
+ bic text,
12
+ bank_name text,
13
+ currency_code char(3) not null default 'EUR' references currencies(code),
14
+ account_id uuid references accounts(id) on delete set null,
15
+ journal_id uuid references journals(id) on delete set null,
16
+ active boolean not null default true,
17
+ created_at timestamptz not null default now(),
18
+ updated_at timestamptz not null default now(),
19
+ foreign key (account_id, company_id) references accounts(id, company_id),
20
+ foreign key (journal_id, company_id) references journals(id, company_id)
21
+ );
22
+
23
+ comment on table bank_accounts is 'Bank and card accounts, each mapped to a ledger account and a journal.';
24
+
25
+ create unique index bank_accounts_id_company_idx on bank_accounts (id, company_id);
26
+ create unique index bank_accounts_company_iban_idx
27
+ on bank_accounts (company_id, iban) where iban is not null;
28
+
29
+ create trigger bank_accounts_set_updated_at
30
+ before update on bank_accounts
31
+ for each row execute function set_updated_at();
32
+
33
+ alter table journals
34
+ add constraint journals_bank_account_fkey
35
+ foreign key (bank_account_id) references bank_accounts(id) on delete set null;
36
+ alter table payments
37
+ add constraint payments_bank_account_fkey
38
+ foreign key (bank_account_id) references bank_accounts(id) on delete set null;
39
+
40
+ -- ---------------------------------------------------------------------------
41
+ -- bank_statements
42
+ --
43
+ -- A statement exists so the balances can be checked for continuity: the
44
+ -- closing balance of one is the opening balance of the next.
45
+ -- ---------------------------------------------------------------------------
46
+
47
+ create table bank_statements (
48
+ id uuid primary key default gen_random_uuid(),
49
+ company_id uuid not null references companies(id) on delete cascade,
50
+ bank_account_id uuid not null references bank_accounts(id) on delete cascade,
51
+ name text,
52
+ statement_date date not null,
53
+ balance_start numeric(16, 2) not null default 0,
54
+ balance_end_declared numeric(16, 2) not null default 0,
55
+ balance_end_computed numeric(16, 2) not null default 0,
56
+ is_consistent boolean generated always as (
57
+ balance_end_declared = balance_end_computed
58
+ ) stored,
59
+ state bank_statement_state not null default 'draft',
60
+ source text,
61
+ created_at timestamptz not null default now(),
62
+ updated_at timestamptz not null default now(),
63
+ foreign key (bank_account_id, company_id) references bank_accounts(id, company_id)
64
+ );
65
+
66
+ comment on table bank_statements is 'Imported statements. `is_consistent` compares the declared closing balance with the sum of the lines.';
67
+
68
+ create unique index bank_statements_id_company_idx on bank_statements (id, company_id);
69
+ create index bank_statements_account_date_idx on bank_statements (bank_account_id, statement_date);
70
+
71
+ create trigger bank_statements_set_updated_at
72
+ before update on bank_statements
73
+ for each row execute function set_updated_at();
74
+
75
+ -- ---------------------------------------------------------------------------
76
+ -- bank_transactions
77
+ -- ---------------------------------------------------------------------------
78
+
79
+ create table bank_transactions (
80
+ id uuid primary key default gen_random_uuid(),
81
+ company_id uuid not null references companies(id) on delete cascade,
82
+ statement_id uuid references bank_statements(id) on delete set null,
83
+ bank_account_id uuid not null references bank_accounts(id) on delete cascade,
84
+ sequence integer not null default 10,
85
+ transaction_date date not null,
86
+ value_date date,
87
+ -- Signed: positive is money in.
88
+ amount numeric(16, 2) not null,
89
+ currency_code char(3) not null default 'EUR' references currencies(code),
90
+ description text,
91
+ counterpart_name text,
92
+ counterpart_iban text,
93
+ reference text,
94
+ -- Structured communication (BE +++000/0000/00000+++, ISO 11649 RF...).
95
+ structured_reference text,
96
+ contact_id uuid references contacts(id) on delete set null,
97
+ entry_id uuid references entries(id) on delete set null,
98
+ state bank_transaction_state not null default 'pending',
99
+ raw jsonb,
100
+ created_at timestamptz not null default now(),
101
+ updated_at timestamptz not null default now(),
102
+ foreign key (statement_id, company_id) references bank_statements(id, company_id),
103
+ foreign key (bank_account_id, company_id) references bank_accounts(id, company_id),
104
+ foreign key (contact_id, company_id) references contacts(id, company_id),
105
+ foreign key (entry_id, company_id) references entries(id, company_id)
106
+ );
107
+
108
+ comment on table bank_transactions is 'Statement lines. `amount` is signed; `raw` keeps whatever the source sent.';
109
+
110
+ create index bank_transactions_statement_idx on bank_transactions (statement_id, sequence);
111
+ create index bank_transactions_account_date_idx on bank_transactions (bank_account_id, transaction_date);
112
+ create index bank_transactions_state_idx on bank_transactions (company_id, state);
113
+
114
+ create trigger bank_transactions_set_updated_at
115
+ before update on bank_transactions
116
+ for each row execute function set_updated_at();
117
+
118
+ create or replace function bank_statements_refresh_balance()
119
+ returns trigger
120
+ language plpgsql
121
+ as $$
122
+ declare
123
+ v_statement uuid := coalesce(new.statement_id, old.statement_id);
124
+ begin
125
+ if v_statement is null then
126
+ return null;
127
+ end if;
128
+ update bank_statements s
129
+ set balance_end_computed = s.balance_start + coalesce((
130
+ select sum(t.amount) from bank_transactions t where t.statement_id = s.id
131
+ ), 0)
132
+ where s.id = v_statement;
133
+ return null;
134
+ end;
135
+ $$;
136
+
137
+ create trigger bank_transactions_refresh_balance
138
+ after insert or update of amount, statement_id or delete on bank_transactions
139
+ for each row execute function bank_statements_refresh_balance();
140
+
141
+ create or replace function bank_statements_recompute()
142
+ returns trigger
143
+ language plpgsql
144
+ as $$
145
+ begin
146
+ new.balance_end_computed := new.balance_start + coalesce((
147
+ select sum(t.amount) from bank_transactions t where t.statement_id = new.id
148
+ ), 0);
149
+ return new;
150
+ end;
151
+ $$;
152
+
153
+ create trigger bank_statements_recompute
154
+ before insert or update of balance_start on bank_statements
155
+ for each row execute function bank_statements_recompute();
156
+
157
+ -- ---------------------------------------------------------------------------
158
+ -- Row level security
159
+ -- ---------------------------------------------------------------------------
160
+
161
+ alter table bank_accounts enable row level security;
162
+ alter table bank_statements enable row level security;
163
+ alter table bank_transactions enable row level security;
164
+
165
+ create policy bank_accounts_select on bank_accounts
166
+ for select using (is_company_member(company_id));
167
+ create policy bank_accounts_write on bank_accounts
168
+ for all using (can_write_company(company_id)) with check (can_write_company(company_id));
169
+
170
+ create policy bank_statements_select on bank_statements
171
+ for select using (is_company_member(company_id));
172
+ create policy bank_statements_write on bank_statements
173
+ for all using (can_write_company(company_id)) with check (can_write_company(company_id));
174
+
175
+ create policy bank_transactions_select on bank_transactions
176
+ for select using (is_company_member(company_id));
177
+ create policy bank_transactions_write on bank_transactions
178
+ for all using (can_write_company(company_id)) with check (can_write_company(company_id));
@@ -0,0 +1,128 @@
1
+ -- Ekwo OS — analytic dimensions and polymorphic attachments.
2
+
3
+ -- ---------------------------------------------------------------------------
4
+ -- Analytic axes
5
+ --
6
+ -- Axes and values in tables, joined to entry lines by a table, not a JSON
7
+ -- column and certainly not by columns created at runtime: under Supabase we
8
+ -- want joins and row level security.
9
+ -- ---------------------------------------------------------------------------
10
+
11
+ create table analytic_axes (
12
+ id uuid primary key default gen_random_uuid(),
13
+ company_id uuid not null references companies(id) on delete cascade,
14
+ code text not null,
15
+ name text not null,
16
+ active boolean not null default true,
17
+ created_at timestamptz not null default now(),
18
+ updated_at timestamptz not null default now(),
19
+ unique (company_id, code)
20
+ );
21
+
22
+ comment on table analytic_axes is 'Analytic dimensions: cost centre, project, activity.';
23
+
24
+ create unique index analytic_axes_id_company_idx on analytic_axes (id, company_id);
25
+
26
+ create trigger analytic_axes_set_updated_at
27
+ before update on analytic_axes
28
+ for each row execute function set_updated_at();
29
+
30
+ create table analytic_values (
31
+ id uuid primary key default gen_random_uuid(),
32
+ company_id uuid not null references companies(id) on delete cascade,
33
+ axis_id uuid not null references analytic_axes(id) on delete cascade,
34
+ code text not null,
35
+ name text not null,
36
+ parent_id uuid references analytic_values(id) on delete set null,
37
+ active boolean not null default true,
38
+ created_at timestamptz not null default now(),
39
+ updated_at timestamptz not null default now(),
40
+ unique (axis_id, code),
41
+ foreign key (axis_id, company_id) references analytic_axes(id, company_id)
42
+ );
43
+
44
+ comment on table analytic_values is 'Values of an axis, optionally hierarchical.';
45
+
46
+ create unique index analytic_values_id_company_idx on analytic_values (id, company_id);
47
+ create index analytic_values_parent_idx on analytic_values (parent_id);
48
+
49
+ create trigger analytic_values_set_updated_at
50
+ before update on analytic_values
51
+ for each row execute function set_updated_at();
52
+
53
+ create table entry_line_analytics (
54
+ id uuid primary key default gen_random_uuid(),
55
+ company_id uuid not null references companies(id) on delete cascade,
56
+ entry_line_id uuid not null references entry_lines(id) on delete cascade,
57
+ analytic_value_id uuid not null references analytic_values(id) on delete restrict,
58
+ percentage numeric(7, 3) not null default 100,
59
+ amount numeric(16, 2),
60
+ created_at timestamptz not null default now(),
61
+ unique (entry_line_id, analytic_value_id),
62
+ constraint entry_line_analytics_percentage check (percentage > 0 and percentage <= 100),
63
+ foreign key (entry_line_id, company_id) references entry_lines(id, company_id) on delete cascade,
64
+ foreign key (analytic_value_id, company_id) references analytic_values(id, company_id)
65
+ );
66
+
67
+ comment on table entry_line_analytics is 'Analytic split of a ledger line. One row per value, share in percent.';
68
+
69
+ create index entry_line_analytics_value_idx on entry_line_analytics (analytic_value_id);
70
+
71
+ -- ---------------------------------------------------------------------------
72
+ -- attachments
73
+ -- ---------------------------------------------------------------------------
74
+
75
+ create table attachments (
76
+ id uuid primary key default gen_random_uuid(),
77
+ company_id uuid not null references companies(id) on delete cascade,
78
+ -- Polymorphic: which table the file belongs to, and which row.
79
+ entity_type text not null,
80
+ entity_id uuid not null,
81
+ file_name text not null,
82
+ mime_type text,
83
+ byte_size bigint,
84
+ -- Path in Supabase Storage, or any URI the application understands.
85
+ storage_path text not null,
86
+ checksum text,
87
+ uploaded_by uuid,
88
+ created_at timestamptz not null default now(),
89
+ constraint attachments_entity_type check (
90
+ entity_type in ('company', 'contact', 'document', 'entry', 'payment',
91
+ 'bank_statement', 'bank_transaction', 'fiscal_year')
92
+ ),
93
+ constraint attachments_size check (byte_size is null or byte_size >= 0)
94
+ );
95
+
96
+ comment on table attachments is 'Files attached to any record. `entity_type` is constrained rather than free text.';
97
+
98
+ create index attachments_entity_idx on attachments (entity_type, entity_id);
99
+ create index attachments_company_idx on attachments (company_id, created_at desc);
100
+
101
+ -- ---------------------------------------------------------------------------
102
+ -- Row level security
103
+ -- ---------------------------------------------------------------------------
104
+
105
+ alter table analytic_axes enable row level security;
106
+ alter table analytic_values enable row level security;
107
+ alter table entry_line_analytics enable row level security;
108
+ alter table attachments enable row level security;
109
+
110
+ create policy analytic_axes_select on analytic_axes
111
+ for select using (is_company_member(company_id));
112
+ create policy analytic_axes_write on analytic_axes
113
+ for all using (can_write_company(company_id)) with check (can_write_company(company_id));
114
+
115
+ create policy analytic_values_select on analytic_values
116
+ for select using (is_company_member(company_id));
117
+ create policy analytic_values_write on analytic_values
118
+ for all using (can_write_company(company_id)) with check (can_write_company(company_id));
119
+
120
+ create policy entry_line_analytics_select on entry_line_analytics
121
+ for select using (is_company_member(company_id));
122
+ create policy entry_line_analytics_write on entry_line_analytics
123
+ for all using (can_write_company(company_id)) with check (can_write_company(company_id));
124
+
125
+ create policy attachments_select on attachments
126
+ for select using (is_company_member(company_id));
127
+ create policy attachments_write on attachments
128
+ for all using (can_write_company(company_id)) with check (can_write_company(company_id));
@@ -0,0 +1,279 @@
1
+ -- Ekwo OS — turning a document into a journal entry.
2
+ --
3
+ -- Rules this function keeps, each of them a bug seen in the wild:
4
+ -- * amounts are always positive; a credit note flips the side, it does not
5
+ -- negate;
6
+ -- * the counterpart line is the difference of the lines already written, so
7
+ -- the entry is balanced by construction and the document header is what
8
+ -- gets challenged, never the ledger;
9
+ -- * accounts are resolved by role (contact, then company default), never by
10
+ -- matching a code prefix;
11
+ -- * a tax that nets to zero is still booked on both sides and still feeds
12
+ -- its declaration boxes, so the ledger and the VAT return agree;
13
+ -- * anything that goes wrong raises. A swallowed error is a missing entry.
14
+
15
+ create or replace function resolve_counterpart_account(
16
+ p_company_id uuid,
17
+ p_contact_id uuid,
18
+ p_is_sale boolean
19
+ )
20
+ returns uuid
21
+ language plpgsql
22
+ stable
23
+ as $$
24
+ declare
25
+ v_account uuid;
26
+ begin
27
+ if p_is_sale then
28
+ select c.receivable_account_id into v_account from contacts c where c.id = p_contact_id;
29
+ if v_account is null then
30
+ select co.receivable_account_id into v_account from companies co where co.id = p_company_id;
31
+ end if;
32
+ else
33
+ select c.payable_account_id into v_account from contacts c where c.id = p_contact_id;
34
+ if v_account is null then
35
+ select co.payable_account_id into v_account from companies co where co.id = p_company_id;
36
+ end if;
37
+ end if;
38
+
39
+ if v_account is null then
40
+ raise exception 'no_counterpart_account: set receivable_account_id / payable_account_id on the contact or the company';
41
+ end if;
42
+ return v_account;
43
+ end;
44
+ $$;
45
+
46
+ comment on function resolve_counterpart_account(uuid, uuid, boolean) is
47
+ 'Third-party account by role: contact override first, company default second. Never by code prefix.';
48
+
49
+
50
+ create or replace function post_document(p_document_id uuid)
51
+ returns entries
52
+ language plpgsql
53
+ as $$
54
+ declare
55
+ v_doc documents%rowtype;
56
+ v_entry entries%rowtype;
57
+ v_journal uuid;
58
+ v_date date;
59
+ v_is_sale boolean;
60
+ v_is_credit boolean;
61
+ v_kind tax_document_kind;
62
+ v_base_credit boolean;
63
+ v_seq integer := 0;
64
+ v_contact uuid;
65
+ v_maturity date;
66
+ v_terms smallint;
67
+ v_counterpart uuid;
68
+ v_diff numeric(16, 2);
69
+ v_amount numeric(16, 2);
70
+ v_side_credit boolean;
71
+ v_label text;
72
+ r record;
73
+ p record;
74
+ begin
75
+ select * into v_doc from documents where id = p_document_id for update;
76
+ if not found then
77
+ raise exception 'unknown_document: document % does not exist', p_document_id;
78
+ end if;
79
+ if v_doc.state = 'posted' then
80
+ raise exception 'document_already_posted: document % is already posted', p_document_id;
81
+ end if;
82
+ if v_doc.state = 'cancelled' then
83
+ raise exception 'document_cancelled: document % cannot be posted', p_document_id;
84
+ end if;
85
+ if v_doc.entry_id is not null then
86
+ raise exception 'document_already_booked: document % already points at entry %',
87
+ p_document_id, v_doc.entry_id;
88
+ end if;
89
+
90
+ if v_doc.doc_type in ('sale_quote', 'purchase_order') then
91
+ raise exception 'document_not_accountable: a % is not booked', v_doc.doc_type;
92
+ end if;
93
+
94
+ v_is_sale := v_doc.doc_type in ('sale_invoice', 'sale_credit_note');
95
+ v_is_credit := v_doc.doc_type in ('sale_credit_note', 'purchase_credit_note');
96
+ v_kind := case when v_is_credit then 'credit_note' else 'invoice' end::tax_document_kind;
97
+ -- Sale invoice and purchase credit note credit the base; the other two debit it.
98
+ v_base_credit := (v_is_sale <> v_is_credit);
99
+
100
+ v_date := coalesce(v_doc.accounting_date, v_doc.document_date);
101
+
102
+ if not exists (
103
+ select 1 from document_lines
104
+ where document_id = p_document_id and line_type = 'product' and amount_untaxed <> 0
105
+ ) then
106
+ raise exception 'document_empty: document % has no billable line', p_document_id;
107
+ end if;
108
+
109
+ -- A fixed-amount tax has no basis to spread over lines; refuse rather than
110
+ -- guess.
111
+ if exists (
112
+ select 1 from document_lines l join taxes t on t.id = l.tax_id
113
+ where l.document_id = p_document_id and t.amount_type <> 'percent'
114
+ ) then
115
+ raise exception 'unsupported_tax_amount_type: only percentage taxes can be posted';
116
+ end if;
117
+
118
+ -- Every tax used must be in force on the accounting date.
119
+ for r in
120
+ select distinct t.id, t.code, t.valid_from, t.valid_to
121
+ from document_lines l join taxes t on t.id = l.tax_id
122
+ where l.document_id = p_document_id
123
+ loop
124
+ if v_date < r.valid_from or (r.valid_to is not null and v_date > r.valid_to) then
125
+ raise exception 'tax_not_in_force: tax % is not applicable on %', r.code, v_date;
126
+ end if;
127
+ end loop;
128
+
129
+ -- Totals are derived; make sure they reflect the lines as they stand now.
130
+ perform documents_refresh_totals(p_document_id);
131
+ select * into v_doc from documents where id = p_document_id;
132
+
133
+ v_journal := coalesce(
134
+ v_doc.journal_id,
135
+ case when v_is_sale
136
+ then (select sales_journal_id from companies where id = v_doc.company_id)
137
+ else (select purchase_journal_id from companies where id = v_doc.company_id)
138
+ end
139
+ );
140
+ if v_journal is null then
141
+ raise exception 'no_journal: set journal_id on the document or a default journal on the company';
142
+ end if;
143
+
144
+ perform assert_period_open(v_doc.company_id, v_date, true);
145
+
146
+ v_label := coalesce(v_doc.number, v_doc.supplier_reference, 'document');
147
+
148
+ insert into entries (company_id, journal_id, fiscal_year_id, entry_date, reference,
149
+ description, state, document_id, currency_code)
150
+ values (v_doc.company_id, v_journal, fiscal_year_at(v_doc.company_id, v_date), v_date,
151
+ coalesce(v_doc.number, v_doc.supplier_reference),
152
+ v_label || case when v_doc.supplier_reference is not null and v_doc.number is not null
153
+ then ' / ' || v_doc.supplier_reference else '' end,
154
+ 'draft', p_document_id, v_doc.currency_code)
155
+ returning * into v_entry;
156
+
157
+ -- ------------------------------------------------------------------ bases
158
+ for r in
159
+ select l.account_id,
160
+ l.tax_id,
161
+ sum(l.amount_untaxed) as base_amount,
162
+ min(l.sequence) as seq,
163
+ string_agg(distinct l.name, ', ') as label
164
+ from document_lines l
165
+ where l.document_id = p_document_id
166
+ and l.line_type = 'product'
167
+ group by l.account_id, l.tax_id
168
+ having sum(l.amount_untaxed) <> 0
169
+ order by 4
170
+ loop
171
+ select tp.declaration_box, tp.factor_percent, tp.box_factor_percent
172
+ into p
173
+ from tax_postings tp
174
+ where tp.tax_id = r.tax_id
175
+ and tp.document_kind = v_kind
176
+ and tp.posting_type = 'base'
177
+ limit 1;
178
+
179
+ v_amount := round(r.base_amount * coalesce(p.factor_percent, 100) / 100, 2);
180
+ v_seq := v_seq + 10;
181
+
182
+ insert into entry_lines (entry_id, company_id, account_id, sequence, name,
183
+ debit, credit, tax_id, tax_line,
184
+ declaration_box, box_amount, currency_code)
185
+ values (v_entry.id, v_doc.company_id, r.account_id, v_seq, left(r.label, 200),
186
+ case when v_base_credit then 0 else v_amount end,
187
+ case when v_base_credit then v_amount else 0 end,
188
+ r.tax_id, false,
189
+ p.declaration_box,
190
+ case when p.declaration_box is null then null
191
+ else round(r.base_amount * coalesce(p.box_factor_percent, 100) / 100, 2) end,
192
+ v_doc.currency_code);
193
+ end loop;
194
+
195
+ -- ------------------------------------------------------------------ taxes
196
+ for r in
197
+ select s.tax_id, s.tax_code, s.tax_name, s.tax_amount
198
+ from document_tax_summary s
199
+ where s.document_id = p_document_id
200
+ and s.tax_id is not null
201
+ and s.tax_amount <> 0
202
+ order by s.tax_code
203
+ loop
204
+ for p in
205
+ select tp.factor_percent, tp.account_id, tp.declaration_box, tp.box_factor_percent
206
+ from tax_postings tp
207
+ where tp.tax_id = r.tax_id
208
+ and tp.document_kind = v_kind
209
+ and tp.posting_type = 'tax'
210
+ order by tp.sequence, tp.id
211
+ loop
212
+ v_amount := round(r.tax_amount * abs(p.factor_percent) / 100, 2);
213
+ if v_amount = 0 then
214
+ continue;
215
+ end if;
216
+ -- A positive factor keeps the side of the base, a negative one flips it.
217
+ v_side_credit := case when p.factor_percent >= 0 then v_base_credit else not v_base_credit end;
218
+ v_seq := v_seq + 10;
219
+
220
+ insert into entry_lines (entry_id, company_id, account_id, sequence, name,
221
+ debit, credit, tax_id, tax_line,
222
+ declaration_box, box_amount, currency_code)
223
+ values (v_entry.id, v_doc.company_id, p.account_id, v_seq, r.tax_name,
224
+ case when v_side_credit then 0 else v_amount end,
225
+ case when v_side_credit then v_amount else 0 end,
226
+ r.tax_id, true,
227
+ p.declaration_box,
228
+ case when p.declaration_box is null then null
229
+ else round(r.tax_amount * coalesce(p.box_factor_percent, 100) / 100, 2) end,
230
+ v_doc.currency_code);
231
+ end loop;
232
+ end loop;
233
+
234
+ -- ------------------------------------------------------------ counterpart
235
+ select total_debit - total_credit into v_diff from entries where id = v_entry.id;
236
+
237
+ if v_diff = 0 then
238
+ raise exception 'document_counterpart_zero: document % produced a nil counterpart', p_document_id;
239
+ end if;
240
+
241
+ v_contact := commercial_entity(v_doc.contact_id);
242
+ v_counterpart := resolve_counterpart_account(v_doc.company_id, v_contact, v_is_sale);
243
+
244
+ select payment_terms_days into v_terms from contacts where id = v_contact;
245
+ v_maturity := coalesce(v_doc.due_date, v_doc.document_date + coalesce(v_terms, 30));
246
+
247
+ v_amount := abs(v_diff);
248
+ v_seq := v_seq + 10;
249
+
250
+ insert into entry_lines (entry_id, company_id, account_id, sequence, name,
251
+ debit, credit, contact_id, date_maturity, currency_code)
252
+ values (v_entry.id, v_doc.company_id, v_counterpart, v_seq, v_label,
253
+ case when v_diff > 0 then 0 else v_amount end,
254
+ case when v_diff > 0 then v_amount else 0 end,
255
+ v_contact, v_maturity, v_doc.currency_code);
256
+
257
+ -- The ledger is right by construction. If the header disagrees, the header
258
+ -- is what is wrong, and we say so instead of quietly patching a line.
259
+ if abs(v_amount - abs(v_doc.amount_total)) > 0.005 then
260
+ raise exception 'document_total_mismatch: document % totals % but its lines book %',
261
+ p_document_id, v_doc.amount_total, v_amount;
262
+ end if;
263
+
264
+ -- --------------------------------------------------------------- posting
265
+ v_entry := post_entry(v_entry.id);
266
+
267
+ update documents
268
+ set state = 'posted',
269
+ number = coalesce(number, v_entry.number),
270
+ entry_id = v_entry.id,
271
+ accounting_date = v_date
272
+ where id = p_document_id;
273
+
274
+ return v_entry;
275
+ end;
276
+ $$;
277
+
278
+ comment on function post_document(uuid) is
279
+ 'Books a document: base lines, tax lines from tax_postings, and a counterpart that balances by construction.';