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