ekwo-os 0.12.0 → 0.12.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.
Files changed (153) hide show
  1. package/README.md +1 -1
  2. package/dist/assets/expected-objects.json +55 -2
  3. package/dist/assets/migrations/20261010160429_an_invoice_wears_the_colour_of_its_company.sql +38 -0
  4. package/dist/assets/migrations/20261010203452_a_filing_file_is_read_as_a_filing.sql +95 -0
  5. package/dist/assets/migrations/20261011081256_a_balance_sheet_before_the_close.sql +450 -0
  6. package/dist/assets/migrations/20261011082857_schema_version_0_12_1.sql +38 -0
  7. package/dist/assets/seed/100_pack_uy.sql +2 -2
  8. package/dist/assets/seed/101_pack_ec.sql +16 -4
  9. package/dist/assets/seed/102_pack_bo.sql +2 -2
  10. package/dist/assets/seed/103_pack_py.sql +31 -19
  11. package/dist/assets/seed/104_pack_do.sql +2 -2
  12. package/dist/assets/seed/105_pack_cr.sql +12 -4
  13. package/dist/assets/seed/106_pack_gt.sql +2 -2
  14. package/dist/assets/seed/107_pack_pa.sql +10 -2
  15. package/dist/assets/seed/108_pack_in.sql +1 -1
  16. package/dist/assets/seed/109_pack_cn.sql +1 -1
  17. package/dist/assets/seed/10_pack_be.sql +1 -1
  18. package/dist/assets/seed/110_pack_ge.sql +16 -6
  19. package/dist/assets/seed/111_pack_md.sql +1 -1
  20. package/dist/assets/seed/112_pack_rs.sql +1 -1
  21. package/dist/assets/seed/113_pack_ba.sql +9 -2
  22. package/dist/assets/seed/114_pack_al.sql +1 -1
  23. package/dist/assets/seed/115_pack_mk.sql +16 -4
  24. package/dist/assets/seed/116_pack_me.sql +1 -1
  25. package/dist/assets/seed/117_pack_bh.sql +1 -1
  26. package/dist/assets/seed/118_pack_om.sql +1 -1
  27. package/dist/assets/seed/119_pack_gh.sql +10 -2
  28. package/dist/assets/seed/11_pack_fr.sql +1 -1
  29. package/dist/assets/seed/120_pack_tz.sql +1 -1
  30. package/dist/assets/seed/121_pack_ug.sql +1 -1
  31. package/dist/assets/seed/122_pack_rw.sql +1 -1
  32. package/dist/assets/seed/123_pack_xk.sql +1 -1
  33. package/dist/assets/seed/124_pack_kz.sql +11 -2
  34. package/dist/assets/seed/125_pack_pk.sql +16 -2
  35. package/dist/assets/seed/126_pack_bd.sql +1 -1
  36. package/dist/assets/seed/127_pack_lk.sql +2 -2
  37. package/dist/assets/seed/128_pack_am.sql +12 -3
  38. package/dist/assets/seed/129_pack_az.sql +17 -5
  39. package/dist/assets/seed/12_pack_lu.sql +1 -1
  40. package/dist/assets/seed/130_pack_hn.sql +2 -2
  41. package/dist/assets/seed/131_pack_sv.sql +14 -4
  42. package/dist/assets/seed/132_pack_ni.sql +13 -3
  43. package/dist/assets/seed/133_pack_et.sql +12 -3
  44. package/dist/assets/seed/134_pack_mu.sql +1 -1
  45. package/dist/assets/seed/135_pack_mz.sql +1 -1
  46. package/dist/assets/seed/136_pack_ao.sql +1 -1
  47. package/dist/assets/seed/137_pack_zm.sql +1 -1
  48. package/dist/assets/seed/138_pack_bm.sql +1 -1
  49. package/dist/assets/seed/139_pack_ky.sql +1 -1
  50. package/dist/assets/seed/13_pack_ee.sql +1 -1
  51. package/dist/assets/seed/140_pack_vg.sql +1 -1
  52. package/dist/assets/seed/141_pack_gg.sql +1 -1
  53. package/dist/assets/seed/142_pack_qa.sql +1 -1
  54. package/dist/assets/seed/143_pack_kw.sql +1 -1
  55. package/dist/assets/seed/144_pack_bn.sql +1 -1
  56. package/dist/assets/seed/145_pack_mo.sql +1 -1
  57. package/dist/assets/seed/146_pack_je.sql +1 -1
  58. package/dist/assets/seed/147_pack_zw.sql +1 -1
  59. package/dist/assets/seed/14_pack_gb.sql +1 -1
  60. package/dist/assets/seed/15_pack_us.sql +4 -2
  61. package/dist/assets/seed/16_pack_ie.sql +1 -1
  62. package/dist/assets/seed/17_pack_nl.sql +1 -1
  63. package/dist/assets/seed/18_pack_de.sql +1 -1
  64. package/dist/assets/seed/19_pack_es.sql +1 -1
  65. package/dist/assets/seed/20_pack_sn.sql +1 -1
  66. package/dist/assets/seed/22_pack_bj.sql +10 -4
  67. package/dist/assets/seed/23_pack_bf.sql +1 -1
  68. package/dist/assets/seed/24_pack_cm.sql +9 -3
  69. package/dist/assets/seed/25_pack_cf.sql +9 -3
  70. package/dist/assets/seed/26_pack_km.sql +1 -1
  71. package/dist/assets/seed/27_pack_cg.sql +11 -3
  72. package/dist/assets/seed/28_pack_ga.sql +1 -1
  73. package/dist/assets/seed/29_pack_gn.sql +9 -3
  74. package/dist/assets/seed/30_pack_gw.sql +1 -1
  75. package/dist/assets/seed/31_pack_gq.sql +1 -1
  76. package/dist/assets/seed/32_pack_ml.sql +9 -3
  77. package/dist/assets/seed/33_pack_ne.sql +9 -3
  78. package/dist/assets/seed/34_pack_cd.sql +9 -3
  79. package/dist/assets/seed/35_pack_td.sql +11 -3
  80. package/dist/assets/seed/36_pack_tg.sql +1 -1
  81. package/dist/assets/seed/37_pack_it.sql +1 -1
  82. package/dist/assets/seed/38_pack_id.sql +1 -1
  83. package/dist/assets/seed/39_pack_my.sql +3 -3
  84. package/dist/assets/seed/40_pack_au.sql +1 -1
  85. package/dist/assets/seed/41_pack_nz.sql +1 -1
  86. package/dist/assets/seed/42_pack_mx.sql +9 -2
  87. package/dist/assets/seed/43_pack_pt.sql +24 -10
  88. package/dist/assets/seed/44_pack_ph.sql +1 -1
  89. package/dist/assets/seed/45_pack_ar.sql +1 -1
  90. package/dist/assets/seed/46_pack_cl.sql +1 -1
  91. package/dist/assets/seed/47_pack_co.sql +13 -3
  92. package/dist/assets/seed/48_pack_pe.sql +13 -2
  93. package/dist/assets/seed/49_pack_ng.sql +13 -3
  94. package/dist/assets/seed/50_pack_sg.sql +1 -1
  95. package/dist/assets/seed/51_pack_jp.sql +1 -1
  96. package/dist/assets/seed/52_pack_hk.sql +1 -1
  97. package/dist/assets/seed/53_pack_tw.sql +9 -2
  98. package/dist/assets/seed/54_pack_kr.sql +20 -10
  99. package/dist/assets/seed/55_pack_vn.sql +11 -2
  100. package/dist/assets/seed/56_pack_th.sql +1 -1
  101. package/dist/assets/seed/57_pack_ua.sql +19 -6
  102. package/dist/assets/seed/58_pack_ca.sql +1 -1
  103. package/dist/assets/seed/60_pack_ae.sql +1 -1
  104. package/dist/assets/seed/61_pack_se.sql +1 -1
  105. package/dist/assets/seed/62_pack_ch.sql +1 -1
  106. package/dist/assets/seed/63_pack_at.sql +1 -1
  107. package/dist/assets/seed/64_pack_pl.sql +12 -12
  108. package/dist/assets/seed/65_pack_dk.sql +1 -1
  109. package/dist/assets/seed/66_pack_no.sql +24 -22
  110. package/dist/assets/seed/67_pack_fi.sql +1 -1
  111. package/dist/assets/seed/68_pack_cz.sql +22 -4
  112. package/dist/assets/seed/69_pack_sk.sql +1 -1
  113. package/dist/assets/seed/70_pack_hu.sql +1 -1
  114. package/dist/assets/seed/71_pack_sa.sql +1 -1
  115. package/dist/assets/seed/72_pack_ro.sql +1 -1
  116. package/dist/assets/seed/73_pack_bg.sql +6 -6
  117. package/dist/assets/seed/74_pack_hr.sql +15 -15
  118. package/dist/assets/seed/75_pack_si.sql +1 -1
  119. package/dist/assets/seed/76_pack_gr.sql +22 -4
  120. package/dist/assets/seed/77_pack_lt.sql +1 -1
  121. package/dist/assets/seed/78_pack_lv.sql +22 -4
  122. package/dist/assets/seed/79_pack_cy.sql +1 -1
  123. package/dist/assets/seed/80_pack_mt.sql +1 -1
  124. package/dist/assets/seed/81_pack_is.sql +1 -1
  125. package/dist/assets/seed/82_pack_tr.sql +1 -1
  126. package/dist/assets/seed/83_pack_eg.sql +1 -1
  127. package/dist/assets/seed/84_pack_ma.sql +24 -10
  128. package/dist/assets/seed/85_pack_tn.sql +1 -1
  129. package/dist/assets/seed/86_pack_dz.sql +11 -4
  130. package/dist/assets/seed/87_pack_il.sql +1 -1
  131. package/dist/assets/seed/88_pack_za.sql +1 -1
  132. package/dist/assets/seed/89_pack_ke.sql +1 -1
  133. package/dist/assets/seed/modules/corporate_tax/15_pack_us.sql +1 -1
  134. package/dist/assets/seed/modules/corporate_tax/42_pack_mx.sql +1 -1
  135. package/dist/assets/seed/modules/corporate_tax/49_pack_ng.sql +1 -1
  136. package/dist/assets/seed/modules/fixed_assets/15_pack_us.sql +1 -1
  137. package/dist/assets/seed/modules/fixed_assets/42_pack_mx.sql +1 -1
  138. package/dist/assets/seed/modules/fixed_assets/49_pack_ng.sql +1 -1
  139. package/dist/cli.js +1 -1
  140. package/dist/cli.js.map +1 -1
  141. package/dist/commands/pack.js +4 -0
  142. package/dist/commands/pack.js.map +1 -1
  143. package/dist/pack/describe.d.ts +5 -0
  144. package/dist/pack/describe.d.ts.map +1 -1
  145. package/dist/pack/describe.js +4 -0
  146. package/dist/pack/describe.js.map +1 -1
  147. package/dist/pack/read.d.ts +6 -0
  148. package/dist/pack/read.d.ts.map +1 -1
  149. package/dist/pack/read.js +65 -0
  150. package/dist/pack/read.js.map +1 -1
  151. package/dist/schema.d.ts +1 -1
  152. package/dist/schema.js +1 -1
  153. package/package.json +3 -3
