shutro-erp 0.2.1 → 0.3.0

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 (229) hide show
  1. package/README.md +17 -10
  2. package/dist/account_portal/.kosh/bindings.d.ts +22 -0
  3. package/dist/account_portal/.kosh/bindings.js +15 -0
  4. package/dist/account_portal/.kosh/schema.d.ts +1350 -0
  5. package/dist/account_portal/index.d.ts +3 -0
  6. package/dist/account_portal/index.js +73 -0
  7. package/dist/account_portal/module.d.ts +5983 -0
  8. package/dist/account_portal/module.js +18 -0
  9. package/dist/accounting/.kosh/bindings.js +1 -1
  10. package/dist/accounting/.kosh/schema.d.ts +142 -9
  11. package/dist/accounting/chart.d.ts +40 -8
  12. package/dist/accounting/chart.js +124 -30
  13. package/dist/accounting/closing.d.ts +6 -1
  14. package/dist/accounting/closing.js +5 -1
  15. package/dist/accounting/demo.js +6 -5
  16. package/dist/accounting/index.d.ts +3 -3
  17. package/dist/accounting/index.js +200 -23
  18. package/dist/accounting/module.d.ts +3326 -1086
  19. package/dist/accounting/module.js +408 -66
  20. package/dist/accounting/payments.d.ts +25 -0
  21. package/dist/accounting/payments.js +96 -4
  22. package/dist/accounting/web/RegisterPayment.d.ts +3 -2
  23. package/dist/accounting/web/RegisterPayment.js +39 -6
  24. package/dist/accounting/web/SettingsPage.js +5 -1
  25. package/dist/accounting/web/messages.js +10 -0
  26. package/dist/cli/init.js +172 -48
  27. package/dist/cli/launch.d.ts +16 -0
  28. package/dist/cli/launch.js +138 -0
  29. package/dist/cli/prompt.d.ts +35 -0
  30. package/dist/cli/prompt.js +46 -0
  31. package/dist/cli/templates.d.ts +11 -3
  32. package/dist/cli/templates.js +32 -7
  33. package/dist/cli/tui.d.ts +7 -0
  34. package/dist/cli/tui.js +254 -0
  35. package/dist/cli/ui.d.ts +25 -5
  36. package/dist/cli/ui.js +49 -9
  37. package/dist/contacts/.kosh/bindings.js +1 -1
  38. package/dist/contacts/.kosh/schema.d.ts +3 -1
  39. package/dist/contacts/index.js +24 -1
  40. package/dist/contacts/module.d.ts +42 -0
  41. package/dist/contacts/module.js +3 -1
  42. package/dist/import/convert.d.ts +55 -0
  43. package/dist/import/convert.js +224 -0
  44. package/dist/import/csv.d.ts +28 -0
  45. package/dist/import/csv.js +115 -0
  46. package/dist/import/index.d.ts +33 -0
  47. package/dist/import/index.js +60 -0
  48. package/dist/import/mapping.d.ts +15 -0
  49. package/dist/import/mapping.js +33 -0
  50. package/dist/import/match.d.ts +24 -0
  51. package/dist/import/match.js +60 -0
  52. package/dist/import/models.d.ts +2 -0
  53. package/dist/import/models.js +102 -0
  54. package/dist/import/routes.d.ts +13 -0
  55. package/dist/import/routes.js +392 -0
  56. package/dist/import/run.d.ts +131 -0
  57. package/dist/import/run.js +568 -0
  58. package/dist/import/service.d.ts +153 -0
  59. package/dist/import/service.js +367 -0
  60. package/dist/import/web/ImportButton.d.ts +7 -0
  61. package/dist/import/web/ImportButton.js +31 -0
  62. package/dist/import/web/ImportWizard.d.ts +75 -0
  63. package/dist/import/web/ImportWizard.js +217 -0
  64. package/dist/import/web/index.d.ts +13 -0
  65. package/dist/import/web/index.js +18 -0
  66. package/dist/import/web/messages.d.ts +2 -0
  67. package/dist/import/web/messages.js +139 -0
  68. package/dist/import/worker.d.ts +3 -0
  69. package/dist/import/worker.js +52 -0
  70. package/dist/import/xlsx.d.ts +20 -0
  71. package/dist/import/xlsx.js +192 -0
  72. package/dist/l10n_bd/.kosh/bindings.d.ts +22 -0
  73. package/dist/l10n_bd/.kosh/bindings.js +15 -0
  74. package/dist/l10n_bd/.kosh/schema.d.ts +1281 -0
  75. package/dist/l10n_bd/documents.d.ts +8 -0
  76. package/dist/l10n_bd/documents.js +183 -0
  77. package/dist/l10n_bd/index.d.ts +8 -0
  78. package/dist/l10n_bd/index.js +156 -0
  79. package/dist/l10n_bd/module.d.ts +5705 -0
  80. package/dist/l10n_bd/module.js +163 -0
  81. package/dist/l10n_bd/mushak.d.ts +67 -0
  82. package/dist/l10n_bd/mushak.js +139 -0
  83. package/dist/l10n_bd/routes.d.ts +3 -0
  84. package/dist/l10n_bd/routes.js +205 -0
  85. package/dist/l10n_bd/web/MushakPage.d.ts +7 -0
  86. package/dist/l10n_bd/web/MushakPage.js +53 -0
  87. package/dist/l10n_bd/web/index.d.ts +13 -0
  88. package/dist/l10n_bd/web/index.js +18 -0
  89. package/dist/l10n_bd/web/messages.d.ts +2 -0
  90. package/dist/l10n_bd/web/messages.js +101 -0
  91. package/dist/l10n_in/.kosh/bindings.d.ts +22 -0
  92. package/dist/l10n_in/.kosh/bindings.js +15 -0
  93. package/dist/l10n_in/.kosh/schema.d.ts +1343 -0
  94. package/dist/l10n_in/documents.d.ts +8 -0
  95. package/dist/l10n_in/documents.js +114 -0
  96. package/dist/l10n_in/einvoice.d.ts +253 -0
  97. package/dist/l10n_in/einvoice.js +485 -0
  98. package/dist/l10n_in/gstr.d.ts +109 -0
  99. package/dist/l10n_in/gstr.js +430 -0
  100. package/dist/l10n_in/index.d.ts +20 -0
  101. package/dist/l10n_in/index.js +232 -0
  102. package/dist/l10n_in/module.d.ts +7823 -0
  103. package/dist/l10n_in/module.js +427 -0
  104. package/dist/l10n_in/routes-einvoice.d.ts +15 -0
  105. package/dist/l10n_in/routes-einvoice.js +124 -0
  106. package/dist/l10n_in/routes.d.ts +17 -0
  107. package/dist/l10n_in/routes.js +282 -0
  108. package/dist/l10n_in/web/EInvoicePanel.d.ts +8 -0
  109. package/dist/l10n_in/web/EInvoicePanel.js +63 -0
  110. package/dist/l10n_in/web/GstPage.d.ts +7 -0
  111. package/dist/l10n_in/web/GstPage.js +57 -0
  112. package/dist/l10n_in/web/GstSettings.d.ts +10 -0
  113. package/dist/l10n_in/web/GstSettings.js +36 -0
  114. package/dist/l10n_in/web/index.d.ts +15 -0
  115. package/dist/l10n_in/web/index.js +22 -0
  116. package/dist/l10n_in/web/messages.d.ts +2 -0
  117. package/dist/l10n_in/web/messages.js +166 -0
  118. package/dist/modules-sdk/demo.d.ts +2 -0
  119. package/dist/modules-sdk/demo.js +7 -3
  120. package/dist/modules-sdk/index.d.ts +2 -2
  121. package/dist/modules-sdk/index.js +1 -1
  122. package/dist/modules-sdk/manifest.d.ts +132 -0
  123. package/dist/modules-sdk/manifest.js +22 -0
  124. package/dist/notify/inbox.js +21 -0
  125. package/dist/notify/messages.js +4 -0
  126. package/dist/notify/models.d.ts +1 -1
  127. package/dist/notify/models.js +2 -0
  128. package/dist/notify/web/messages.js +4 -0
  129. package/dist/portal/.kosh/bindings.d.ts +22 -0
  130. package/dist/portal/.kosh/bindings.js +15 -0
  131. package/dist/portal/.kosh/schema.d.ts +346 -0
  132. package/dist/portal/announce.d.ts +16 -0
  133. package/dist/portal/announce.js +117 -0
  134. package/dist/portal/documents.d.ts +17 -0
  135. package/dist/portal/documents.js +61 -0
  136. package/dist/portal/index.d.ts +20 -0
  137. package/dist/portal/index.js +65 -0
  138. package/dist/portal/module.d.ts +1405 -0
  139. package/dist/portal/module.js +84 -0
  140. package/dist/portal/routes-documents.d.ts +2 -0
  141. package/dist/portal/routes-documents.js +391 -0
  142. package/dist/portal/routes.d.ts +13 -0
  143. package/dist/portal/routes.js +313 -0
  144. package/dist/portal/rules.d.ts +11 -0
  145. package/dist/portal/rules.js +25 -0
  146. package/dist/portal/web/PortalAccess.d.ts +8 -0
  147. package/dist/portal/web/PortalAccess.js +66 -0
  148. package/dist/portal/web/index.d.ts +12 -0
  149. package/dist/portal/web/index.js +17 -0
  150. package/dist/portal/web/messages.d.ts +2 -0
  151. package/dist/portal/web/messages.js +33 -0
  152. package/dist/product/.kosh/bindings.js +1 -1
  153. package/dist/product/.kosh/schema.d.ts +12 -3
  154. package/dist/product/demo.js +6 -5
  155. package/dist/product/index.d.ts +1 -0
  156. package/dist/product/index.js +17 -4
  157. package/dist/product/module.d.ts +346 -14
  158. package/dist/product/module.js +48 -18
  159. package/dist/product/taxes.d.ts +59 -0
  160. package/dist/product/taxes.js +61 -0
  161. package/dist/project/.kosh/bindings.js +1 -1
  162. package/dist/project/.kosh/schema.d.ts +3 -1
  163. package/dist/project/module.d.ts +20 -0
  164. package/dist/project_portal/.kosh/bindings.d.ts +22 -0
  165. package/dist/project_portal/.kosh/bindings.js +15 -0
  166. package/dist/project_portal/.kosh/schema.d.ts +671 -0
  167. package/dist/project_portal/index.d.ts +9 -0
  168. package/dist/project_portal/index.js +42 -0
  169. package/dist/project_portal/module.d.ts +2142 -0
  170. package/dist/project_portal/module.js +22 -0
  171. package/dist/purchase/.kosh/bindings.js +1 -1
  172. package/dist/purchase/.kosh/schema.d.ts +15 -4
  173. package/dist/purchase/demo.js +3 -3
  174. package/dist/purchase/index.js +1 -1
  175. package/dist/purchase/module.d.ts +232 -8
  176. package/dist/purchase/module.js +51 -9
  177. package/dist/purchase_account/.kosh/bindings.js +1 -1
  178. package/dist/purchase_account/.kosh/schema.d.ts +144 -10
  179. package/dist/purchase_account/module.d.ts +2008 -641
  180. package/dist/purchase_account/module.js +2 -2
  181. package/dist/purchase_portal/.kosh/bindings.d.ts +22 -0
  182. package/dist/purchase_portal/.kosh/bindings.js +15 -0
  183. package/dist/purchase_portal/.kosh/schema.d.ts +822 -0
  184. package/dist/purchase_portal/index.d.ts +9 -0
  185. package/dist/purchase_portal/index.js +53 -0
  186. package/dist/purchase_portal/module.d.ts +2758 -0
  187. package/dist/purchase_portal/module.js +18 -0
  188. package/dist/reporting/documents.js +20 -3
  189. package/dist/reporting/index.d.ts +1 -0
  190. package/dist/reporting/index.js +1 -0
  191. package/dist/reporting/routes-documents.js +9 -2
  192. package/dist/reporting/words.d.ts +11 -0
  193. package/dist/reporting/words.js +229 -0
  194. package/dist/sale_account/.kosh/bindings.js +1 -1
  195. package/dist/sale_account/.kosh/schema.d.ts +144 -10
  196. package/dist/sale_account/module.d.ts +2008 -641
  197. package/dist/sale_account/module.js +3 -3
  198. package/dist/sale_portal/.kosh/bindings.d.ts +22 -0
  199. package/dist/sale_portal/.kosh/bindings.js +15 -0
  200. package/dist/sale_portal/.kosh/schema.d.ts +736 -0
  201. package/dist/sale_portal/index.d.ts +9 -0
  202. package/dist/sale_portal/index.js +71 -0
  203. package/dist/sale_portal/module.d.ts +2718 -0
  204. package/dist/sale_portal/module.js +19 -0
  205. package/dist/sale_project/.kosh/bindings.js +1 -1
  206. package/dist/sale_project/.kosh/schema.d.ts +15 -4
  207. package/dist/sale_project/module.d.ts +390 -10
  208. package/dist/sales/.kosh/bindings.js +1 -1
  209. package/dist/sales/.kosh/schema.d.ts +15 -4
  210. package/dist/sales/demo.js +3 -3
  211. package/dist/sales/index.js +67 -1
  212. package/dist/sales/module.d.ts +232 -8
  213. package/dist/sales/module.js +51 -12
  214. package/dist/server/auth/base.js +2 -0
  215. package/dist/server/auth/service.d.ts +2 -0
  216. package/dist/server/auth/service.js +7 -1
  217. package/dist/server/index.d.ts +1 -1
  218. package/dist/server/index.js +1 -1
  219. package/dist/server/server.js +26 -1
  220. package/dist/ui/api.d.ts +2 -0
  221. package/dist/ui/app.js +1 -1
  222. package/dist/ui/context.d.ts +3 -1
  223. package/dist/ui/context.js +2 -2
  224. package/dist/ui/index.d.ts +1 -1
  225. package/dist/ui/index.js +1 -1
  226. package/dist/ui/lib/format.d.ts +2 -0
  227. package/dist/ui/lib/format.js +3 -1
  228. package/dist/ui/views/FormView.js +19 -6
  229. package/package.json +50 -2
