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