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