@@ -0,0 +1,22 @@
1
+ /**
2
+ * The data layer of Projects in the portal (RFC 0015 §5.4): customers' portal users read the projects made for their
3
+ * contact and company, and those projects' tasks (the portal's record rule, through the task's project).
4
+ */
5
+ import { portalRule, portalShutro } from '../portal/index.js';
6
+ import { projectShutro } from '../project/index.js';
7
+ import { defineModule, extendModel } from './.kosh/bindings.js';
8
+ export const ProjectPortal = extendModel('project.project', {
9
+ access: { 'portal.user': ['read'] },
10
+ rules: { portal: portalRule('partner') },
11
+ });
12
+ export const TaskPortal = extendModel('project.task', {
13
+ access: { 'portal.user': ['read'] },
14
+ rules: { portal: portalRule('project.partner') },
15
+ });
16
+ export const projectPortalShutro = defineModule({
17
+ name: 'project_portal',
18
+ version: '0.1.0',
19
+ depends: [projectShutro, portalShutro],
20
+ models: [],
21
+ extensions: [ProjectPortal, TaskPortal],
22
+ });
@@ -1,4 +1,4 @@
1
- // GENERATED by `pnpm generate:models` (Shutro’s generator). Do not edit. definitions-hash: 5ec17ee747e621b4
1
+ // GENERATED by `pnpm generate:models` (Shutro’s generator). Do not edit. definitions-hash: d7f70059c723acf9
2
2
  // Bindings of module `purchase`: import the definition API from here to get types scoped to what it can see.