package/README.md CHANGED
@@ -517,7 +517,7 @@ exactly six fields:
517
517
  "organization": "My Organisation",
518
518
  "country": "<cc>",
519
519
  "edition": "community",
520
- "schema_version": "0.12.0",
520
+ "schema_version": "0.12.1",
521
521
  "contact_email": "you@example.com"
522
522
  }
523
523
  ```
@@ -1,6 +1,6 @@
1
1
  {
2
- "schemaVersion": "0.12.0",
3
- "migration": "20261010181201",
2
+ "schemaVersion": "0.12.1",
3
+ "migration": "20261011082857",
4
4
  "socle": {
5
5
  "schema": "public",
6
6
  "tables": [
@@ -793,6 +793,14 @@
793
793
  "name": "id",
794
794
  "type": "uuid"
795
795
  },
796
+ {
797
+ "name": "invoice_accent_color",
798
+ "type": "text"
799
+ },
800
+ {
801
+ "name": "invoice_logo_position",
802
+ "type": "text"
803
+ },
796
804
  {
797
805
  "name": "language",
798
806
  "type": "character(2)"
@@ -3905,6 +3913,10 @@
3905
3913
  "name": "assert_writes_into_known_company",
3906
3914
  "arguments": "p_company_id uuid"
3907
3915
  },
3916
+ {
3917
+ "name": "attachment_is_filing_deposit_file",
3918
+ "arguments": "p_attachment_id uuid"
3919
+ },
3908
3920
  {
3909
3921
  "name": "audit_changes",
3910
3922
  "arguments": ""
@@ -4713,6 +4725,10 @@
4713
4725
  "name": "statement_account_matches",
4714
4726
  "arguments": "p_company_id uuid, p_statement_code text, p_from date, p_to date"
4715
4727
  },
4728
+ {
4729
+ "name": "statement_rule_catches",
4730
+ "arguments": "p_rule statement_line_rules, p_code text, p_account_type account_type, p_balance numeric"
4731
+ },
4716
4732
  {
4717
4733
  "name": "suggest_combination",
4718
4734
  "arguments": "p_transaction_id uuid"
@@ -4832,6 +4848,10 @@
4832
4848
  {
4833
4849
  "name": "version_at_least",
4834
4850
  "arguments": "p_version text, p_floor text"
4851
+ },
4852
+ {
4853
+ "name": "year_result_account",
4854
+ "arguments": "p_company_id uuid, p_balance numeric"
4835
4855
  }
4836
4856
  ],
4837
4857
  "policies": [
@@ -7312,6 +7332,17 @@
7312
7332
  "authenticated": [],
7313
7333
  "service_role": []
7314
7334
  },
7335
+ {
7336
+ "name": "attachment_is_filing_deposit_file",
7337
+ "arguments": "p_attachment_id uuid",
7338
+ "anon": [],
7339
+ "authenticated": [
7340
+ "execute"
7341
+ ],
7342
+ "service_role": [
7343
+ "execute"
7344
+ ]
7345
+ },
7315
7346
  {
7316
7347
  "name": "audit_changes",
7317
7348
  "arguments": "",
@@ -9412,6 +9443,17 @@
9412
9443
  "execute"
9413
9444
  ]
9414
9445
  },
9446
+ {
9447
+ "name": "statement_rule_catches",
9448
+ "arguments": "p_rule statement_line_rules, p_code text, p_account_type account_type, p_balance numeric",
9449
+ "anon": [],
9450
+ "authenticated": [
9451
+ "execute"
9452
+ ],
9453
+ "service_role": [
9454
+ "execute"
9455
+ ]
9456
+ },
9415
9457
  {
9416
9458
  "name": "suggest_combination",
9417
9459
  "arguments": "p_transaction_id uuid",
@@ -9721,6 +9763,17 @@
9721
9763
  "service_role": [
9722
9764
  "execute"
9723
9765
  ]
9766
+ },
9767
+ {
9768
+ "name": "year_result_account",
9769
+ "arguments": "p_company_id uuid, p_balance numeric",
9770
+ "anon": [],
9771
+ "authenticated": [
9772
+ "execute"
9773
+ ],
9774
+ "service_role": [
9775
+ "execute"
9776
+ ]
9724
9777
  }
9725
9778
  ],
9726
9779
  "defaultPrivileges": []
@@ -0,0 +1,38 @@
1
+ -- Ekwo OS — an invoice wears the colour of the company that sends it.
2
+ --
3
+ -- `@ekwo-ai/invoice-pdf` prints every invoice in one layout and takes a small
4
+ -- theme: an accent colour and the side of the logo. Until now only the caller
5
+ -- could hand it one, so the PDF of `ekwo doc pdf`, of the MCP tool
6
+ -- `render_invoice_pdf` and of any other client came out in the brick's default
7
+ -- whoever had sent it. Which colour a company prints in is a fact about that
8
+ -- company, the same for every surface that renders its invoices; it belongs
9
+ -- beside its logo, on `companies`.
10
+ --
11
+ -- **Two columns, both nullable.** Null is the brick's default, which is the
12
+ -- answer for every company that exists today and needs no backfill. The
13
+ -- typeface of the theme stays out: it is a file, and the core keeps none.
14
+ --
15
+ -- **The same constraints the brick applies.** A colour is `#rrggbb` and a side
16
+ -- is `left` or `right`; anything else would be stored here and refused at the
17
+ -- first rendering, so it is refused at the write instead.
18
+ --
19
+ -- **Who may write it** is who may write the company: `companies_update`
20
+ -- judges the row, `company.write`. No grant changes — the table is already
21
+ -- granted, and a column added to it is covered by that grant.
22
+
23
+ alter table companies
24
+ add column if not exists invoice_accent_color text,
25
+ add column if not exists invoice_logo_position text;
26
+
27
+ alter table companies
28
+ add constraint companies_invoice_accent_color_hex
29
+ check (invoice_accent_color ~ '^#[0-9A-Fa-f]{6}$');
30
+
31
+ alter table companies
32
+ add constraint companies_invoice_logo_position_side
33
+ check (invoice_logo_position in ('left', 'right'));
34
+
35
+ comment on column companies.invoice_accent_color is
36
+ 'The accent colour of this company''s invoice PDF, written #rrggbb: the title, the rules and the bands of the layout. Null is the default of @ekwo-ai/invoice-pdf.';
37
+ comment on column companies.invoice_logo_position is
38
+ 'The side of this company''s invoice PDF its logo is printed on: left or right. Null is the default of @ekwo-ai/invoice-pdf (left).';
@@ -0,0 +1,95 @@
1
+ -- Ekwo OS — the file of a declaration is read as a declaration.
2
+ --
3
+ -- `filings.read` was granted apart from `documents.read` on purpose: what a
4
+ -- company declared is not the same secret as what it books
5
+ -- (`20260917150000`), and the deposits that record each send ask it
6
+ -- (`20260918110000`). The two files of a deposit — what was sent, and the
7
+ -- receipt that came back — are rows of `attachments`, and every row of
8
+ -- `attachments` was read through `documents.read` and written through
9
+ -- `documents.write` (`20260913083216`). So a member whose `filings.read` was
10
+ -- withdrawn and who kept `documents.read` saw no deposit, and still read the
11
+ -- declaration that went and the acknowledgement of the administration.
12
+ -- Decision 0039 left it as an open item; this closes it.
13
+ --
14
+ -- **Which files.** Two kinds, and either is enough:
15
+ --
16
+ -- - an attachment **of a declaration** (`entity_type = 'tax_filing'`), which
17
+ -- is where the two files of a deposit are kept, from the moment they are
18
+ -- uploaded and before the deposit names them;
19
+ -- - an attachment **a deposit names**, as `sent_file_id` or
20
+ -- `acknowledgement_id`, wherever it was pinned: the trigger of
21
+ -- `20261007113412` keeps it in the declaration's company and does not
22
+ -- ask its `entity_type`.
23
+ --
24
+ -- Such a file is read with `filings.read` and written — uploaded, changed,
25
+ -- moved, deleted — with `filings.write`, the capability that writes deposits.
26
+ -- Every other attachment keeps `documents.read` and `documents.write`. The
27
+ -- two policies of a client handing a piece over (`attachments_deposit`,
28
+ -- `attachments_select_own_deposit`, `20260918113807`) are untouched: they
29
+ -- only ever reach a piece on the company itself, or one the caller filed.
30
+ --
31
+ -- **Why a definer function asks about the deposit.** A policy reads other
32
+ -- tables under the caller's own policies, and the deposits ask
33
+ -- `filings.read`: an `exists` written in the policy would find no deposit for
34
+ -- precisely the member this is about, and let the file through as an
35
+ -- ordinary one. `attachment_is_filing_deposit_file()` looks past the
36
+ -- policies of `tax_filing_deposits`, answers about one attachment and nothing
37
+ -- else, and is two probes of the indexes `20260918110000` put on the two
38
+ -- columns. On a shared installation it answers only about a company the
39
+ -- caller may know of (`may_know_of_company()`, decision 0065): an id of
40
+ -- another tenant's file gets the answer an id of nobody gets. The capabilities are compared the way `20260918141627` compares
41
+ -- them — a sub-select run once per statement — and `attachments` is a table
42
+ -- read file by file, never walked by a report.
43
+
44
+ create or replace function attachment_is_filing_deposit_file(p_attachment_id uuid)
45
+ returns boolean
46
+ language sql
47
+ stable
48
+ security definer
49
+ set search_path = public, pg_temp
50
+ as $$
51
+ select exists (select 1 from tax_filing_deposits d join tax_filings f on f.id = d.filing_id
52
+ where d.sent_file_id = p_attachment_id and may_know_of_company(f.company_id))
53
+ or exists (select 1 from tax_filing_deposits d join tax_filings f on f.id = d.filing_id
54
+ where d.acknowledgement_id = p_attachment_id and may_know_of_company(f.company_id));
55
+ $$;
56
+
57
+ comment on function attachment_is_filing_deposit_file(uuid) is
58
+ 'Whether a deposit of a declaration names this attachment as the file that was sent or as the receipt. Definer, because the policy of attachments asks it for callers who may not read the deposits — which is the case it exists for; it answers about one id and nothing else, and about a company the caller may not know of as about nobody (decision 0065).';
59
+
60
+ revoke execute on function attachment_is_filing_deposit_file(uuid) from public, anon;
61
+ grant execute on function attachment_is_filing_deposit_file(uuid) to authenticated, service_role;
62
+
63
+ drop policy attachments_select on attachments;
64
+ create policy attachments_select on attachments
65
+ for select using (
66
+ case
67
+ when entity_type = 'tax_filing' or attachment_is_filing_deposit_file(id)
68
+ then company_id = any ((select companies_with_capability('filings.read'))::uuid[])
69
+ else company_id = any ((select companies_with_capability('documents.read'))::uuid[])
70
+ end
71
+ );
72
+
73
+ comment on policy attachments_select on attachments is
74
+ 'documents.read, except for the files of a declaration — attached to a tax_filing, or named by a deposit as what was sent or the receipt — which are proof of filing and read with filings.read, like the deposits themselves.';
75
+
76
+ drop policy attachments_write on attachments;
77
+ create policy attachments_write on attachments
78
+ for all using (
79
+ case
80
+ when entity_type = 'tax_filing' or attachment_is_filing_deposit_file(id)
81
+ then company_id = any ((select companies_with_capability('filings.write'))::uuid[])
82
+ else company_id = any ((select companies_with_capability('documents.write'))::uuid[])
83
+ end
84
+ )
85
+ -- A check is asked once per row written, as `20260918141627` leaves it.
86
+ with check (
87
+ case
88
+ when entity_type = 'tax_filing' or attachment_is_filing_deposit_file(id)
89
+ then has_capability(company_id, 'filings.write')
90
+ else has_capability(company_id, 'documents.write')
91
+ end
92
+ );
93
+
94
+ comment on policy attachments_write on attachments is
95
+ 'documents.write, except for the files of a declaration — attached to a tax_filing, or named by a deposit — which are written with filings.write, the capability that records a deposit. Moving a file onto a declaration needs both: the old row is asked documents.write, the new one filings.write.';