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,146 @@
|
|
|
1
|
+
-- Ekwo OS — taxes and their postings.
|
|
2
|
+
--
|
|
3
|
+
-- A tax says how much. `tax_postings` say where it lands in the ledger and in
|
|
4
|
+
-- which box of the VAT return. That indirection is what keeps country rules
|
|
5
|
+
-- out of application code.
|
|
6
|
+
|
|
7
|
+
create type tax_amount_type as enum ('percent', 'fixed');
|
|
8
|
+
create type tax_scope as enum ('sale', 'purchase', 'both');
|
|
9
|
+
create type tax_document_kind as enum ('invoice', 'credit_note');
|
|
10
|
+
create type tax_posting_type as enum ('base', 'tax');
|
|
11
|
+
|
|
12
|
+
-- How an operation is treated for the return. Drives nothing on its own; it
|
|
13
|
+
-- documents the tax and lets an application group taxes sensibly.
|
|
14
|
+
create type tax_treatment as enum (
|
|
15
|
+
'domestic',
|
|
16
|
+
'domestic_reverse_charge',
|
|
17
|
+
'intracom_goods',
|
|
18
|
+
'intracom_services',
|
|
19
|
+
'intracom_acquisition_goods',
|
|
20
|
+
'intracom_acquisition_services',
|
|
21
|
+
'export',
|
|
22
|
+
'import',
|
|
23
|
+
'exempt',
|
|
24
|
+
'not_subject'
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
create table taxes (
|
|
28
|
+
id uuid primary key default gen_random_uuid(),
|
|
29
|
+
company_id uuid not null references companies(id) on delete cascade,
|
|
30
|
+
code text not null,
|
|
31
|
+
name text not null,
|
|
32
|
+
description text,
|
|
33
|
+
amount_type tax_amount_type not null default 'percent',
|
|
34
|
+
-- Percentage when amount_type = 'percent', absolute amount when 'fixed'.
|
|
35
|
+
amount numeric(12, 4) not null default 0,
|
|
36
|
+
applies_to tax_scope not null default 'both',
|
|
37
|
+
treatment tax_treatment not null default 'domestic',
|
|
38
|
+
country char(2),
|
|
39
|
+
-- Temporal validity. A rate change is a new period, not a new tax.
|
|
40
|
+
valid_from date not null default date '1970-01-01',
|
|
41
|
+
valid_to date,
|
|
42
|
+
legal_reference text,
|
|
43
|
+
-- EN 16931 BT-118 category code: S, Z, E, AE, K, G, O, L, M.
|
|
44
|
+
vat_category char(2),
|
|
45
|
+
exemption_code text,
|
|
46
|
+
price_include boolean not null default false,
|
|
47
|
+
sequence integer not null default 10,
|
|
48
|
+
active boolean not null default true,
|
|
49
|
+
created_at timestamptz not null default now(),
|
|
50
|
+
updated_at timestamptz not null default now(),
|
|
51
|
+
unique (company_id, code),
|
|
52
|
+
constraint taxes_validity check (valid_to is null or valid_to >= valid_from),
|
|
53
|
+
constraint taxes_country_format check (country is null or country ~ '^[A-Z]{2}$')
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
comment on table taxes is 'VAT and similar taxes, with temporal validity and a legal reference.';
|
|
57
|
+
comment on column taxes.amount is 'Percentage (21.0000) or fixed amount, per amount_type.';
|
|
58
|
+
comment on column taxes.vat_category is 'EN 16931 BT-118 / BT-151 category code.';
|
|
59
|
+
|
|
60
|
+
create index taxes_company_active_idx on taxes (company_id, active);
|
|
61
|
+
create unique index taxes_id_company_idx on taxes (id, company_id);
|
|
62
|
+
|
|
63
|
+
create trigger taxes_set_updated_at
|
|
64
|
+
before update on taxes
|
|
65
|
+
for each row execute function set_updated_at();
|
|
66
|
+
|
|
67
|
+
-- ---------------------------------------------------------------------------
|
|
68
|
+
-- tax_postings
|
|
69
|
+
-- ---------------------------------------------------------------------------
|
|
70
|
+
|
|
71
|
+
create table tax_postings (
|
|
72
|
+
id uuid primary key default gen_random_uuid(),
|
|
73
|
+
tax_id uuid not null references taxes(id) on delete cascade,
|
|
74
|
+
company_id uuid not null references companies(id) on delete cascade,
|
|
75
|
+
document_kind tax_document_kind not null default 'invoice',
|
|
76
|
+
posting_type tax_posting_type not null,
|
|
77
|
+
-- Share of the amount carried by this posting. Positive keeps the side of
|
|
78
|
+
-- the base line, negative flips it: that is how a self-assessed tax books
|
|
79
|
+
-- +100 on the deductible account and -100 on the payable one.
|
|
80
|
+
factor_percent numeric(7, 3) not null default 100,
|
|
81
|
+
-- NULL on a base posting: the base keeps the account of the document line.
|
|
82
|
+
account_id uuid references accounts(id) on delete restrict,
|
|
83
|
+
-- Box of the national VAT return this posting feeds, e.g. '03', '59', 'B1'.
|
|
84
|
+
declaration_box text,
|
|
85
|
+
-- Share reported in that box. Independent from factor_percent, because a
|
|
86
|
+
-- box is always filled with the sign the form expects.
|
|
87
|
+
box_factor_percent numeric(7, 3) not null default 100,
|
|
88
|
+
sequence integer not null default 10,
|
|
89
|
+
created_at timestamptz not null default now(),
|
|
90
|
+
updated_at timestamptz not null default now(),
|
|
91
|
+
constraint tax_postings_base_has_no_account check (
|
|
92
|
+
posting_type <> 'base' or account_id is null
|
|
93
|
+
),
|
|
94
|
+
constraint tax_postings_tax_has_account check (
|
|
95
|
+
posting_type <> 'tax' or account_id is not null
|
|
96
|
+
),
|
|
97
|
+
foreign key (tax_id, company_id) references taxes(id, company_id) on delete cascade,
|
|
98
|
+
foreign key (account_id, company_id) references accounts(id, company_id)
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
comment on table tax_postings is
|
|
102
|
+
'Where a tax lands: ledger account and VAT-return box, per tax and per document kind.';
|
|
103
|
+
comment on column tax_postings.factor_percent is
|
|
104
|
+
'Accounting share. Positive keeps the base side, negative flips it (self-assessment).';
|
|
105
|
+
comment on column tax_postings.box_factor_percent is
|
|
106
|
+
'Declaration share. Separate from factor_percent so a box always gets the sign the form expects.';
|
|
107
|
+
|
|
108
|
+
create index tax_postings_tax_idx on tax_postings (tax_id, document_kind, posting_type, sequence);
|
|
109
|
+
-- A tax describes one basis, so it has at most one base posting per document
|
|
110
|
+
-- kind. Several would silently double the reported base.
|
|
111
|
+
create unique index tax_postings_one_base_idx
|
|
112
|
+
on tax_postings (tax_id, document_kind) where posting_type = 'base';
|
|
113
|
+
create index tax_postings_box_idx on tax_postings (company_id, declaration_box);
|
|
114
|
+
|
|
115
|
+
create trigger tax_postings_set_updated_at
|
|
116
|
+
before update on tax_postings
|
|
117
|
+
for each row execute function set_updated_at();
|
|
118
|
+
|
|
119
|
+
-- Resolve the rate of a tax at a given date; NULL when it is not in force.
|
|
120
|
+
create or replace function tax_rate_at(p_tax_id uuid, p_date date)
|
|
121
|
+
returns numeric
|
|
122
|
+
language sql
|
|
123
|
+
stable
|
|
124
|
+
as $$
|
|
125
|
+
select t.amount
|
|
126
|
+
from taxes t
|
|
127
|
+
where t.id = p_tax_id
|
|
128
|
+
and t.amount_type = 'percent'
|
|
129
|
+
and p_date >= t.valid_from
|
|
130
|
+
and (t.valid_to is null or p_date <= t.valid_to);
|
|
131
|
+
$$;
|
|
132
|
+
|
|
133
|
+
comment on function tax_rate_at(uuid, date) is 'Percentage in force at a date, NULL when the tax does not apply then.';
|
|
134
|
+
|
|
135
|
+
alter table taxes enable row level security;
|
|
136
|
+
alter table tax_postings enable row level security;
|
|
137
|
+
|
|
138
|
+
create policy taxes_select on taxes
|
|
139
|
+
for select using (is_company_member(company_id));
|
|
140
|
+
create policy taxes_write on taxes
|
|
141
|
+
for all using (can_write_company(company_id)) with check (can_write_company(company_id));
|
|
142
|
+
|
|
143
|
+
create policy tax_postings_select on tax_postings
|
|
144
|
+
for select using (is_company_member(company_id));
|
|
145
|
+
create policy tax_postings_write on tax_postings
|
|
146
|
+
for all using (can_write_company(company_id)) with check (can_write_company(company_id));
|
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
-- Ekwo OS — journal entries and their lines, numbering, period locks.
|
|
2
|
+
|
|
3
|
+
create type entry_state as enum ('draft', 'posted', 'cancelled');
|
|
4
|
+
|
|
5
|
+
create table entries (
|
|
6
|
+
id uuid primary key default gen_random_uuid(),
|
|
7
|
+
company_id uuid not null references companies(id) on delete cascade,
|
|
8
|
+
journal_id uuid not null references journals(id) on delete restrict,
|
|
9
|
+
fiscal_year_id uuid references fiscal_years(id) on delete restrict,
|
|
10
|
+
-- Assigned when the entry is posted. A draft burns no number.
|
|
11
|
+
number text,
|
|
12
|
+
entry_date date not null,
|
|
13
|
+
reference text,
|
|
14
|
+
description text,
|
|
15
|
+
state entry_state not null default 'draft',
|
|
16
|
+
-- Set by post_document(); a document owns at most one entry.
|
|
17
|
+
document_id uuid,
|
|
18
|
+
reversed_entry_id uuid references entries(id) on delete set null,
|
|
19
|
+
currency_code char(3) references currencies(code),
|
|
20
|
+
-- Maintained from entry_lines. Never written by hand.
|
|
21
|
+
total_debit numeric(16, 2) not null default 0,
|
|
22
|
+
total_credit numeric(16, 2) not null default 0,
|
|
23
|
+
is_balanced boolean generated always as (total_debit = total_credit) stored,
|
|
24
|
+
posted_at timestamptz,
|
|
25
|
+
created_at timestamptz not null default now(),
|
|
26
|
+
updated_at timestamptz not null default now(),
|
|
27
|
+
constraint entries_posted_is_balanced check (state <> 'posted' or total_debit = total_credit),
|
|
28
|
+
constraint entries_posted_has_number check (state <> 'posted' or number is not null),
|
|
29
|
+
foreign key (journal_id, company_id) references journals(id, company_id)
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
comment on table entries is 'Journal entries. A document and its entry are two layers joined by a foreign key.';
|
|
33
|
+
comment on column entries.number is 'CODE/YYYY/NNNN, assigned at posting.';
|
|
34
|
+
comment on column entries.total_debit is 'Derived from entry_lines by trigger; the lines are authoritative.';
|
|
35
|
+
|
|
36
|
+
create unique index entries_company_number_idx on entries (company_id, number) where number is not null;
|
|
37
|
+
create unique index entries_id_company_idx on entries (id, company_id);
|
|
38
|
+
create index entries_company_date_idx on entries (company_id, entry_date);
|
|
39
|
+
create index entries_journal_idx on entries (journal_id, entry_date);
|
|
40
|
+
create index entries_fiscal_year_idx on entries (fiscal_year_id);
|
|
41
|
+
create index entries_document_idx on entries (document_id);
|
|
42
|
+
|
|
43
|
+
create trigger entries_set_updated_at
|
|
44
|
+
before update on entries
|
|
45
|
+
for each row execute function set_updated_at();
|
|
46
|
+
|
|
47
|
+
-- ---------------------------------------------------------------------------
|
|
48
|
+
-- entry_lines
|
|
49
|
+
-- ---------------------------------------------------------------------------
|
|
50
|
+
|
|
51
|
+
create table entry_lines (
|
|
52
|
+
id uuid primary key default gen_random_uuid(),
|
|
53
|
+
entry_id uuid not null references entries(id) on delete cascade,
|
|
54
|
+
company_id uuid not null references companies(id) on delete cascade,
|
|
55
|
+
account_id uuid not null references accounts(id) on delete restrict,
|
|
56
|
+
sequence integer not null default 10,
|
|
57
|
+
name text,
|
|
58
|
+
debit numeric(16, 2) not null default 0,
|
|
59
|
+
credit numeric(16, 2) not null default 0,
|
|
60
|
+
-- Authoritative signed amount; debit and credit are its projection.
|
|
61
|
+
balance numeric(16, 2) generated always as (debit - credit) stored,
|
|
62
|
+
currency_code char(3) references currencies(code),
|
|
63
|
+
amount_currency numeric(16, 2),
|
|
64
|
+
contact_id uuid references contacts(id) on delete set null,
|
|
65
|
+
-- Due date of this line. Feeds the aged balance straight from the ledger.
|
|
66
|
+
date_maturity date,
|
|
67
|
+
tax_id uuid references taxes(id) on delete set null,
|
|
68
|
+
-- True when this line IS the tax amount, false when it is a taxed base.
|
|
69
|
+
tax_line boolean not null default false,
|
|
70
|
+
declaration_box text,
|
|
71
|
+
box_amount numeric(16, 2),
|
|
72
|
+
-- Matching. `matching_number` is the human-readable letter, `matched_amount`
|
|
73
|
+
-- the part of this line already reconciled.
|
|
74
|
+
matching_number text,
|
|
75
|
+
matched_amount numeric(16, 2) not null default 0,
|
|
76
|
+
created_at timestamptz not null default now(),
|
|
77
|
+
updated_at timestamptz not null default now(),
|
|
78
|
+
constraint entry_lines_amounts_positive check (debit >= 0 and credit >= 0),
|
|
79
|
+
constraint entry_lines_one_side check (debit = 0 or credit = 0),
|
|
80
|
+
constraint entry_lines_matched_within check (matched_amount >= 0 and matched_amount <= abs(debit - credit)),
|
|
81
|
+
foreign key (entry_id, company_id) references entries(id, company_id) on delete cascade,
|
|
82
|
+
foreign key (account_id, company_id) references accounts(id, company_id),
|
|
83
|
+
foreign key (contact_id, company_id) references contacts(id, company_id),
|
|
84
|
+
foreign key (tax_id, company_id) references taxes(id, company_id)
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
comment on table entry_lines is 'Ledger lines. Amounts are always positive; a reversal flips the side, it never negates.';
|
|
88
|
+
comment on column entry_lines.declaration_box is 'VAT-return box this line feeds, copied from the tax posting that produced it.';
|
|
89
|
+
comment on column entry_lines.box_amount is 'Amount to report in that box, in the sign the form expects.';
|
|
90
|
+
comment on column entry_lines.matching_number is 'Reconciliation letter shared by matched lines. Exported as EcritureLet in the FEC.';
|
|
91
|
+
|
|
92
|
+
create unique index entry_lines_id_company_idx on entry_lines (id, company_id);
|
|
93
|
+
create index entry_lines_entry_idx on entry_lines (entry_id, sequence);
|
|
94
|
+
create index entry_lines_account_idx on entry_lines (account_id);
|
|
95
|
+
create index entry_lines_contact_idx on entry_lines (contact_id);
|
|
96
|
+
create index entry_lines_maturity_idx on entry_lines (company_id, date_maturity);
|
|
97
|
+
create index entry_lines_matching_idx on entry_lines (company_id, matching_number) where matching_number is not null;
|
|
98
|
+
create index entry_lines_box_idx on entry_lines (company_id, declaration_box) where declaration_box is not null;
|
|
99
|
+
|
|
100
|
+
create trigger entry_lines_set_updated_at
|
|
101
|
+
before update on entry_lines
|
|
102
|
+
for each row execute function set_updated_at();
|
|
103
|
+
|
|
104
|
+
-- Keep the entry totals in step with its lines.
|
|
105
|
+
create or replace function entries_refresh_totals()
|
|
106
|
+
returns trigger
|
|
107
|
+
language plpgsql
|
|
108
|
+
as $$
|
|
109
|
+
declare
|
|
110
|
+
v_entry_id uuid := coalesce(new.entry_id, old.entry_id);
|
|
111
|
+
begin
|
|
112
|
+
update entries e
|
|
113
|
+
set total_debit = coalesce(s.debit, 0),
|
|
114
|
+
total_credit = coalesce(s.credit, 0)
|
|
115
|
+
from (
|
|
116
|
+
select sum(l.debit) as debit, sum(l.credit) as credit
|
|
117
|
+
from entry_lines l
|
|
118
|
+
where l.entry_id = v_entry_id
|
|
119
|
+
) s
|
|
120
|
+
where e.id = v_entry_id;
|
|
121
|
+
return null;
|
|
122
|
+
end;
|
|
123
|
+
$$;
|
|
124
|
+
|
|
125
|
+
create trigger entry_lines_refresh_totals
|
|
126
|
+
after insert or update of debit, credit, entry_id or delete on entry_lines
|
|
127
|
+
for each row execute function entries_refresh_totals();
|
|
128
|
+
|
|
129
|
+
-- ---------------------------------------------------------------------------
|
|
130
|
+
-- Numbering
|
|
131
|
+
-- ---------------------------------------------------------------------------
|
|
132
|
+
|
|
133
|
+
create or replace function next_entry_number(p_journal_id uuid, p_date date)
|
|
134
|
+
returns text
|
|
135
|
+
language plpgsql
|
|
136
|
+
as $$
|
|
137
|
+
declare
|
|
138
|
+
v_code text;
|
|
139
|
+
v_year smallint := extract(year from p_date)::smallint;
|
|
140
|
+
v_number integer;
|
|
141
|
+
begin
|
|
142
|
+
select j.code into v_code from journals j where j.id = p_journal_id;
|
|
143
|
+
if v_code is null then
|
|
144
|
+
raise exception 'unknown_journal: journal % does not exist', p_journal_id;
|
|
145
|
+
end if;
|
|
146
|
+
|
|
147
|
+
insert into journal_sequences (journal_id, year, last_number)
|
|
148
|
+
values (p_journal_id, v_year, 1)
|
|
149
|
+
on conflict (journal_id, year)
|
|
150
|
+
do update set last_number = journal_sequences.last_number + 1
|
|
151
|
+
returning last_number into v_number;
|
|
152
|
+
|
|
153
|
+
return v_code || '/' || v_year::text || '/' || lpad(v_number::text, 4, '0');
|
|
154
|
+
end;
|
|
155
|
+
$$;
|
|
156
|
+
|
|
157
|
+
comment on function next_entry_number(uuid, date) is
|
|
158
|
+
'Next number for a journal and year, as CODE/YYYY/NNNN. Atomic: the counter row is locked, not the journal.';
|
|
159
|
+
|
|
160
|
+
-- ---------------------------------------------------------------------------
|
|
161
|
+
-- Period locks
|
|
162
|
+
-- ---------------------------------------------------------------------------
|
|
163
|
+
|
|
164
|
+
create or replace function assert_period_open(
|
|
165
|
+
p_company_id uuid,
|
|
166
|
+
p_date date,
|
|
167
|
+
p_is_tax boolean default false
|
|
168
|
+
)
|
|
169
|
+
returns void
|
|
170
|
+
language plpgsql
|
|
171
|
+
stable
|
|
172
|
+
as $$
|
|
173
|
+
declare
|
|
174
|
+
v_lock date;
|
|
175
|
+
v_tax_lock date;
|
|
176
|
+
v_closed boolean;
|
|
177
|
+
begin
|
|
178
|
+
select lock_date, tax_lock_date into v_lock, v_tax_lock
|
|
179
|
+
from companies where id = p_company_id;
|
|
180
|
+
|
|
181
|
+
if v_lock is not null and p_date <= v_lock then
|
|
182
|
+
raise exception 'period_locked: % is on or before the accounting lock date %', p_date, v_lock
|
|
183
|
+
using errcode = '55006';
|
|
184
|
+
end if;
|
|
185
|
+
|
|
186
|
+
if p_is_tax and v_tax_lock is not null and p_date <= v_tax_lock then
|
|
187
|
+
raise exception 'tax_period_locked: % is on or before the tax lock date %', p_date, v_tax_lock
|
|
188
|
+
using errcode = '55006';
|
|
189
|
+
end if;
|
|
190
|
+
|
|
191
|
+
select f.is_closed into v_closed
|
|
192
|
+
from fiscal_years f
|
|
193
|
+
where f.company_id = p_company_id
|
|
194
|
+
and p_date between f.start_date and f.end_date;
|
|
195
|
+
|
|
196
|
+
if v_closed then
|
|
197
|
+
raise exception 'fiscal_year_closed: % falls in a closed fiscal year', p_date
|
|
198
|
+
using errcode = '55006';
|
|
199
|
+
end if;
|
|
200
|
+
end;
|
|
201
|
+
$$;
|
|
202
|
+
|
|
203
|
+
comment on function assert_period_open(uuid, date, boolean) is
|
|
204
|
+
'Raises when a date is protected by a lock date or a closed fiscal year.';
|
|
205
|
+
|
|
206
|
+
create or replace function entries_guard_period()
|
|
207
|
+
returns trigger
|
|
208
|
+
language plpgsql
|
|
209
|
+
as $$
|
|
210
|
+
declare
|
|
211
|
+
v_is_tax boolean;
|
|
212
|
+
begin
|
|
213
|
+
if tg_op = 'DELETE' then
|
|
214
|
+
perform assert_period_open(old.company_id, old.entry_date,
|
|
215
|
+
exists (select 1 from entry_lines l where l.entry_id = old.id and l.declaration_box is not null));
|
|
216
|
+
return old;
|
|
217
|
+
end if;
|
|
218
|
+
|
|
219
|
+
v_is_tax := exists (select 1 from entry_lines l where l.entry_id = new.id and l.declaration_box is not null);
|
|
220
|
+
perform assert_period_open(new.company_id, new.entry_date, v_is_tax);
|
|
221
|
+
|
|
222
|
+
if tg_op = 'UPDATE' and old.entry_date <> new.entry_date then
|
|
223
|
+
perform assert_period_open(old.company_id, old.entry_date, v_is_tax);
|
|
224
|
+
end if;
|
|
225
|
+
|
|
226
|
+
return new;
|
|
227
|
+
end;
|
|
228
|
+
$$;
|
|
229
|
+
|
|
230
|
+
create trigger entries_guard_period
|
|
231
|
+
before insert or update or delete on entries
|
|
232
|
+
for each row execute function entries_guard_period();
|
|
233
|
+
|
|
234
|
+
create or replace function entry_lines_guard_period()
|
|
235
|
+
returns trigger
|
|
236
|
+
language plpgsql
|
|
237
|
+
as $$
|
|
238
|
+
declare
|
|
239
|
+
v_row entries%rowtype;
|
|
240
|
+
v_entry uuid := coalesce(new.entry_id, old.entry_id);
|
|
241
|
+
v_is_tax boolean := coalesce(new.declaration_box, old.declaration_box) is not null;
|
|
242
|
+
begin
|
|
243
|
+
-- Matching is not a change to the accounts, so it stays possible after a
|
|
244
|
+
-- period is locked. Everything else is guarded.
|
|
245
|
+
if tg_op = 'UPDATE'
|
|
246
|
+
and new.debit = old.debit
|
|
247
|
+
and new.credit = old.credit
|
|
248
|
+
and new.account_id = old.account_id
|
|
249
|
+
and new.entry_id = old.entry_id
|
|
250
|
+
and coalesce(new.declaration_box, '') = coalesce(old.declaration_box, '')
|
|
251
|
+
and coalesce(new.box_amount, 0) = coalesce(old.box_amount, 0)
|
|
252
|
+
then
|
|
253
|
+
return new;
|
|
254
|
+
end if;
|
|
255
|
+
|
|
256
|
+
select * into v_row from entries where id = v_entry;
|
|
257
|
+
if found then
|
|
258
|
+
perform assert_period_open(v_row.company_id, v_row.entry_date, v_is_tax);
|
|
259
|
+
end if;
|
|
260
|
+
if tg_op = 'DELETE' then
|
|
261
|
+
return old;
|
|
262
|
+
end if;
|
|
263
|
+
return new;
|
|
264
|
+
end;
|
|
265
|
+
$$;
|
|
266
|
+
|
|
267
|
+
create trigger entry_lines_guard_period
|
|
268
|
+
before insert or update or delete on entry_lines
|
|
269
|
+
for each row execute function entry_lines_guard_period();
|
|
270
|
+
|
|
271
|
+
-- ---------------------------------------------------------------------------
|
|
272
|
+
-- Posting an entry
|
|
273
|
+
-- ---------------------------------------------------------------------------
|
|
274
|
+
|
|
275
|
+
create or replace function post_entry(p_entry_id uuid)
|
|
276
|
+
returns entries
|
|
277
|
+
language plpgsql
|
|
278
|
+
as $$
|
|
279
|
+
declare
|
|
280
|
+
v_entry entries%rowtype;
|
|
281
|
+
v_lines integer;
|
|
282
|
+
begin
|
|
283
|
+
select * into v_entry from entries where id = p_entry_id for update;
|
|
284
|
+
if not found then
|
|
285
|
+
raise exception 'unknown_entry: entry % does not exist', p_entry_id;
|
|
286
|
+
end if;
|
|
287
|
+
if v_entry.state = 'posted' then
|
|
288
|
+
return v_entry;
|
|
289
|
+
end if;
|
|
290
|
+
if v_entry.state = 'cancelled' then
|
|
291
|
+
raise exception 'entry_cancelled: entry % cannot be posted', p_entry_id;
|
|
292
|
+
end if;
|
|
293
|
+
|
|
294
|
+
select count(*) into v_lines from entry_lines where entry_id = p_entry_id;
|
|
295
|
+
if v_lines = 0 then
|
|
296
|
+
raise exception 'entry_empty: entry % has no lines', p_entry_id;
|
|
297
|
+
end if;
|
|
298
|
+
|
|
299
|
+
-- Re-read the totals maintained by the line trigger.
|
|
300
|
+
select * into v_entry from entries where id = p_entry_id;
|
|
301
|
+
if v_entry.total_debit <> v_entry.total_credit then
|
|
302
|
+
raise exception 'entry_unbalanced: entry % has debit % and credit %',
|
|
303
|
+
p_entry_id, v_entry.total_debit, v_entry.total_credit;
|
|
304
|
+
end if;
|
|
305
|
+
|
|
306
|
+
perform assert_period_open(v_entry.company_id, v_entry.entry_date, true);
|
|
307
|
+
|
|
308
|
+
update entries
|
|
309
|
+
set number = coalesce(number, next_entry_number(journal_id, entry_date)),
|
|
310
|
+
fiscal_year_id = coalesce(fiscal_year_id, fiscal_year_at(company_id, entry_date)),
|
|
311
|
+
state = 'posted',
|
|
312
|
+
posted_at = now()
|
|
313
|
+
where id = p_entry_id
|
|
314
|
+
returning * into v_entry;
|
|
315
|
+
|
|
316
|
+
return v_entry;
|
|
317
|
+
end;
|
|
318
|
+
$$;
|
|
319
|
+
|
|
320
|
+
comment on function post_entry(uuid) is
|
|
321
|
+
'Validates, numbers and posts an entry. Raises rather than warning: a swallowed error is a missing entry.';
|
|
322
|
+
|
|
323
|
+
-- ---------------------------------------------------------------------------
|
|
324
|
+
-- Row level security
|
|
325
|
+
-- ---------------------------------------------------------------------------
|
|
326
|
+
|
|
327
|
+
alter table entries enable row level security;
|
|
328
|
+
alter table entry_lines enable row level security;
|
|
329
|
+
|
|
330
|
+
create policy entries_select on entries
|
|
331
|
+
for select using (is_company_member(company_id));
|
|
332
|
+
create policy entries_write on entries
|
|
333
|
+
for all using (can_write_company(company_id)) with check (can_write_company(company_id));
|
|
334
|
+
|
|
335
|
+
create policy entry_lines_select on entry_lines
|
|
336
|
+
for select using (is_company_member(company_id));
|
|
337
|
+
create policy entry_lines_write on entry_lines
|
|
338
|
+
for all using (can_write_company(company_id)) with check (can_write_company(company_id));
|