3
3
  export { defineModel, defineModule, extendModel, f, replace } from '../../server/orm.js';
4
4
  import { definitions } from '../../server/orm.js';
@@ -1,4 +1,4 @@
1
- // GENERATED by `pnpm generate:models` (Shutro’s generator). Do not edit. definitions-hash: 5ec17ee747e621b4
1
+ // GENERATED by `pnpm generate:models` (Shutro’s generator). Do not edit. definitions-hash: d7f70059c723acf9
2
2
  // Schema view of module `purchase` (RFC 0002 §7.7): the models it owns or depends on, with the extensions it can see.
3
3
  import type { F } from '../../server/orm.js';
4
4
 
@@ -46,7 +46,13 @@ export interface AccountTax {
46
46
  readonly active: F.Bool<{ readonly required: true; readonly default: true }>;
47
47
  readonly name: F.Char<{ readonly required: true; readonly translate: true }>;
48
48
  readonly use: F.Selection<'sale' | 'purchase', { readonly required: true; readonly default: true }>;
49
+ readonly sequence: F.Integer<{ readonly required: true; readonly default: true }>;
50
+ readonly amountType: F.Selection<'percent' | 'fixed', { readonly required: true; readonly default: true }>;
49
51
  readonly rate: F.Decimal<{ readonly required: true; readonly default: true }>;
52
+ readonly fixedAmount: F.Decimal<{ readonly required: true; readonly default: true }>;
53
+ readonly affectsBase: F.Bool<{ readonly required: true; readonly default: true }>;
54
+ readonly priceIncluded: F.Bool<{ readonly required: true; readonly default: true }>;
55
+ readonly reverseCharge: F.Bool<{ readonly required: true; readonly default: true }>;
50
56
  };
51
57
  readonly methods: AccountTaxMethods;
52
58
  }
