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,349 @@
|
|
|
1
|
+
-- Ekwo OS — how often a company files, written down instead of asked every time.
|
|
2
|
+
--
|
|
3
|
+
-- `vat_return()` takes two dates and works out the boxes between them, which is
|
|
4
|
+
-- right: a return is a period, and the caller knows which one. What nothing
|
|
5
|
+
-- held was **how often this company files at all**. Luxembourg sets the cadence
|
|
6
|
+
-- by turnover — annual up to 112 000 euros, quarterly to 620 000, monthly above
|
|
7
|
+
-- — and the pack could not say so; a Belgian company on quarterly returns and
|
|
8
|
+
-- one on monthly returns were the same row. So `ekwo status`, a reminder, and
|
|
9
|
+
-- any client offering "file the current period" had to ask a human every time,
|
|
10
|
+
-- and nothing stopped a quarterly filer from being handed a July return.
|
|
11
|
+
--
|
|
12
|
+
-- Three pieces, and each one is in the place that owns the answer.
|
|
13
|
+
--
|
|
14
|
+
-- `tax_report_templates.periods` what the **form** accepts. A list, because
|
|
15
|
+
-- a country may file one set of boxes on more than one cadence: the
|
|
16
|
+
-- column held a single value with `month_or_quarter` bolted on as a
|
|
17
|
+
-- fourth word, which cannot say "month, quarter or year" and is not a
|
|
18
|
+
-- cadence anybody files on. The list can.
|
|
19
|
+
-- `companies.vat_period` what **this company** files. Nullable, and
|
|
20
|
+
-- with no default: a company that has not said keeps its books exactly as
|
|
21
|
+
-- before, and nothing here guesses. A guess would be a missed deadline.
|
|
22
|
+
-- `country_defaults.vat_period_default` what the **pack proposes**, when the
|
|
23
|
+
-- law of that country gives one answer that does not depend on a fact
|
|
24
|
+
-- about the company. Null everywhere it does depend on one, which is
|
|
25
|
+
-- three of the four packs here today — see the note on the column.
|
|
26
|
+
--
|
|
27
|
+
-- **The vocabulary is the one already published**: `month`, `quarter`, `year`,
|
|
28
|
+
-- now an enum rather than three spellings agreed by convention. A second
|
|
29
|
+
-- spelling — `monthly`, `quarterly` — would be the same fact written twice.
|
|
30
|
+
-- `month_or_quarter` becomes the two cadences it always meant.
|
|
31
|
+
--
|
|
32
|
+
-- **What the return does with it.** It refuses a period the company does not
|
|
33
|
+
-- file on, by name, and only when the refusal is certain: the company has
|
|
34
|
+
-- recorded a cadence, the form offers that cadence, the dates asked for are
|
|
35
|
+
-- themselves a whole cadence the form offers, and the two differ. Anything
|
|
36
|
+
-- else is an analysis and not a filing — a fortnight, a half-year, the annual
|
|
37
|
+
-- recapitulative form a quarterly filer also files — and it goes through.
|
|
38
|
+
|
|
39
|
+
-- ---------------------------------------------------------------------------
|
|
40
|
+
-- The vocabulary
|
|
41
|
+
-- ---------------------------------------------------------------------------
|
|
42
|
+
|
|
43
|
+
do $$
|
|
44
|
+
begin
|
|
45
|
+
if not exists (select 1 from pg_type where typname = 'declaration_period') then
|
|
46
|
+
create type declaration_period as enum ('month', 'quarter', 'year');
|
|
47
|
+
end if;
|
|
48
|
+
end;
|
|
49
|
+
$$;
|
|
50
|
+
|
|
51
|
+
comment on type declaration_period is
|
|
52
|
+
'How often a declaration is filed: month, quarter, year. The three cadences every European periodic return is filed on; a country that files on another adds a value here rather than a word of its own somewhere else.';
|
|
53
|
+
|
|
54
|
+
-- ---------------------------------------------------------------------------
|
|
55
|
+
-- What a form accepts
|
|
56
|
+
-- ---------------------------------------------------------------------------
|
|
57
|
+
--
|
|
58
|
+
-- `period` was `text not null default 'month_or_quarter'`, and that default is
|
|
59
|
+
-- the reason this column could not be trusted: a pack that said nothing about
|
|
60
|
+
-- its cadence got Belgium's and France's answer, silently. There is no default
|
|
61
|
+
-- now. A form says what it accepts, or `ekwo pack check` refuses the pack.
|
|
62
|
+
--
|
|
63
|
+
-- Duplicates in the list are not refused by a constraint. `= any(periods)`
|
|
64
|
+
-- reads `{month,month}` exactly as it reads `{month}`, so a duplicate changes
|
|
65
|
+
-- no behaviour; `ekwo pack check` says so at the one moment it is worth saying,
|
|
66
|
+
-- which is when somebody is writing the pack.
|
|
67
|
+
|
|
68
|
+
alter table tax_report_templates drop constraint if exists tax_report_templates_period;
|
|
69
|
+
alter table tax_report_templates alter column period drop default;
|
|
70
|
+
|
|
71
|
+
alter table tax_report_templates
|
|
72
|
+
alter column period type declaration_period[]
|
|
73
|
+
using (
|
|
74
|
+
case period
|
|
75
|
+
when 'month_or_quarter' then array['month', 'quarter']
|
|
76
|
+
else array[period]
|
|
77
|
+
end
|
|
78
|
+
)::declaration_period[];
|
|
79
|
+
|
|
80
|
+
alter table tax_report_templates rename column period to periods;
|
|
81
|
+
|
|
82
|
+
alter table tax_report_templates
|
|
83
|
+
add constraint tax_report_templates_periods_not_empty check (cardinality(periods) >= 1);
|
|
84
|
+
|
|
85
|
+
comment on column tax_report_templates.periods is
|
|
86
|
+
'Cadences this form is filed on, from packs/<cc>/tax_report.json. A list because one set of boxes may be filed monthly, quarterly or annually depending on turnover. No default: a pack that names none is refused by `ekwo pack check`.';
|
|
87
|
+
|
|
88
|
+
-- ---------------------------------------------------------------------------
|
|
89
|
+
-- What a company files, and what a pack proposes
|
|
90
|
+
-- ---------------------------------------------------------------------------
|
|
91
|
+
|
|
92
|
+
alter table companies
|
|
93
|
+
add column if not exists vat_period declaration_period;
|
|
94
|
+
|
|
95
|
+
comment on column companies.vat_period is
|
|
96
|
+
'How often this company files its periodic return. Null means it has not been recorded, which is not an error and not a cadence: the books are kept the same either way, vat_return() imposes nothing, and `ekwo status` says "not recorded" rather than naming a cadence nobody chose.';
|
|
97
|
+
|
|
98
|
+
alter table country_defaults
|
|
99
|
+
add column if not exists vat_period_default declaration_period;
|
|
100
|
+
|
|
101
|
+
comment on column country_defaults.vat_period_default is
|
|
102
|
+
'Cadence a company of this country files on unless it says otherwise, from the pack. Null wherever the law makes the cadence depend on a fact about the company — turnover in Belgium, France and Luxembourg — because a pack proposing one of two lawful answers there would be choosing a filing deadline for somebody it knows nothing about. Set where the law gives one answer for everybody, as in Estonia. Read at install; never read by the return.';
|
|
103
|
+
|
|
104
|
+
-- ---------------------------------------------------------------------------
|
|
105
|
+
-- Which cadence a pair of dates is
|
|
106
|
+
-- ---------------------------------------------------------------------------
|
|
107
|
+
--
|
|
108
|
+
-- A whole calendar month, quarter or year, and null for anything else. Null is
|
|
109
|
+
-- the useful half of the answer: it is what tells the return that it is being
|
|
110
|
+
-- asked for an analysis rather than for a filing, and an analysis is refused
|
|
111
|
+
-- for nothing.
|
|
112
|
+
|
|
113
|
+
create or replace function declaration_period_of(p_from date, p_to date)
|
|
114
|
+
returns declaration_period
|
|
115
|
+
language sql
|
|
116
|
+
immutable
|
|
117
|
+
as $$
|
|
118
|
+
select case
|
|
119
|
+
when p_from = date_trunc('month', p_from)::date
|
|
120
|
+
and p_to = (date_trunc('month', p_from) + interval '1 month' - interval '1 day')::date
|
|
121
|
+
then 'month'::declaration_period
|
|
122
|
+
when p_from = date_trunc('quarter', p_from)::date
|
|
123
|
+
and p_to = (date_trunc('quarter', p_from) + interval '3 months' - interval '1 day')::date
|
|
124
|
+
then 'quarter'::declaration_period
|
|
125
|
+
when p_from = date_trunc('year', p_from)::date
|
|
126
|
+
and p_to = (date_trunc('year', p_from) + interval '1 year' - interval '1 day')::date
|
|
127
|
+
then 'year'::declaration_period
|
|
128
|
+
else null
|
|
129
|
+
end;
|
|
130
|
+
$$;
|
|
131
|
+
|
|
132
|
+
comment on function declaration_period_of(date, date) is
|
|
133
|
+
'The cadence a pair of dates is a whole one of — month, quarter, year — or null when the two dates are not a filing period at all.';
|
|
134
|
+
|
|
135
|
+
revoke execute on function declaration_period_of(date, date) from public, anon;
|
|
136
|
+
grant execute on function declaration_period_of(date, date) to authenticated, service_role;
|
|
137
|
+
|
|
138
|
+
-- ---------------------------------------------------------------------------
|
|
139
|
+
-- The return reads it
|
|
140
|
+
-- ---------------------------------------------------------------------------
|
|
141
|
+
--
|
|
142
|
+
-- Replaced whole rather than patched, because a function is replaced whole in
|
|
143
|
+
-- PostgreSQL. Everything below the guard is `20260914121200` unchanged.
|
|
144
|
+
|
|
145
|
+
create or replace function vat_return(
|
|
146
|
+
p_company_id uuid,
|
|
147
|
+
p_from date,
|
|
148
|
+
p_to date,
|
|
149
|
+
p_report_code text default null
|
|
150
|
+
)
|
|
151
|
+
returns table (
|
|
152
|
+
box text,
|
|
153
|
+
kind text,
|
|
154
|
+
amount numeric,
|
|
155
|
+
computed boolean,
|
|
156
|
+
name text,
|
|
157
|
+
sequence integer,
|
|
158
|
+
hidden boolean,
|
|
159
|
+
report_code text
|
|
160
|
+
)
|
|
161
|
+
language plpgsql
|
|
162
|
+
stable
|
|
163
|
+
as $$
|
|
164
|
+
declare
|
|
165
|
+
-- 'box|kind' -> amount, for every box summed from the ledger, then the
|
|
166
|
+
-- totals `evaluate_totals()` derives from them. The key carries the kind
|
|
167
|
+
-- because the French CA3 puts a base and a tax on line 08 and a formula has
|
|
168
|
+
-- to be able to name one of them.
|
|
169
|
+
v_values jsonb := '{}'::jsonb;
|
|
170
|
+
v_formulas jsonb := '[]'::jsonb;
|
|
171
|
+
v_totals jsonb := '{}'::jsonb;
|
|
172
|
+
v_rows jsonb := '[]'::jsonb;
|
|
173
|
+
v_country char(2);
|
|
174
|
+
v_report text;
|
|
175
|
+
v_in char(2);
|
|
176
|
+
v_count integer;
|
|
177
|
+
v_codes text;
|
|
178
|
+
-- How often this company files, what the form accepts, and what the two
|
|
179
|
+
-- dates asked for actually are.
|
|
180
|
+
v_files declaration_period;
|
|
181
|
+
v_accepts declaration_period[];
|
|
182
|
+
v_asked declaration_period;
|
|
183
|
+
-- A declaration figure is not a ledger figure, but it is written in the
|
|
184
|
+
-- same currency and with the same decimals.
|
|
185
|
+
v_round money_rounding;
|
|
186
|
+
r record;
|
|
187
|
+
begin
|
|
188
|
+
select c.fiscal_country, c.vat_period into v_country, v_files
|
|
189
|
+
from companies c where c.id = p_company_id;
|
|
190
|
+
if not found then
|
|
191
|
+
raise exception 'unknown_company: %', p_company_id;
|
|
192
|
+
end if;
|
|
193
|
+
v_round := rounding_of(p_company_id);
|
|
194
|
+
|
|
195
|
+
-- Which form. The caller names one, or the country files exactly one on
|
|
196
|
+
-- that date. Two and no name is a question only the caller can answer — a
|
|
197
|
+
-- Canadian company files the federal return and the Québec one at once — so
|
|
198
|
+
-- this asks instead of guessing.
|
|
199
|
+
if p_report_code is not null then
|
|
200
|
+
select t.country, t.code into v_in, v_report
|
|
201
|
+
from tax_report_templates t
|
|
202
|
+
where t.code = p_report_code
|
|
203
|
+
and t.valid_from <= p_to
|
|
204
|
+
and (t.valid_to is null or t.valid_to >= p_to)
|
|
205
|
+
order by t.country
|
|
206
|
+
limit 1;
|
|
207
|
+
if v_report is null then
|
|
208
|
+
raise exception 'unknown_tax_report: % is not a declaration form in force on %',
|
|
209
|
+
p_report_code, p_to;
|
|
210
|
+
end if;
|
|
211
|
+
else
|
|
212
|
+
select count(*), min(t.code), string_agg(t.code, ', ' order by t.code)
|
|
213
|
+
into v_count, v_report, v_codes
|
|
214
|
+
from tax_report_templates t
|
|
215
|
+
where t.country = v_country
|
|
216
|
+
and t.is_periodic_return
|
|
217
|
+
and t.valid_from <= p_to
|
|
218
|
+
and (t.valid_to is null or t.valid_to >= p_to);
|
|
219
|
+
if v_count > 1 then
|
|
220
|
+
raise exception 'ambiguous_tax_report: % files several declarations on % (%); name one',
|
|
221
|
+
v_country, p_to, v_codes;
|
|
222
|
+
end if;
|
|
223
|
+
v_in := v_country;
|
|
224
|
+
if v_count = 0 then
|
|
225
|
+
v_report := null; -- no pack for this country: the ledger boxes, and no total.
|
|
226
|
+
end if;
|
|
227
|
+
end if;
|
|
228
|
+
|
|
229
|
+
-- The period asked for against the one this company files on. Four things
|
|
230
|
+
-- have to hold before this refuses, and the fourth is what keeps it out of
|
|
231
|
+
-- everybody's way: the company has recorded a cadence, the form is one it
|
|
232
|
+
-- files on that cadence, the dates are themselves a whole cadence of that
|
|
233
|
+
-- form, and the two are not the same. A fortnight, a half-year, the annual
|
|
234
|
+
-- recapitulative form a quarterly filer also files — none of those is a
|
|
235
|
+
-- filing on the wrong cadence, and none of them is refused.
|
|
236
|
+
if v_files is not null and v_report is not null then
|
|
237
|
+
select t.periods into v_accepts
|
|
238
|
+
from tax_report_templates t
|
|
239
|
+
where t.country = v_in and t.code = v_report;
|
|
240
|
+
v_asked := declaration_period_of(p_from, p_to);
|
|
241
|
+
if v_asked is not null
|
|
242
|
+
and v_files = any(v_accepts)
|
|
243
|
+
and v_asked = any(v_accepts)
|
|
244
|
+
and v_asked <> v_files then
|
|
245
|
+
raise exception
|
|
246
|
+
'wrong_declaration_period: this company files % returns on %; % to % is a %',
|
|
247
|
+
v_files, v_report, p_from, p_to, v_asked;
|
|
248
|
+
end if;
|
|
249
|
+
end if;
|
|
250
|
+
|
|
251
|
+
-- 1. What the tax postings wrote on the ledger. Unchanged: this half never
|
|
252
|
+
-- knew a country.
|
|
253
|
+
for r in
|
|
254
|
+
with ledger as (
|
|
255
|
+
select l.declaration_box as lbox,
|
|
256
|
+
case when l.tax_line then 'tax' else 'base' end as lkind,
|
|
257
|
+
round_amount(sum(l.box_amount), v_round) as lamount
|
|
258
|
+
from entry_lines l
|
|
259
|
+
join entries e on e.id = l.entry_id
|
|
260
|
+
where l.company_id = p_company_id
|
|
261
|
+
and e.state = 'posted'
|
|
262
|
+
and e.entry_date between p_from and p_to
|
|
263
|
+
and l.declaration_box is not null
|
|
264
|
+
-- A box number belongs to one form. A line whose posting names
|
|
265
|
+
-- another form is not on this declaration; one that names none is
|
|
266
|
+
-- the single-return case every European company is in.
|
|
267
|
+
and (v_report is null or coalesce((
|
|
268
|
+
select min(tp.report_code)
|
|
269
|
+
from tax_postings tp
|
|
270
|
+
where tp.tax_id = l.tax_id
|
|
271
|
+
and tp.declaration_box = l.declaration_box
|
|
272
|
+
and tp.posting_type =
|
|
273
|
+
(case when l.tax_line then 'tax' else 'base' end)::tax_posting_type
|
|
274
|
+
), v_report) = v_report)
|
|
275
|
+
group by 1, 2
|
|
276
|
+
having round_amount(sum(l.box_amount), v_round) <> 0
|
|
277
|
+
)
|
|
278
|
+
select g.lbox, g.lkind, g.lamount, b.name as lname,
|
|
279
|
+
b.sequence as lsequence, coalesce(b.hidden, false) as lhidden
|
|
280
|
+
from ledger g
|
|
281
|
+
left join tax_report_box_templates b
|
|
282
|
+
on b.country = v_in and b.report_code = v_report
|
|
283
|
+
and b.box = g.lbox and b.kind = g.lkind
|
|
284
|
+
order by coalesce(b.sequence, 2147483647), g.lbox, g.lkind
|
|
285
|
+
loop
|
|
286
|
+
v_values := v_values || jsonb_build_object(r.lbox || '|' || r.lkind, r.lamount);
|
|
287
|
+
v_rows := v_rows || jsonb_build_array(jsonb_build_object(
|
|
288
|
+
'box', r.lbox, 'kind', r.lkind, 'amount', r.lamount, 'computed', false,
|
|
289
|
+
'name', r.lname, 'sequence', r.lsequence, 'hidden', r.lhidden,
|
|
290
|
+
'report_code', v_report));
|
|
291
|
+
end loop;
|
|
292
|
+
|
|
293
|
+
-- 2. The totals of the form, through the evaluator the statements use. A
|
|
294
|
+
-- return prints what it has, so a nil total is left out of the answer —
|
|
295
|
+
-- and kept in the working set, so a later total that names it reads a
|
|
296
|
+
-- zero rather than a gap.
|
|
297
|
+
if v_report is not null then
|
|
298
|
+
select coalesce(jsonb_agg(jsonb_build_object(
|
|
299
|
+
'key', b.box || '|total', 'plus', to_jsonb(b.plus_boxes),
|
|
300
|
+
'minus', to_jsonb(b.minus_boxes), 'floor_zero', b.floor_zero,
|
|
301
|
+
'sequence', b.sequence
|
|
302
|
+
) order by b.sequence, b.box), '[]'::jsonb)
|
|
303
|
+
into v_formulas
|
|
304
|
+
from tax_report_box_templates b
|
|
305
|
+
where b.country = v_in
|
|
306
|
+
and b.report_code = v_report
|
|
307
|
+
and b.kind = 'total'
|
|
308
|
+
and (b.valid_from is null or b.valid_from <= p_to)
|
|
309
|
+
and (b.valid_to is null or b.valid_to >= p_to);
|
|
310
|
+
|
|
311
|
+
v_totals := evaluate_totals(v_values, v_formulas, v_round, false);
|
|
312
|
+
|
|
313
|
+
for r in
|
|
314
|
+
select b.box as tbox, b.name as tname, b.sequence as tsequence, b.hidden as thidden
|
|
315
|
+
from tax_report_box_templates b
|
|
316
|
+
where b.country = v_in
|
|
317
|
+
and b.report_code = v_report
|
|
318
|
+
and b.kind = 'total'
|
|
319
|
+
and (b.valid_from is null or b.valid_from <= p_to)
|
|
320
|
+
and (b.valid_to is null or b.valid_to >= p_to)
|
|
321
|
+
and v_totals ? (b.box || '|total')
|
|
322
|
+
order by b.sequence, b.box
|
|
323
|
+
loop
|
|
324
|
+
v_rows := v_rows || jsonb_build_array(jsonb_build_object(
|
|
325
|
+
'box', r.tbox, 'kind', 'total',
|
|
326
|
+
'amount', (v_totals ->> (r.tbox || '|total'))::numeric, 'computed', true,
|
|
327
|
+
'name', r.tname, 'sequence', r.tsequence, 'hidden', r.thidden,
|
|
328
|
+
'report_code', v_report));
|
|
329
|
+
end loop;
|
|
330
|
+
end if;
|
|
331
|
+
|
|
332
|
+
return query
|
|
333
|
+
select (x ->> 'box')::text,
|
|
334
|
+
(x ->> 'kind')::text,
|
|
335
|
+
(x ->> 'amount')::numeric,
|
|
336
|
+
(x ->> 'computed')::boolean,
|
|
337
|
+
(x ->> 'name')::text,
|
|
338
|
+
(x ->> 'sequence')::integer,
|
|
339
|
+
(x ->> 'hidden')::boolean,
|
|
340
|
+
(x ->> 'report_code')::text
|
|
341
|
+
from jsonb_array_elements(v_rows) as x;
|
|
342
|
+
end;
|
|
343
|
+
$$;
|
|
344
|
+
|
|
345
|
+
comment on function vat_return(uuid, date, date, text) is
|
|
346
|
+
'Declaration boxes for a period: summed from the ledger, then the totals of the country''s form worked out by evaluate_totals(), the same evaluator financial_statement() uses. Refuses a period the company does not file on, when it has recorded one. No country rule lives in this function.';
|
|
347
|
+
|
|
348
|
+
revoke execute on function vat_return(uuid, date, date, text) from public, anon;
|
|
349
|
+
grant execute on function vat_return(uuid, date, date, text) to authenticated, service_role;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
-- Ekwo OS — a service bought from a supplier who is not established here.
|
|
2
|
+
--
|
|
3
|
+
-- The `tax_treatment` vocabulary had `intracom_acquisition_services` for a
|
|
4
|
+
-- supplier in another Member State and `import` for goods crossing the
|
|
5
|
+
-- Union's border, and nothing at all for the case in between: a service
|
|
6
|
+
-- received from a supplier who is not established in the buyer's country, on
|
|
7
|
+
-- which the buyer accounts for the tax themselves under the general
|
|
8
|
+
-- business-to-business rule — articles 44 and 196 of Directive 2006/112/EC.
|
|
9
|
+
-- Every Member State needs it, and `docs/international.md` recorded it as a
|
|
10
|
+
-- gap when the Estonian pack had to declare such a tax as `import`, which is
|
|
11
|
+
-- a rule about goods.
|
|
12
|
+
--
|
|
13
|
+
-- The name is `foreign_services_received` rather than `import_services`,
|
|
14
|
+
-- which is what that note proposed, for two reasons. The rule turns on
|
|
15
|
+
-- **establishment** and not on the border: a supplier established in another
|
|
16
|
+
-- Member State but not registered here falls under the same article, so a
|
|
17
|
+
-- name built on "import" would be as wrong for this treatment as `import`
|
|
18
|
+
-- already was. And `import` in this vocabulary means goods declared to
|
|
19
|
+
-- customs, an entirely different mechanism with an entirely different
|
|
20
|
+
-- document behind it; a name that echoed it would invite exactly the
|
|
21
|
+
-- confusion this value exists to end.
|
|
22
|
+
--
|
|
23
|
+
-- Nothing in the core branches on a treatment, here or anywhere: the value
|
|
24
|
+
-- documents the tax, and what the tax does is said by its postings. What it
|
|
25
|
+
-- does change is the legal mention a document carries, which the next
|
|
26
|
+
-- migration reads, and what `ekwo pack check` requires of the tax's
|
|
27
|
+
-- EN 16931 category — a supplier not established here writes no invoice the
|
|
28
|
+
-- standard governs, so there is no category of theirs to record.
|
|
29
|
+
--
|
|
30
|
+
-- A value added to an enum cannot be used in the transaction that adds it.
|
|
31
|
+
-- The runner applies each file as one transaction, so the value is added
|
|
32
|
+
-- alone here and used by the files that come after.
|
|
33
|
+
|
|
34
|
+
alter type tax_treatment add value 'foreign_services_received' after 'intracom_acquisition_services';
|
|
35
|
+
|
|
36
|
+
-- No object is created, so there is nothing to grant. The type itself is
|
|
37
|
+
-- reachable by everyone who can already read the column that uses it.
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
-- Ekwo OS — where `foreign_services_received` lands among the legal mentions.
|
|
2
|
+
--
|
|
3
|
+
-- `document_legal_mentions` resolves nine conditions, six of them from the
|
|
4
|
+
-- treatments of the taxes a document's lines carry. A treatment the `case`
|
|
5
|
+
-- does not name falls through every branch and produces no sentence at all,
|
|
6
|
+
-- which is what `import` does and is right for it: goods declared to customs
|
|
7
|
+
-- put nothing on an invoice the company writes.
|
|
8
|
+
--
|
|
9
|
+
-- A service received from a supplier who is not established here is the other
|
|
10
|
+
-- shape. The tax on it is accounted for by the recipient under articles 44
|
|
11
|
+
-- and 196 of Directive 2006/112/EC, and the sentence that says so is the
|
|
12
|
+
-- reverse-charge one — the same mechanism, and the same wording in all four
|
|
13
|
+
-- packs of this repository. So the value joins `reverse_charge` rather than
|
|
14
|
+
-- `intra_eu_services`, which is about a supply between two Member States and
|
|
15
|
+
-- says the wrong thing about a supplier outside one.
|
|
16
|
+
--
|
|
17
|
+
-- It joins it beside `domestic_reverse_charge`, and the two stay distinct
|
|
18
|
+
-- values because they are two different articles and two different boxes of a
|
|
19
|
+
-- return; what they share is the sentence.
|
|
20
|
+
--
|
|
21
|
+
-- Nothing else in the view changes. `create or replace view` keeps the grant
|
|
22
|
+
-- and the policy of the object it replaces, and the columns are the same
|
|
23
|
+
-- columns in the same order, which is what `create or replace` requires.
|
|
24
|
+
|
|
25
|
+
create or replace view document_legal_mentions
|
|
26
|
+
with (security_invoker = true) as
|
|
27
|
+
with document_taxes as (
|
|
28
|
+
select d.id as document_id,
|
|
29
|
+
d.company_id,
|
|
30
|
+
c.fiscal_country as country,
|
|
31
|
+
d.document_date,
|
|
32
|
+
d.doc_type,
|
|
33
|
+
coalesce(
|
|
34
|
+
array_agg(distinct t.treatment::text) filter (where t.treatment is not null),
|
|
35
|
+
array[]::text[]
|
|
36
|
+
) as treatments,
|
|
37
|
+
coalesce(bool_or(t.cash_basis), false) as on_cash_basis
|
|
38
|
+
from documents d
|
|
39
|
+
join companies c on c.id = d.company_id
|
|
40
|
+
left join document_lines l on l.document_id = d.id
|
|
41
|
+
left join taxes t on t.id = l.tax_id
|
|
42
|
+
group by d.id, d.company_id, c.fiscal_country, d.document_date, d.doc_type
|
|
43
|
+
)
|
|
44
|
+
select dt.document_id,
|
|
45
|
+
dt.company_id,
|
|
46
|
+
m.country,
|
|
47
|
+
m.code,
|
|
48
|
+
m.applies_when,
|
|
49
|
+
m.text,
|
|
50
|
+
m.text_i18n,
|
|
51
|
+
m.sequence,
|
|
52
|
+
m.legal_reference
|
|
53
|
+
from document_taxes dt
|
|
54
|
+
join legal_mention_templates m
|
|
55
|
+
on m.country = dt.country
|
|
56
|
+
and m.valid_from <= dt.document_date
|
|
57
|
+
and (m.valid_to is null or m.valid_to >= dt.document_date)
|
|
58
|
+
where case m.applies_when
|
|
59
|
+
when 'always' then true
|
|
60
|
+
when 'reverse_charge' then dt.treatments
|
|
61
|
+
&& array['domestic_reverse_charge', 'foreign_services_received']
|
|
62
|
+
when 'intra_eu_goods' then dt.treatments && array['intracom_goods', 'intracom_acquisition_goods']
|
|
63
|
+
when 'intra_eu_services' then dt.treatments && array['intracom_services', 'intracom_acquisition_services']
|
|
64
|
+
when 'export' then dt.treatments && array['export']
|
|
65
|
+
when 'exempt' then dt.treatments && array['exempt']
|
|
66
|
+
when 'cash_basis' then dt.on_cash_basis
|
|
67
|
+
when 'late_payment' then dt.doc_type in ('sale_invoice', 'sale_credit_note')
|
|
68
|
+
else false
|
|
69
|
+
end;
|
|
70
|
+
|
|
71
|
+
comment on view document_legal_mentions is
|
|
72
|
+
'The legal mentions that apply to a document: its country, the validity of the mention on its date, and the treatments of the taxes its lines carry. A reverse-charge mention comes out for a domestic reverse charge and for a service received from a supplier who is not established here, which is the same mechanism under a different article. A small_business mention never comes out, because no column records the regime.';
|