@@ -499,8 +505,10 @@ export interface ProductProduct {
499
505
  readonly standardPrice: F.Decimal<{ readonly required: true; readonly default: true }>;
500
506
  readonly saleOk: F.Bool<{ readonly required: true; readonly default: true }>;
501
507
  readonly purchaseOk: F.Bool<{ readonly required: true; readonly default: true }>;
502
- readonly tax: F.Many2one<'account.tax'>;
503
- readonly purchaseTax: F.Many2one<'account.tax'>;
508
+ readonly taxes: F.Many2many<'account.tax', { readonly required: true }>;
509
+ readonly purchaseTaxes: F.Many2many<'account.tax', { readonly required: true }>;
510
+ readonly tax: F.Many2one<'account.tax', { readonly readonly: true }>;
511
+ readonly purchaseTax: F.Many2one<'account.tax', { readonly readonly: true }>;
504
512
  readonly description: F.Text<{ readonly translate: true }>;
505
513
  };
506
514
  readonly methods: ProductProductMethods;
@@ -567,7 +575,8 @@ export interface PurchaseOrderLine {
567
575
  readonly quantity: F.Decimal<{ readonly required: true; readonly default: true }>;
568
576
  readonly uom: F.Many2one<'uom.uom'>;
569
577
  readonly priceUnit: F.Decimal<{ readonly required: true; readonly default: true }>;
570
- readonly tax: F.Many2one<'account.tax'>;
578
+ readonly taxes: F.Many2many<'account.tax', { readonly required: true }>;
579
+ readonly tax: F.Many2one<'account.tax', { readonly readonly: true }>;
571
580
  readonly datePlanned: F.DateOnly;
572
581
  readonly currency: F.Many2one<'res.currency', { readonly readonly: true; readonly compute: true; readonly store: true }>;
573
582
  readonly subtotal: F.Monetary<'currency', { readonly readonly: true; readonly compute: true; readonly store: true }>;
@@ -592,6 +601,7 @@ export interface ResCompany {
592
601
  readonly displayName: F.Char<{ readonly required: true; readonly readonly: true; readonly compute: true }>;
593
602
  readonly name: F.Char<{ readonly required: true }>;
594
603
  readonly currency: F.Many2one<'res.currency', { readonly required: true }>;
604
+ readonly numberGrouping: F.Selection<'international' | 'lakh', { readonly required: true; readonly default: true }>;
595
605
  };
596
606
  readonly methods: ResCompanyMethods;
597
607
  }
@@ -645,6 +655,7 @@ export interface ResPartner {
645
655
  readonly city: F.Char;
646
656
  readonly zip: F.Char;
647
657
  readonly country: F.Char;
658
+ readonly state: F.Char;
648
659
  readonly taxId: F.Char;
649
660
  readonly isCustomer: F.Bool<{ readonly required: true; readonly default: true }>;
650
661
  readonly isVendor: F.Bool<{ readonly required: true; readonly default: true }>;
@@ -2,7 +2,7 @@
2
2
  * Demo data of Purchase (RFC 0008 §5.8): a buyer's orders at every stage of the approval policy: confirmed after
3
3
  * submission, approved by the manager, and one large enough to wait for the director.
4
4
  */
5
- import { idByName } from '../modules-sdk/index.js';
5
+ import { idByName, maybeIdByName } from '../modules-sdk/index.js';
6
6
  import { decide, requestsOf } from '../permissions/index.js';
7
7
  import { orm } from '../server/orm.js';
8
8
  /** The demo buyer and the manager who approves. */
@@ -54,7 +54,7 @@ export async function purchaseDemo(context) {
54
54
  .load({ currency: true });
55
55
  if (company === undefined)
56
56
  throw new Error('Demo data: no company.');
57
- const vat = await idByName(env, 'account.tax', 'VAT 15% (purchases)');
57
+ const vat = await maybeIdByName(env, 'account.tax', 'VAT 15% (purchases)');
58
58
  for (const o of ORDERS) {
59
59
  const lines = [];
60
60
  for (const l of o.lines) {
@@ -64,7 +64,7 @@ export async function purchaseDemo(context) {
64
64
  name: l.product,
65
65
  quantity: l.quantity,
66
66
  priceUnit: l.price,
67
- tax: orm.asId(vat, 'account.tax'),
67
+ taxes: { set: vat === null ? [] : [orm.asId(vat, 'account.tax')] },
68
68
  datePlanned: context.date(14 - o.daysAgo),
69
69
  });
70
70
  }
@@ -146,7 +146,7 @@ export const purchase = defineModule({
146
146
  'quantity',
147
147
  'uom',
148
148
  'priceUnit',
149
- 'tax',
149
+ 'taxes',
150
150
  { field: 'datePlanned', id: 'line_date_planned' },
151
151
  'subtotal',
152
152
  ], { readonlyWhen: { state: { notIn: ['draft', 'sent'] } } }),
@@ -497,6 +497,16 @@ export declare const PurchaseOrderLine: import("../server/orm.js").Model<"purcha
497
497
  readonly hasDefault: true;
498
498
  readonly readonly: false;
499
499
  }>;
500
+ readonly taxes: import("../server/orm.js").Many2manyField<"account.tax", {
501
+ readonly required: true;
502
+ readonly computed: false;
503
+ readonly inverse: false;
504
+ readonly sequence: false;
505
+ readonly computeName: undefined;
506
+ readonly store: true;
507
+ readonly hasDefault: true;
508
+ readonly readonly: false;
509
+ }>;
500
510
  readonly tax: import("../server/orm.js").Many2oneField<"account.tax", {
501
511
  readonly required: false;
502
512
  readonly computed: false;
@@ -505,7 +515,7 @@ export declare const PurchaseOrderLine: import("../server/orm.js").Model<"purcha
505
515
  readonly computeName: undefined;
506
516
  readonly store: true;
507
517
  readonly hasDefault: false;
508
- readonly readonly: false;
518
+ readonly readonly: true;
509
519
  }>;
510
520
  readonly datePlanned: import("../server/orm.js").ScalarField<"date", string, string, {
511
521
  readonly required: false;
@@ -608,6 +618,18 @@ export declare const PurchaseOrderLine: import("../server/orm.js").Model<"purcha
608
618
  readonly hasDefault: true;
609
619
  readonly readonly: false;
610
620
  }>;
621
+ /** The line's taxes, applied in order (RFC 0016). */
622
+ readonly taxes: import("../server/orm.js").Many2manyField<"account.tax", {
623
+ readonly required: true;
624
+ readonly computed: false;
625
+ readonly inverse: false;
626
+ readonly sequence: false;
627
+ readonly computeName: undefined;
628
+ readonly store: true;
629
+ readonly hasDefault: true;
630
+ readonly readonly: false;
631
+ }>;
632
+ /** Before 0.2.0, one tax per line: copied into `taxes` by the migration; dropped later. */
611
633
  readonly tax: import("../server/orm.js").Many2oneField<"account.tax", {
612
634
  readonly required: false;
613
635
  readonly computed: false;
@@ -616,7 +638,7 @@ export declare const PurchaseOrderLine: import("../server/orm.js").Model<"purcha
616
638
  readonly computeName: undefined;
617
639
  readonly store: true;
618
640
  readonly hasDefault: false;
619
- readonly readonly: false;
641
+ readonly readonly: true;
620
642
  }>;
621
643
  readonly datePlanned: import("../server/orm.js").ScalarField<"date", string, string, {
622
644
  readonly required: false;
@@ -1157,6 +1179,16 @@ export declare const purchaseShutro: import("../server/orm.js").Module<readonly
1157
1179
  readonly hasDefault: true;
1158
1180
  readonly readonly: false;
1159
1181
  }>;
1182
+ readonly taxes: import("../server/orm.js").Many2manyField<"account.tax", {
1183
+ readonly required: true;
1184
+ readonly computed: false;
1185
+ readonly inverse: false;
1186
+ readonly sequence: false;
1187
+ readonly computeName: undefined;
1188
+ readonly store: true;
1189
+ readonly hasDefault: true;
1190
+ readonly readonly: false;
1191
+ }>;
1160
1192
  readonly tax: import("../server/orm.js").Many2oneField<"account.tax", {
1161
1193
  readonly required: false;
1162
1194
  readonly computed: false;
@@ -1165,7 +1197,7 @@ export declare const purchaseShutro: import("../server/orm.js").Module<readonly
1165
1197
  readonly computeName: undefined;
1166
1198
  readonly store: true;
1167
1199
  readonly hasDefault: false;
1168
- readonly readonly: false;
1200
+ readonly readonly: true;
1169
1201
  }>;
1170
1202
  readonly datePlanned: import("../server/orm.js").ScalarField<"date", string, string, {
1171
1203
  readonly required: false;
@@ -1268,6 +1300,18 @@ export declare const purchaseShutro: import("../server/orm.js").Module<readonly
1268
1300
  readonly hasDefault: true;
1269
1301
  readonly readonly: false;
1270
1302
  }>;
1303
+ /** The line's taxes, applied in order (RFC 0016). */
1304
+ readonly taxes: import("../server/orm.js").Many2manyField<"account.tax", {
1305
+ readonly required: true;
1306
+ readonly computed: false;
1307
+ readonly inverse: false;
1308
+ readonly sequence: false;
1309
+ readonly computeName: undefined;
1310
+ readonly store: true;
1311
+ readonly hasDefault: true;
1312
+ readonly readonly: false;
1313
+ }>;
1314
+ /** Before 0.2.0, one tax per line: copied into `taxes` by the migration; dropped later. */
1271
1315
  readonly tax: import("../server/orm.js").Many2oneField<"account.tax", {
1272
1316
  readonly required: false;
1273
1317
  readonly computed: false;
@@ -1276,7 +1320,7 @@ export declare const purchaseShutro: import("../server/orm.js").Module<readonly
1276
1320
  readonly computeName: undefined;
1277
1321
  readonly store: true;
1278
1322
  readonly hasDefault: false;
1279
- readonly readonly: false;
1323
+ readonly readonly: true;
1280
1324
  }>;
1281
1325
  readonly datePlanned: import("../server/orm.js").ScalarField<"date", string, string, {
1282
1326
  readonly required: false;
@@ -1482,6 +1526,16 @@ export declare const purchaseShutro: import("../server/orm.js").Module<readonly
1482
1526
  readonly hasDefault: false;
1483
1527
  readonly readonly: false;
1484
1528
  }, string>;
1529
+ readonly state: import("../server/orm.js").CharField<{
1530
+ readonly required: false;
1531
+ readonly computed: false;
1532
+ readonly inverse: false;
1533
+ readonly sequence: false;
1534
+ readonly computeName: undefined;
1535
+ readonly store: true;
1536
+ readonly hasDefault: false;
1537
+ readonly readonly: false;
1538
+ }, string>;
1485
1539
  readonly taxId: import("../server/orm.js").CharField<{
1486
1540
  readonly required: false;
1487
1541
  readonly computed: false;
@@ -1653,6 +1707,16 @@ export declare const purchaseShutro: import("../server/orm.js").Module<readonly
1653
1707
  readonly hasDefault: false;
1654
1708
  readonly readonly: false;
1655
1709
  }, string>;
1710
+ readonly state: import("../server/orm.js").CharField<{
1711
+ readonly required: false;
1712
+ readonly computed: false;
1713
+ readonly inverse: false;
1714
+ readonly sequence: false;
1715
+ readonly computeName: undefined;
1716
+ readonly store: true;
1717
+ readonly hasDefault: false;
1718
+ readonly readonly: false;
1719
+ }, string>;
1656
1720
  readonly taxId: import("../server/orm.js").CharField<{
1657
1721
  readonly required: false;
1658
1722
  readonly computed: false;
@@ -1973,6 +2037,26 @@ export declare const purchaseShutro: import("../server/orm.js").Module<readonly
1973
2037
  readonly hasDefault: true;
1974
2038
  readonly readonly: false;
1975
2039
  }>;
2040
+ readonly sequence: import("../server/orm.js").ScalarField<"integer", number, number, {
2041
+ readonly required: true;
2042
+ readonly computed: false;
2043
+ readonly inverse: false;
2044
+ readonly sequence: false;
2045
+ readonly computeName: undefined;
2046
+ readonly store: true;
2047
+ readonly hasDefault: true;
2048
+ readonly readonly: false;
2049
+ }>;
2050
+ readonly amountType: import("../server/orm.js").SelectionField<"fixed" | "percent", {
2051
+ readonly required: true;
2052
+ readonly computed: false;
2053
+ readonly inverse: false;
2054
+ readonly sequence: false;
2055
+ readonly computeName: undefined;
2056
+ readonly store: true;
2057
+ readonly hasDefault: true;
2058
+ readonly readonly: false;
2059
+ }>;
1976
2060
  readonly rate: import("../server/orm.js").DecimalField<{
1977
2061
  readonly required: true;
1978
2062
  readonly computed: false;
@@ -1983,6 +2067,46 @@ export declare const purchaseShutro: import("../server/orm.js").Module<readonly
1983
2067
  readonly hasDefault: true;
1984
2068
  readonly readonly: false;
1985
2069
  }>;
2070
+ readonly fixedAmount: import("../server/orm.js").DecimalField<{
2071
+ readonly required: true;
2072
+ readonly computed: false;
2073
+ readonly inverse: false;
2074
+ readonly sequence: false;
2075
+ readonly computeName: undefined;
2076
+ readonly store: true;
2077
+ readonly hasDefault: true;
2078
+ readonly readonly: false;
2079
+ }>;
2080
+ readonly affectsBase: import("../server/orm.js").ScalarField<"boolean", boolean, boolean, {
2081
+ readonly required: true;
2082
+ readonly computed: false;
2083
+ readonly inverse: false;
2084
+ readonly sequence: false;
2085
+ readonly computeName: undefined;
2086
+ readonly store: true;
2087
+ readonly hasDefault: true;
2088
+ readonly readonly: false;
2089
+ }>;
2090
+ readonly priceIncluded: import("../server/orm.js").ScalarField<"boolean", boolean, boolean, {
2091
+ readonly required: true;
2092
+ readonly computed: false;
2093
+ readonly inverse: false;
2094
+ readonly sequence: false;
2095
+ readonly computeName: undefined;
2096
+ readonly store: true;
2097
+ readonly hasDefault: true;
2098
+ readonly readonly: false;
2099
+ }>;
2100
+ readonly reverseCharge: import("../server/orm.js").ScalarField<"boolean", boolean, boolean, {
2101
+ readonly required: true;
2102
+ readonly computed: false;
2103
+ readonly inverse: false;
2104
+ readonly sequence: false;
2105
+ readonly computeName: undefined;
2106
+ readonly store: true;
2107
+ readonly hasDefault: true;
2108
+ readonly readonly: false;
2109
+ }>;
1986
2110
  }, {} & import("../server/orm.js").TransitionMethods<{
1987
2111
  readonly name: import("../server/orm.js").CharField<{
1988
2112
  readonly required: true;
@@ -2004,6 +2128,26 @@ export declare const purchaseShutro: import("../server/orm.js").Module<readonly
2004
2128
  readonly hasDefault: true;
2005
2129
  readonly readonly: false;
2006
2130
  }>;
2131
+ readonly sequence: import("../server/orm.js").ScalarField<"integer", number, number, {
2132
+ readonly required: true;
2133
+ readonly computed: false;
2134
+ readonly inverse: false;
2135
+ readonly sequence: false;
2136
+ readonly computeName: undefined;
2137
+ readonly store: true;
2138
+ readonly hasDefault: true;
2139
+ readonly readonly: false;
2140
+ }>;
2141
+ readonly amountType: import("../server/orm.js").SelectionField<"fixed" | "percent", {
2142
+ readonly required: true;
2143
+ readonly computed: false;
2144
+ readonly inverse: false;
2145
+ readonly sequence: false;
2146
+ readonly computeName: undefined;
2147
+ readonly store: true;
2148
+ readonly hasDefault: true;
2149
+ readonly readonly: false;
2150
+ }>;
2007
2151
  readonly rate: import("../server/orm.js").DecimalField<{
2008
2152
  readonly required: true;
2009
2153
  readonly computed: false;
@@ -2014,6 +2158,46 @@ export declare const purchaseShutro: import("../server/orm.js").Module<readonly
2014
2158
  readonly hasDefault: true;
2015
2159
  readonly readonly: false;
2016
2160
  }>;
2161
+ readonly fixedAmount: import("../server/orm.js").DecimalField<{
2162
+ readonly required: true;
2163
+ readonly computed: false;
2164
+ readonly inverse: false;
2165
+ readonly sequence: false;
2166
+ readonly computeName: undefined;
2167
+ readonly store: true;
2168
+ readonly hasDefault: true;
2169
+ readonly readonly: false;
2170
+ }>;
2171
+ readonly affectsBase: import("../server/orm.js").ScalarField<"boolean", boolean, boolean, {
2172
+ readonly required: true;
2173
+ readonly computed: false;
2174
+ readonly inverse: false;
2175
+ readonly sequence: false;
2176
+ readonly computeName: undefined;
2177
+ readonly store: true;
2178
+ readonly hasDefault: true;
2179
+ readonly readonly: false;
2180
+ }>;
2181
+ readonly priceIncluded: import("../server/orm.js").ScalarField<"boolean", boolean, boolean, {
2182
+ readonly required: true;
2183
+ readonly computed: false;
2184
+ readonly inverse: false;
2185
+ readonly sequence: false;
2186
+ readonly computeName: undefined;
2187
+ readonly store: true;
2188
+ readonly hasDefault: true;
2189
+ readonly readonly: false;
2190
+ }>;
2191
+ readonly reverseCharge: import("../server/orm.js").ScalarField<"boolean", boolean, boolean, {
2192
+ readonly required: true;
2193
+ readonly computed: false;
2194
+ readonly inverse: false;
2195
+ readonly sequence: false;
2196
+ readonly computeName: undefined;
2197
+ readonly store: true;
2198
+ readonly hasDefault: true;
2199
+ readonly readonly: false;
2200
+ }>;
2017
2201
  }>>, import("../server/orm.js").Model<"product.product", {
2018
2202
  readonly id: import("../server/orm.js").IdField<"product.product">;
2019
2203
  readonly createdAt: import("../server/orm.js").ScalarField<'datetime', Date, Date, {
@@ -2157,6 +2341,26 @@ export declare const purchaseShutro: import("../server/orm.js").Module<readonly
2157
2341
  readonly hasDefault: true;
2158
2342
  readonly readonly: false;
2159
2343
  }>;
2344
+ readonly taxes: import("../server/orm.js").Many2manyField<"account.tax", {
2345
+ readonly required: true;
2346
+ readonly computed: false;
2347
+ readonly inverse: false;
2348
+ readonly sequence: false;
2349
+ readonly computeName: undefined;
2350
+ readonly store: true;
2351
+ readonly hasDefault: true;
2352
+ readonly readonly: false;
2353
+ }>;
2354
+ readonly purchaseTaxes: import("../server/orm.js").Many2manyField<"account.tax", {
2355
+ readonly required: true;
2356
+ readonly computed: false;
2357
+ readonly inverse: false;
2358
+ readonly sequence: false;
2359
+ readonly computeName: undefined;
2360
+ readonly store: true;
2361
+ readonly hasDefault: true;
2362
+ readonly readonly: false;
2363
+ }>;
2160
2364
  readonly tax: import("../server/orm.js").Many2oneField<"account.tax", {
2161
2365
  readonly required: false;
2162
2366
  readonly computed: false;
@@ -2165,7 +2369,7 @@ export declare const purchaseShutro: import("../server/orm.js").Module<readonly
2165
2369
  readonly computeName: undefined;
2166
2370
  readonly store: true;
2167
2371
  readonly hasDefault: false;
2168
- readonly readonly: false;
2372
+ readonly readonly: true;
2169
2373
  }>;
2170
2374
  readonly purchaseTax: import("../server/orm.js").Many2oneField<"account.tax", {
2171
2375
  readonly required: false;
@@ -2175,7 +2379,7 @@ export declare const purchaseShutro: import("../server/orm.js").Module<readonly
2175
2379
  readonly computeName: undefined;
2176
2380
  readonly store: true;
2177
2381
  readonly hasDefault: false;
2178
- readonly readonly: false;
2382
+ readonly readonly: true;
2179
2383
  }>;
2180
2384
  readonly description: import("../server/orm.js").ScalarField<"text", string, string | Readonly<Record<string, string>>, {
2181
2385
  readonly required: false;
@@ -2288,6 +2492,26 @@ export declare const purchaseShutro: import("../server/orm.js").Module<readonly
2288
2492
  readonly hasDefault: true;
2289
2493
  readonly readonly: false;
2290
2494
  }>;
2495
+ readonly taxes: import("../server/orm.js").Many2manyField<"account.tax", {
2496
+ readonly required: true;
2497
+ readonly computed: false;
2498
+ readonly inverse: false;
2499
+ readonly sequence: false;
2500
+ readonly computeName: undefined;
2501
+ readonly store: true;
2502
+ readonly hasDefault: true;
2503
+ readonly readonly: false;
2504
+ }>;
2505
+ readonly purchaseTaxes: import("../server/orm.js").Many2manyField<"account.tax", {
2506
+ readonly required: true;
2507
+ readonly computed: false;
2508
+ readonly inverse: false;
2509
+ readonly sequence: false;
2510
+ readonly computeName: undefined;
2511
+ readonly store: true;
2512
+ readonly hasDefault: true;
2513
+ readonly readonly: false;
2514
+ }>;
2291
2515
  readonly tax: import("../server/orm.js").Many2oneField<"account.tax", {
2292
2516
  readonly required: false;
2293
2517
  readonly computed: false;
@@ -2296,7 +2520,7 @@ export declare const purchaseShutro: import("../server/orm.js").Module<readonly
2296
2520
  readonly computeName: undefined;
2297
2521
  readonly store: true;
2298
2522
  readonly hasDefault: false;
2299
- readonly readonly: false;
2523
+ readonly readonly: true;
2300
2524
  }>;
2301
2525
  readonly purchaseTax: import("../server/orm.js").Many2oneField<"account.tax", {
2302
2526
  readonly required: false;
@@ -2306,7 +2530,7 @@ export declare const purchaseShutro: import("../server/orm.js").Module<readonly
2306
2530
  readonly computeName: undefined;
2307
2531
  readonly store: true;
2308
2532
  readonly hasDefault: false;
2309
- readonly readonly: false;
2533
+ readonly readonly: true;
2310
2534
  }>;
2311
2535
  readonly description: import("../server/orm.js").ScalarField<"text", string, string | Readonly<Record<string, string>>, {
2312
2536
  readonly required: false;
@@ -7,9 +7,13 @@
7
7
  import { contactsShutro } from '../contacts/index.js';
8
8
  import { messagingShutro } from '../messaging/index.js';
9
9
  import { approvalGuard, permissionsShutro, requestApprovals } from '../permissions/index.js';
10
- import { productShutro } from '../product/index.js';
10
+ import { computeTaxes, productShutro, taxRule } from '../product/index.js';
11
11
  import { orm } from '../server/orm.js';
12
12
  import { check, compute, defineModel, defineModule, f, onchange, records, } from './.kosh/bindings.js';
13
+ /** A line's taxes through the engine (RFC 0016): its amount, its taxes in order. */
14
+ function taxesOf(l) {
15
+ return computeTaxes(l.quantity.times(l.priceUnit), l.quantity, [...l.taxes].map(taxRule));
16
+ }
13
17
  const amounts = compute('purchase.order', ['amountUntaxed', 'amountTax', 'amountTotal'], ['lines.subtotal', 'lines.taxAmount'], (orders) => {
14
18
  for (const o of orders) {
15
19
  // A new order has no currency until its partner is chosen: no amounts yet.
@@ -129,7 +133,10 @@ export const PurchaseOrderLine = defineModel('purchase.order.line', {
129
133
  quantity: f.decimal({ scale: 3, required: true, default: '1' }),
130
134
  uom: f.many2one('uom.uom', { label: 'Unit' }),
131
135
  priceUnit: f.decimal({ scale: 2, required: true, default: '0', label: 'Unit price' }),
132
- tax: f.many2one('account.tax'),
136
+ /** The line's taxes, applied in order (RFC 0016). */
137
+ taxes: f.many2many('account.tax'),
138
+ /** Before 0.2.0, one tax per line: copied into `taxes` by the migration; dropped later. */
139
+ tax: f.many2one('account.tax', { label: 'Tax (before 0.2.0)', readonly: true }),
133
140
  datePlanned: f.date({ label: 'Expected arrival' }),
134
141
  currency: f.many2one('res.currency', {
135
142
  store: true,
@@ -141,30 +148,55 @@ export const PurchaseOrderLine = defineModel('purchase.order.line', {
141
148
  subtotal: f.monetary({
142
149
  currency: 'currency',
143
150
  store: true,
144
- ...compute('purchase.order.line', 'subtotal', ['quantity', 'priceUnit'], (lines) => {
151
+ ...compute('purchase.order.line', 'subtotal', [
152
+ 'quantity',
153
+ 'priceUnit',
154
+ 'taxes.rate',
155
+ 'taxes.sequence',
156
+ 'taxes.amountType',
157
+ 'taxes.fixedAmount',
158
+ 'taxes.affectsBase',
159
+ 'taxes.priceIncluded',
160
+ 'taxes.reverseCharge',
161
+ ], (lines) => {
145
162
  for (const l of lines)
146
- l.subtotal = l.quantity.times(l.priceUnit);
163
+ l.subtotal = taxesOf(l).untaxed;
147
164
  }),
148
165
  }),
149
166
  taxAmount: f.monetary({
150
167
  currency: 'currency',
151
168
  store: true,
152
169
  label: 'Tax',
153
- ...compute('purchase.order.line', 'taxAmount', ['subtotal', 'tax.rate'], (lines) => {
170
+ ...compute('purchase.order.line', 'taxAmount', [
171
+ 'quantity',
172
+ 'priceUnit',
173
+ 'taxes.rate',
174
+ 'taxes.sequence',
175
+ 'taxes.amountType',
176
+ 'taxes.fixedAmount',
177
+ 'taxes.affectsBase',
178
+ 'taxes.priceIncluded',
179
+ 'taxes.reverseCharge',
180
+ ], (lines) => {
154
181
  for (const l of lines)
155
- l.taxAmount = (l.subtotal?.amount ?? orm.toDecimal(0)).times(l.tax?.rate ?? 0);
182
+ l.taxAmount = taxesOf(l).taxTotal;
156
183
  }),
157
184
  }),
158
185
  },
159
186
  onchange: {
160
- product: onchange('purchase.order.line', async (d) => {
187
+ product: onchange('purchase.order.line', async (d, env) => {
161
188
  const p = await d.record('product');
162
189
  if (p === null)
163
190
  return;
164
191
  d.set('name', p.name);
165
192
  d.set('priceUnit', p.standardPrice);
166
193
  d.set('uom', p.uom?.id ?? null);
167
- d.set('tax', p.purchaseTax?.id ?? null);
194
+ // The product's taxes, loaded (a draft's related record has its plain fields only).
195
+ const [taxed] = await env
196
+ .model('product.product')
197
+ .browse([p.id])
198
+ .load({ purchaseTaxes: true });
199
+ d.set('taxes', { set: [...(taxed?.purchaseTaxes.ids ?? [])] });
168
200
  }),
169
201
  },
170
202
  constraints: {
@@ -176,7 +208,17 @@ export const PurchaseOrderLine = defineModel('purchase.order.line', {
176
208
  });
177
209
  export const purchaseShutro = defineModule({
178
210
  name: 'purchase',
179
- version: '0.1.0',
211
+ version: '0.2.0',
212
+ migrations: [
213
+ {
214
+ version: '0.2.0',
215
+ description: 'Several taxes per line: the single tax of each line becomes its first',
216
+ up: async (ctx) => {
217
+ await ctx.sql `INSERT INTO purchase_order_line_account_tax_rel (purchase_order_line_id, account_tax_id)
218
+ SELECT id, tax_id FROM purchase_order_line WHERE tax_id IS NOT NULL ON CONFLICT DO NOTHING`;
219
+ },
220
+ },
221
+ ],
180
222
  depends: [contactsShutro, productShutro, messagingShutro, permissionsShutro],
181
223
  groups: [
182
224
  orm.defineGroup({
@@ -1,4 +1,4 @@
1
- // GENERATED by `pnpm generate:models` (Shutro’s generator). Do not edit. definitions-hash: f903224b80d0f1f1
1
+ // GENERATED by `pnpm generate:models` (Shutro’s generator). Do not edit. definitions-hash: 3208f1c12068264a
2
2
  // Bindings of module `purchase_account`: import the definition API from here to get types scoped to what it can see.
3
3
  export { defineModel, defineModule, extendModel, f, replace } from '../../server/orm.js';
4
4
  import { definitions } from '../../server/orm.js';