shutro-erp 0.3.1 → 0.3.3

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 (168) hide show
  1. package/dist/account_portal/.kosh/bindings.js +1 -1
  2. package/dist/account_portal/.kosh/schema.d.ts +29 -1
  3. package/dist/account_portal/index.js +3 -2
  4. package/dist/accounting/.kosh/bindings.js +1 -1
  5. package/dist/accounting/.kosh/schema.d.ts +29 -1
  6. package/dist/accounting/index.js +4 -0
  7. package/dist/assistant/index.js +1 -1
  8. package/dist/cli/init.js +2 -0
  9. package/dist/cli/launch.js +8 -5
  10. package/dist/cli/templates.js +4 -1
  11. package/dist/cli/ui.js +19 -1
  12. package/dist/contacts/.kosh/bindings.js +1 -1
  13. package/dist/contacts/.kosh/schema.d.ts +29 -1
  14. package/dist/integrations/inbound.d.ts +36 -0
  15. package/dist/integrations/inbound.js +171 -0
  16. package/dist/integrations/index.d.ts +18 -0
  17. package/dist/integrations/index.js +400 -0
  18. package/dist/integrations/models.d.ts +6 -0
  19. package/dist/integrations/models.js +119 -0
  20. package/dist/integrations/web/DeliveryTools.d.ts +4 -0
  21. package/dist/integrations/web/DeliveryTools.js +15 -0
  22. package/dist/integrations/web/EndpointTools.d.ts +7 -0
  23. package/dist/integrations/web/EndpointTools.js +25 -0
  24. package/dist/integrations/web/InboundTools.d.ts +4 -0
  25. package/dist/integrations/web/InboundTools.js +15 -0
  26. package/dist/integrations/web/WebhookTools.d.ts +7 -0
  27. package/dist/integrations/web/WebhookTools.js +25 -0
  28. package/dist/integrations/web/index.d.ts +16 -0
  29. package/dist/integrations/web/index.js +27 -0
  30. package/dist/integrations/web/messages.d.ts +2 -0
  31. package/dist/integrations/web/messages.js +53 -0
  32. package/dist/integrations/webhooks.d.ts +63 -0
  33. package/dist/integrations/webhooks.js +217 -0
  34. package/dist/l10n_bd/.kosh/bindings.js +1 -1
  35. package/dist/l10n_bd/.kosh/schema.d.ts +29 -1
  36. package/dist/l10n_in/.kosh/bindings.js +1 -1
  37. package/dist/l10n_in/.kosh/schema.d.ts +29 -4
  38. package/dist/l10n_in/module.d.ts +0 -62
  39. package/dist/l10n_in/module.js +2 -4
  40. package/dist/modules-sdk/index.d.ts +1 -1
  41. package/dist/modules-sdk/manifest.d.ts +48 -0
  42. package/dist/payment/.kosh/bindings.d.ts +22 -0
  43. package/dist/payment/.kosh/bindings.js +15 -0
  44. package/dist/payment/.kosh/schema.d.ts +1581 -0
  45. package/dist/payment/bkash.d.ts +28 -0
  46. package/dist/payment/bkash.js +169 -0
  47. package/dist/payment/index.d.ts +38 -0
  48. package/dist/payment/index.js +431 -0
  49. package/dist/payment/module.d.ts +6856 -0
  50. package/dist/payment/module.js +77 -0
  51. package/dist/payment/money.d.ts +7 -0
  52. package/dist/payment/money.js +37 -0
  53. package/dist/payment/providers.d.ts +75 -0
  54. package/dist/payment/providers.js +77 -0
  55. package/dist/payment/razorpay.d.ts +12 -0
  56. package/dist/payment/razorpay.js +149 -0
  57. package/dist/payment/settle.d.ts +11 -0
  58. package/dist/payment/settle.js +59 -0
  59. package/dist/payment/sslcommerz.d.ts +12 -0
  60. package/dist/payment/sslcommerz.js +185 -0
  61. package/dist/payment/stripe.d.ts +15 -0
  62. package/dist/payment/stripe.js +182 -0
  63. package/dist/permissions/admin.d.ts +3 -0
  64. package/dist/permissions/admin.js +108 -10
  65. package/dist/permissions/index.d.ts +1 -0
  66. package/dist/permissions/index.js +3 -0
  67. package/dist/permissions/roles.d.ts +2 -0
  68. package/dist/permissions/roles.js +236 -0
  69. package/dist/portal/.kosh/bindings.js +1 -1
  70. package/dist/portal/.kosh/schema.d.ts +29 -1
  71. package/dist/portal/routes-documents.js +5 -0
  72. package/dist/product/.kosh/bindings.js +1 -1
  73. package/dist/product/.kosh/schema.d.ts +29 -1
  74. package/dist/project/.kosh/bindings.js +1 -1
  75. package/dist/project/.kosh/schema.d.ts +29 -1
  76. package/dist/project_portal/.kosh/bindings.js +1 -1
  77. package/dist/project_portal/.kosh/schema.d.ts +29 -1
  78. package/dist/purchase/.kosh/bindings.js +1 -1
  79. package/dist/purchase/.kosh/schema.d.ts +29 -1
  80. package/dist/purchase_account/.kosh/bindings.js +1 -1
  81. package/dist/purchase_account/.kosh/schema.d.ts +29 -1
  82. package/dist/purchase_portal/.kosh/bindings.js +1 -1
  83. package/dist/purchase_portal/.kosh/schema.d.ts +29 -1
  84. package/dist/sale_account/.kosh/bindings.js +1 -1
  85. package/dist/sale_account/.kosh/schema.d.ts +29 -1
  86. package/dist/sale_portal/.kosh/bindings.js +1 -1
  87. package/dist/sale_portal/.kosh/schema.d.ts +29 -1
  88. package/dist/sale_project/.kosh/bindings.js +1 -1
  89. package/dist/sale_project/.kosh/schema.d.ts +29 -1
  90. package/dist/sales/.kosh/bindings.js +1 -1
  91. package/dist/sales/.kosh/schema.d.ts +29 -1
  92. package/dist/sales/index.js +2 -0
  93. package/dist/server/api/rest.d.ts +6 -1
  94. package/dist/server/api/rest.js +11 -0
  95. package/dist/server/auth/base.js +22 -0
  96. package/dist/server/auth/routes.d.ts +3 -0
  97. package/dist/server/auth/routes.js +29 -0
  98. package/dist/server/auth/service.d.ts +52 -0
  99. package/dist/server/auth/service.js +168 -3
  100. package/dist/server/identity.d.ts +2 -0
  101. package/dist/server/index.d.ts +2 -2
  102. package/dist/server/index.js +1 -1
  103. package/dist/server/server.js +11 -3
  104. package/dist/settings/company.d.ts +34 -0
  105. package/dist/settings/company.js +187 -0
  106. package/dist/settings/index.d.ts +10 -10
  107. package/dist/settings/index.js +159 -30
  108. package/dist/settings/people.d.ts +16 -0
  109. package/dist/settings/people.js +505 -0
  110. package/dist/settings/security.d.ts +13 -0
  111. package/dist/settings/security.js +158 -0
  112. package/dist/settings/web/AuditPage.d.ts +8 -0
  113. package/dist/settings/web/AuditPage.js +74 -0
  114. package/dist/settings/web/CompaniesPage.d.ts +8 -0
  115. package/dist/settings/web/CompaniesPage.js +52 -0
  116. package/dist/settings/web/CompanyPage.d.ts +9 -0
  117. package/dist/settings/web/CompanyPage.js +94 -0
  118. package/dist/settings/web/OverviewPage.d.ts +9 -0
  119. package/dist/settings/web/OverviewPage.js +66 -0
  120. package/dist/settings/web/PeoplePage.d.ts +9 -0
  121. package/dist/settings/web/PeoplePage.js +163 -0
  122. package/dist/settings/web/ProfilePage.d.ts +14 -0
  123. package/dist/settings/web/ProfilePage.js +194 -0
  124. package/dist/settings/web/RolesEditor.d.ts +35 -0
  125. package/dist/settings/web/RolesEditor.js +49 -0
  126. package/dist/settings/web/RolesPage.d.ts +9 -0
  127. package/dist/settings/web/RolesPage.js +296 -0
  128. package/dist/settings/web/SecurityPage.d.ts +8 -0
  129. package/dist/settings/web/SecurityPage.js +81 -0
  130. package/dist/settings/web/index.d.ts +9 -0
  131. package/dist/settings/web/index.js +26 -1
  132. package/dist/settings/web/messages.js +566 -0
  133. package/dist/ui/api.d.ts +4 -0
  134. package/dist/ui/app.d.ts +5 -0
  135. package/dist/ui/app.js +108 -31
  136. package/dist/ui/components/primitives.d.ts +9 -1
  137. package/dist/ui/components/primitives.js +12 -4
  138. package/dist/ui/context.d.ts +10 -1
  139. package/dist/ui/context.js +60 -2
  140. package/dist/ui/i18n/messages.d.ts +46 -0
  141. package/dist/ui/i18n/messages.js +92 -0
  142. package/dist/ui/index.d.ts +2 -1
  143. package/dist/ui/index.js +2 -1
  144. package/dist/ui/lib/accent.d.ts +13 -0
  145. package/dist/ui/lib/accent.js +36 -0
  146. package/dist/ui/shell/Activate.d.ts +6 -0
  147. package/dist/ui/shell/Activate.js +39 -0
  148. package/dist/ui/shell/CommandPalette.d.ts +7 -1
  149. package/dist/ui/shell/CommandPalette.js +16 -2
  150. package/dist/ui/shell/Sidebar.d.ts +27 -0
  151. package/dist/ui/shell/Sidebar.js +84 -0
  152. package/dist/ui/shell/TwoFactorSetup.d.ts +5 -0
  153. package/dist/ui/shell/TwoFactorSetup.js +32 -0
  154. package/dist/ui/shell/shortcuts.d.ts +3 -0
  155. package/dist/ui/shell/shortcuts.js +13 -4
  156. package/dist/ui/styles.css +70 -28
  157. package/dist/ui/views/DateField.d.ts +10 -0
  158. package/dist/ui/views/DateField.js +129 -0
  159. package/dist/ui/views/FormView.js +161 -21
  160. package/dist/ui/views/ListView.d.ts +2 -0
  161. package/dist/ui/views/ListView.js +8 -3
  162. package/dist/ui/views/StatusChip.d.ts +10 -0
  163. package/dist/ui/views/StatusChip.js +22 -0
  164. package/dist/ui/views/widgets.d.ts +3 -0
  165. package/dist/ui/views/widgets.js +26 -8
  166. package/dist/views/types.d.ts +7 -0
  167. package/dist/views/validate.js +4 -0
  168. package/package.json +14 -2
@@ -0,0 +1,236 @@
1
+ import { HttpProblem } from '../server/index.js';
2
+ import { requireAdministrator } from './admin.js';
3
+ const PERMS = ['read', 'write', 'create', 'unlink', 'export', 'import'];
4
+ const find = async (env, model, where, keys) => {
5
+ const set = (await env.model(model).search({ where, order: ['id asc'] }));
6
+ return set.length === 0 ? [] : (await set.load(keys)).read(['id', ...keys]);
7
+ };
8
+ const bad = (detail) => new HttpProblem(400, 'invalid-body', 'Invalid request', detail);
9
+ export function registerRoleRoutes(context) {
10
+ const { app, registry } = context;
11
+ const reg = registry.registry;
12
+ const loaded = registry.loaded;
13
+ const modules = loaded.modules;
14
+ const hidden = new Set(modules.flatMap((m) => m.privateModels ?? []));
15
+ const appOf = new Map(modules.map((m) => [m.name, m.app?.label ?? null]));
16
+ /** Every group a set of roles amounts to: declared groups' closure, runtime roles followed through. */
17
+ const closureOf = (codes, runtime) => {
18
+ const roles = new Map(runtime.roles.map((r) => [r.code, r]));
19
+ const seen = new Set();
20
+ const queue = [...codes];
21
+ while (queue.length > 0) {
22
+ const code = queue.pop();
23
+ if (seen.has(code))
24
+ continue;
25
+ seen.add(code);
26
+ for (const next of roles.get(code)?.implies ?? [])
27
+ queue.push(next);
28
+ }
29
+ return new Set([
30
+ ...seen,
31
+ ...reg.security.closure([...seen].filter((c) => reg.security.groups.has(c))),
32
+ ]);
33
+ };
34
+ /** What a set of groups grants: per model the permissions, and the feature permissions. */
35
+ const grants = (groups, runtime, except) => {
36
+ const models = new Map();
37
+ for (const [name, model] of reg.models) {
38
+ const access = (model.model.access ?? {});
39
+ const perms = new Set();
40
+ for (const g of groups)
41
+ for (const p of access[g] ?? [])
42
+ perms.add(p);
43
+ if (perms.size > 0)
44
+ models.set(name, perms);
45
+ }
46
+ for (const a of runtime.access)
47
+ if (groups.has(a.role) && a.role !== except)
48
+ for (const p of a.perms) {
49
+ const set = models.get(a.model) ?? new Set();
50
+ set.add(p);
51
+ models.set(a.model, set);
52
+ }
53
+ const permissions = new Set();
54
+ for (const p of reg.security.permissions.values())
55
+ if (p.groups.some((g) => groups.has(g)))
56
+ permissions.add(p.code);
57
+ for (const g of runtime.permissions)
58
+ if (groups.has(g.role) && g.role !== except)
59
+ permissions.add(g.permission);
60
+ const levels = new Set([...loaded.accessLevels.entries()]
61
+ .filter(([, level]) => level.groups.length > 0 && level.groups.every((g) => groups.has(g)))
62
+ .map(([code]) => code));
63
+ return { models, permissions, levels };
64
+ };
65
+ const levelLabel = (code) => {
66
+ const level = loaded.accessLevels.get(code);
67
+ return level === undefined
68
+ ? code
69
+ : `${appOf.get(level.module) ?? level.module} · ${level.label}`;
70
+ };
71
+ const permissionLabel = (code) => reg.security.permissions.get(code)?.label ?? code;
72
+ /** The role, whether declared in code or made at runtime. */
73
+ const roleOf = (code, runtime) => {
74
+ const declared = reg.security.groups.get(code);
75
+ if (declared !== undefined)
76
+ return {
77
+ code,
78
+ label: declared.label ?? code,
79
+ implies: [...(declared.implies ?? [])],
80
+ builtIn: true,
81
+ };
82
+ const made = runtime.roles.find((r) => r.code === code);
83
+ if (made === undefined)
84
+ throw new HttpProblem(404, 'missing-record', 'Not found', `There is no role '${code}'.`);
85
+ return { code, label: made.label, implies: [...made.implies], builtIn: false };
86
+ };
87
+ const holdersOf = async (env, code) => env.asSuperuser({ reason: 'role holders' }, async (su) => {
88
+ const assigned = await find(su, 'auth.user_group', { group: code }, ['user']);
89
+ const ids = [...new Set(assigned.map((a) => a['user']))];
90
+ if (ids.length === 0)
91
+ return [];
92
+ return (await find(su, 'res.users', { id: { in: ids } }, ['name', 'login'])).map((u) => ({
93
+ id: u['id'],
94
+ name: String(u['name']),
95
+ login: String(u['login']),
96
+ }));
97
+ });
98
+ const codeParam = (request) => String(request.params['code'] ?? '');
99
+ app.get('/api/v1/admin/roles/:code', async (request) => {
100
+ const code = codeParam(request);
101
+ return request.env(async (env) => {
102
+ requireAdministrator(env);
103
+ const runtime = await env.securityAdmin.describe();
104
+ const role = roleOf(code, runtime);
105
+ const closure = closureOf([code], runtime);
106
+ // Locked: what code and the included roles give; own: this role's runtime grants.
107
+ const locked = grants(closure, runtime, code);
108
+ const own = new Map(runtime.access.filter((a) => a.role === code).map((a) => [a.model, [...a.perms]]));
109
+ const ownPermissions = runtime.permissions
110
+ .filter((p) => p.role === code)
111
+ .map((p) => p.permission);
112
+ return {
113
+ ...role,
114
+ administrator: env.access.administratorGroups().has(code),
115
+ accessLevels: [...grants(closureOf(role.implies, runtime), runtime).levels],
116
+ holders: await holdersOf(env, code),
117
+ models: [...reg.models]
118
+ .filter(([name]) => !hidden.has(name) && !name.startsWith('shutro.'))
119
+ .map(([name, model]) => ({
120
+ name,
121
+ label: model.model.label ?? name,
122
+ app: appOf.get(model.module) ?? null,
123
+ locked: [...(locked.models.get(name) ?? [])],
124
+ own: own.get(name) ?? [],
125
+ }))
126
+ // Apps first (by name), technical models last.
127
+ .sort((a, b) => Number(a.app === null) - Number(b.app === null) ||
128
+ (a.app ?? '').localeCompare(b.app ?? '') ||
129
+ a.label.localeCompare(b.label)),
130
+ permissions: [...reg.security.permissions.values()].map((p) => ({
131
+ code: p.code,
132
+ label: p.label ?? p.code,
133
+ locked: locked.permissions.has(p.code),
134
+ own: ownPermissions.includes(p.code),
135
+ })),
136
+ rules: runtime.rules.filter((r) => r.role === code),
137
+ fields: runtime.fields.filter((f) => f.read.includes(code) || f.write.includes(code)),
138
+ };
139
+ }, { write: true });
140
+ });
141
+ app.post('/api/v1/admin/roles/:code/preview', async (request) => {
142
+ const code = codeParam(request);
143
+ const body = (request.body ?? {});
144
+ const list = (v, what) => {
145
+ if (v === undefined)
146
+ return undefined;
147
+ if (!Array.isArray(v) || v.some((x) => typeof x !== 'string'))
148
+ throw bad(`${what} is a list of codes.`);
149
+ return v;
150
+ };
151
+ const levels = list(body['accessLevels'], 'accessLevels');
152
+ const implies = list(body['implies'], 'implies');
153
+ const permissions = list(body['permissions'], 'permissions');
154
+ const access = body['access'];
155
+ if (access !== undefined &&
156
+ (typeof access !== 'object' || access === null || Array.isArray(access)))
157
+ throw bad('access is { model: [permissions] }.');
158
+ return request.env(async (env) => {
159
+ requireAdministrator(env);
160
+ const runtime = await env.securityAdmin.describe();
161
+ const role = roleOf(code, runtime);
162
+ // The role's proposed state, as a runtime overlay of itself.
163
+ const levelGroups = (levels ?? []).flatMap((l) => {
164
+ const level = loaded.accessLevels.get(l);
165
+ if (level === undefined)
166
+ throw bad(`'${l}' is not an access level.`);
167
+ return [...level.groups];
168
+ });
169
+ const proposedImplies = levels === undefined && implies === undefined
170
+ ? role.implies
171
+ : [...new Set([...levelGroups, ...(implies ?? [])])];
172
+ const ownAccess = (access ??
173
+ Object.fromEntries(runtime.access.filter((a) => a.role === code).map((a) => [a.model, a.perms])));
174
+ const proposed = {
175
+ ...runtime,
176
+ roles: role.builtIn
177
+ ? runtime.roles
178
+ : runtime.roles.map((r) => (r.code === code ? { ...r, implies: proposedImplies } : r)),
179
+ access: [
180
+ ...runtime.access.filter((a) => a.role !== code),
181
+ ...Object.entries(ownAccess).map(([model, perms]) => ({
182
+ role: code,
183
+ model,
184
+ perms: perms,
185
+ })),
186
+ ],
187
+ permissions: permissions === undefined
188
+ ? runtime.permissions
189
+ : [
190
+ ...runtime.permissions.filter((p) => p.role !== code),
191
+ ...permissions.map((permission) => ({ role: code, permission })),
192
+ ],
193
+ };
194
+ const before = grants(closureOf([code], runtime), runtime);
195
+ const after = grants(closureOf([code], proposed), proposed);
196
+ const holders = await holdersOf(env, code);
197
+ const others = await env.asSuperuser({ reason: 'role preview' }, (su) => find(su, 'auth.user_group', { user: { in: holders.map((h) => h.id) } }, [
198
+ 'user',
199
+ 'group',
200
+ ]));
201
+ const people = holders
202
+ .map((h) => {
203
+ const elsewhere = grants(closureOf(others
204
+ .filter((o) => o['user'] === h.id && o['group'] !== code)
205
+ .map((o) => String(o['group'])), runtime), runtime);
206
+ const diff = (from, to, kept) => [...to].filter((x) => !from.has(x) && !kept.has(x));
207
+ return {
208
+ id: h.id,
209
+ name: h.name,
210
+ gains: [
211
+ ...diff(before.levels, after.levels, elsewhere.levels).map(levelLabel),
212
+ ...diff(before.permissions, after.permissions, elsewhere.permissions).map(permissionLabel),
213
+ ],
214
+ losses: [
215
+ ...diff(after.levels, before.levels, elsewhere.levels).map(levelLabel),
216
+ ...diff(after.permissions, before.permissions, elsewhere.permissions).map(permissionLabel),
217
+ ],
218
+ };
219
+ })
220
+ .filter((p) => p.gains.length > 0 || p.losses.length > 0);
221
+ const models = [...new Set([...before.models.keys(), ...after.models.keys()])]
222
+ .map((name) => {
223
+ const was = before.models.get(name) ?? new Set();
224
+ const will = after.models.get(name) ?? new Set();
225
+ return {
226
+ model: name,
227
+ label: reg.models.get(name)?.model?.label ?? name,
228
+ added: PERMS.filter((p) => will.has(p) && !was.has(p)),
229
+ removed: PERMS.filter((p) => was.has(p) && !will.has(p)),
230
+ };
231
+ })
232
+ .filter((m) => m.added.length > 0 || m.removed.length > 0);
233
+ return { holders: holders.length, people, models };
234
+ }, { write: true });
235
+ });
236
+ }
@@ -1,4 +1,4 @@
1
- // GENERATED by `pnpm generate:models` (Shutro’s generator). Do not edit. definitions-hash: bae647ca883975a1
1
+ // GENERATED by `pnpm generate:models` (Shutro’s generator). Do not edit. definitions-hash: f41721dc1c51ba8a
2
2
  // Bindings of module `portal`: 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: bae647ca883975a1
1
+ // GENERATED by `pnpm generate:models` (Shutro’s generator). Do not edit. definitions-hash: f41721dc1c51ba8a
2
2
  // Schema view of module `portal` (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
 
@@ -7,6 +7,7 @@ export interface SchemaView {
7
7
  readonly 'audit.event': AuditEvent;
8
8
  readonly 'auth.api_key': AuthApiKey;
9
9
  readonly 'auth.credential': AuthCredential;
10
+ readonly 'auth.policy': AuthPolicy;
10
11
  readonly 'auth.session': AuthSession;
11
12
  readonly 'auth.user_grant': AuthUserGrant;
12
13
  readonly 'auth.user_group': AuthUserGroup;
@@ -97,6 +98,26 @@ export interface AuthCredential {
97
98
  export interface AuthCredentialMethods extends F.Methods<typeof import('../../server/index.js').baseShutro, 'auth.credential'> {
98
99
  }
99
100
 
101
+ /** `auth.policy` (owner: base). */
102
+ export interface AuthPolicy {
103
+ readonly name: 'auth.policy';
104
+ readonly fields: {
105
+ readonly id: F.Id<'auth.policy'>;
106
+ readonly createdAt: F.Datetime<{ readonly required: true; readonly readonly: true }>;
107
+ readonly updatedAt: F.Datetime<{ readonly required: true; readonly readonly: true }>;
108
+ readonly createdBy: F.Many2one<'res.users', { readonly readonly: true }>;
109
+ readonly updatedBy: F.Many2one<'res.users', { readonly readonly: true }>;
110
+ readonly displayName: F.Char<{ readonly required: true; readonly readonly: true; readonly compute: true }>;
111
+ readonly twoFactor: F.Selection<'administrators' | 'everyone', { readonly required: true; readonly default: true }>;
112
+ readonly sessionDays: F.Integer;
113
+ };
114
+ readonly methods: AuthPolicyMethods;
115
+ }
116
+
117
+ /** Methods of `auth.policy`: declared ones and transitions. */
118
+ export interface AuthPolicyMethods extends F.Methods<typeof import('../../server/index.js').baseShutro, 'auth.policy'> {
119
+ }
120
+
100
121
  /** `auth.session` (owner: base). */
101
122
  export interface AuthSession {
102
123
  readonly name: 'auth.session';
@@ -278,6 +299,13 @@ export interface ResCompany {
278
299
  readonly name: F.Char<{ readonly required: true }>;
279
300
  readonly currency: F.Many2one<'res.currency', { readonly required: true }>;
280
301
  readonly numberGrouping: F.Selection<'international' | 'lakh', { readonly required: true; readonly default: true }>;
302
+ readonly accentColor: F.Char;
303
+ readonly street: F.Char;
304
+ readonly city: F.Char;
305
+ readonly zip: F.Char;
306
+ readonly email: F.Char;
307
+ readonly phone: F.Char;
308
+ readonly website: F.Char;
281
309
  };
282
310
  readonly methods: ResCompanyMethods;
283
311
  }
@@ -207,6 +207,11 @@ export function registerPortalDocumentRoutes(context) {
207
207
  ? {}
208
208
  : { lineFields: meta(d.lineModel, d.spec.lines.fields), lines }),
209
209
  actions: await available(su, d, id),
210
+ payable: d.spec.payment !== undefined &&
211
+ (await ref(su, d.model.name).search({
212
+ where: { and: [{ id }, d.spec.payment.when] },
213
+ limit: 1,
214
+ })).length > 0,
210
215
  pdf: d.spec.pdf !== undefined,
211
216
  thread: d.spec.thread === true,
212
217
  };
@@ -1,4 +1,4 @@
1
- // GENERATED by `pnpm generate:models` (Shutro’s generator). Do not edit. definitions-hash: 86d7229d7b275957
1
+ // GENERATED by `pnpm generate:models` (Shutro’s generator). Do not edit. definitions-hash: 2544d3673d343d73
2
2
  // Bindings of module `product`: 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: 86d7229d7b275957
1
+ // GENERATED by `pnpm generate:models` (Shutro’s generator). Do not edit. definitions-hash: 2544d3673d343d73
2
2
  // Schema view of module `product` (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
 
@@ -8,6 +8,7 @@ export interface SchemaView {
8
8
  readonly 'audit.event': AuditEvent;
9
9
  readonly 'auth.api_key': AuthApiKey;
10
10
  readonly 'auth.credential': AuthCredential;
11
+ readonly 'auth.policy': AuthPolicy;
11
12
  readonly 'auth.session': AuthSession;
12
13
  readonly 'auth.user_grant': AuthUserGrant;
13
14
  readonly 'auth.user_group': AuthUserGroup;
@@ -125,6 +126,26 @@ export interface AuthCredential {
125
126
  export interface AuthCredentialMethods extends F.Methods<typeof import('../../server/index.js').baseShutro, 'auth.credential'> {
126
127
  }
127
128
 
129
+ /** `auth.policy` (owner: base). */
130
+ export interface AuthPolicy {
131
+ readonly name: 'auth.policy';
132
+ readonly fields: {
133
+ readonly id: F.Id<'auth.policy'>;
134
+ readonly createdAt: F.Datetime<{ readonly required: true; readonly readonly: true }>;
135
+ readonly updatedAt: F.Datetime<{ readonly required: true; readonly readonly: true }>;
136
+ readonly createdBy: F.Many2one<'res.users', { readonly readonly: true }>;
137
+ readonly updatedBy: F.Many2one<'res.users', { readonly readonly: true }>;
138
+ readonly displayName: F.Char<{ readonly required: true; readonly readonly: true; readonly compute: true }>;
139
+ readonly twoFactor: F.Selection<'administrators' | 'everyone', { readonly required: true; readonly default: true }>;
140
+ readonly sessionDays: F.Integer;
141
+ };
142
+ readonly methods: AuthPolicyMethods;
143
+ }
144
+
145
+ /** Methods of `auth.policy`: declared ones and transitions. */
146
+ export interface AuthPolicyMethods extends F.Methods<typeof import('../../server/index.js').baseShutro, 'auth.policy'> {
147
+ }
148
+
128
149
  /** `auth.session` (owner: base). */
129
150
  export interface AuthSession {
130
151
  readonly name: 'auth.session';
@@ -288,6 +309,13 @@ export interface ResCompany {
288
309
  readonly name: F.Char<{ readonly required: true }>;
289
310
  readonly currency: F.Many2one<'res.currency', { readonly required: true }>;
290
311
  readonly numberGrouping: F.Selection<'international' | 'lakh', { readonly required: true; readonly default: true }>;
312
+ readonly accentColor: F.Char;
313
+ readonly street: F.Char;
314
+ readonly city: F.Char;
315
+ readonly zip: F.Char;
316
+ readonly email: F.Char;
317
+ readonly phone: F.Char;
318
+ readonly website: F.Char;
291
319
  };
292
320
  readonly methods: ResCompanyMethods;
293
321
  }
@@ -1,4 +1,4 @@
1
- // GENERATED by `pnpm generate:models` (Shutro’s generator). Do not edit. definitions-hash: 8538c294f98318cd
1
+ // GENERATED by `pnpm generate:models` (Shutro’s generator). Do not edit. definitions-hash: 25d6271e4bd2aa40
2
2
  // Bindings of module `project`: 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: 8538c294f98318cd
1
+ // GENERATED by `pnpm generate:models` (Shutro’s generator). Do not edit. definitions-hash: 25d6271e4bd2aa40
2
2
  // Schema view of module `project` (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
 
@@ -7,6 +7,7 @@ export interface SchemaView {
7
7
  readonly 'audit.event': AuditEvent;
8
8
  readonly 'auth.api_key': AuthApiKey;
9
9
  readonly 'auth.credential': AuthCredential;
10
+ readonly 'auth.policy': AuthPolicy;
10
11
  readonly 'auth.session': AuthSession;
11
12
  readonly 'auth.user_grant': AuthUserGrant;
12
13
  readonly 'auth.user_group': AuthUserGroup;
@@ -106,6 +107,26 @@ export interface AuthCredential {
106
107
  export interface AuthCredentialMethods extends F.Methods<typeof import('../../server/index.js').baseShutro, 'auth.credential'> {
107
108
  }
108
109
 
110
+ /** `auth.policy` (owner: base). */
111
+ export interface AuthPolicy {
112
+ readonly name: 'auth.policy';
113
+ readonly fields: {
114
+ readonly id: F.Id<'auth.policy'>;
115
+ readonly createdAt: F.Datetime<{ readonly required: true; readonly readonly: true }>;
116
+ readonly updatedAt: F.Datetime<{ readonly required: true; readonly readonly: true }>;
117
+ readonly createdBy: F.Many2one<'res.users', { readonly readonly: true }>;
118
+ readonly updatedBy: F.Many2one<'res.users', { readonly readonly: true }>;
119
+ readonly displayName: F.Char<{ readonly required: true; readonly readonly: true; readonly compute: true }>;
120
+ readonly twoFactor: F.Selection<'administrators' | 'everyone', { readonly required: true; readonly default: true }>;
121
+ readonly sessionDays: F.Integer;
122
+ };
123
+ readonly methods: AuthPolicyMethods;
124
+ }
125
+
126
+ /** Methods of `auth.policy`: declared ones and transitions. */
127
+ export interface AuthPolicyMethods extends F.Methods<typeof import('../../server/index.js').baseShutro, 'auth.policy'> {
128
+ }
129
+
109
130
  /** `auth.session` (owner: base). */
110
131
  export interface AuthSession {
111
132
  readonly name: 'auth.session';
@@ -503,6 +524,13 @@ export interface ResCompany {
503
524
  readonly name: F.Char<{ readonly required: true }>;
504
525
  readonly currency: F.Many2one<'res.currency', { readonly required: true }>;
505
526
  readonly numberGrouping: F.Selection<'international' | 'lakh', { readonly required: true; readonly default: true }>;
527
+ readonly accentColor: F.Char;
528
+ readonly street: F.Char;
529
+ readonly city: F.Char;
530
+ readonly zip: F.Char;
531
+ readonly email: F.Char;
532
+ readonly phone: F.Char;
533
+ readonly website: F.Char;
506
534
  };
507
535
  readonly methods: ResCompanyMethods;
508
536
  }
@@ -1,4 +1,4 @@
1
- // GENERATED by `pnpm generate:models` (Shutro’s generator). Do not edit. definitions-hash: 0440c5ae846a11ac
1
+ // GENERATED by `pnpm generate:models` (Shutro’s generator). Do not edit. definitions-hash: 99c699d27d0e98db
2
2
  // Bindings of module `project_portal`: 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: 0440c5ae846a11ac
1
+ // GENERATED by `pnpm generate:models` (Shutro’s generator). Do not edit. definitions-hash: 99c699d27d0e98db
2
2
  // Schema view of module `project_portal` (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
 
@@ -7,6 +7,7 @@ export interface SchemaView {
7
7
  readonly 'audit.event': AuditEvent;
8
8
  readonly 'auth.api_key': AuthApiKey;
9
9
  readonly 'auth.credential': AuthCredential;
10
+ readonly 'auth.policy': AuthPolicy;
10
11
  readonly 'auth.session': AuthSession;
11
12
  readonly 'auth.user_grant': AuthUserGrant;
12
13
  readonly 'auth.user_group': AuthUserGroup;
@@ -109,6 +110,26 @@ export interface AuthCredential {
109
110
  export interface AuthCredentialMethods extends F.Methods<typeof import('../../server/index.js').baseShutro, 'auth.credential'> {
110
111
  }
111
112
 
113
+ /** `auth.policy` (owner: base). */
114
+ export interface AuthPolicy {
115
+ readonly name: 'auth.policy';
116
+ readonly fields: {
117
+ readonly id: F.Id<'auth.policy'>;
118
+ readonly createdAt: F.Datetime<{ readonly required: true; readonly readonly: true }>;
119
+ readonly updatedAt: F.Datetime<{ readonly required: true; readonly readonly: true }>;
120
+ readonly createdBy: F.Many2one<'res.users', { readonly readonly: true }>;
121
+ readonly updatedBy: F.Many2one<'res.users', { readonly readonly: true }>;
122
+ readonly displayName: F.Char<{ readonly required: true; readonly readonly: true; readonly compute: true }>;
123
+ readonly twoFactor: F.Selection<'administrators' | 'everyone', { readonly required: true; readonly default: true }>;
124
+ readonly sessionDays: F.Integer;
125
+ };
126
+ readonly methods: AuthPolicyMethods;
127
+ }
128
+
129
+ /** Methods of `auth.policy`: declared ones and transitions. */
130
+ export interface AuthPolicyMethods extends F.Methods<typeof import('../../server/index.js').baseShutro, 'auth.policy'> {
131
+ }
132
+
112
133
  /** `auth.session` (owner: base). */
113
134
  export interface AuthSession {
114
135
  readonly name: 'auth.session';
@@ -578,6 +599,13 @@ export interface ResCompany {
578
599
  readonly name: F.Char<{ readonly required: true }>;
579
600
  readonly currency: F.Many2one<'res.currency', { readonly required: true }>;
580
601
  readonly numberGrouping: F.Selection<'international' | 'lakh', { readonly required: true; readonly default: true }>;
602
+ readonly accentColor: F.Char;
603
+ readonly street: F.Char;
604
+ readonly city: F.Char;
605
+ readonly zip: F.Char;
606
+ readonly email: F.Char;
607
+ readonly phone: F.Char;
608
+ readonly website: F.Char;
581
609
  };
582
610
  readonly methods: ResCompanyMethods;
583
611
  }
@@ -1,4 +1,4 @@
1
- // GENERATED by `pnpm generate:models` (Shutro’s generator). Do not edit. definitions-hash: c5ae4567ecbd3b97
1
+ // GENERATED by `pnpm generate:models` (Shutro’s generator). Do not edit. definitions-hash: 96928facddb91996
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: c5ae4567ecbd3b97
1
+ // GENERATED by `pnpm generate:models` (Shutro’s generator). Do not edit. definitions-hash: 96928facddb91996
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
 
@@ -11,6 +11,7 @@ export interface SchemaView {
11
11
  readonly 'audit.event': AuditEvent;
12
12
  readonly 'auth.api_key': AuthApiKey;
13
13
  readonly 'auth.credential': AuthCredential;
14
+ readonly 'auth.policy': AuthPolicy;
14
15
  readonly 'auth.session': AuthSession;
15
16
  readonly 'auth.user_grant': AuthUserGrant;
16
17
  readonly 'auth.user_group': AuthUserGroup;
@@ -219,6 +220,26 @@ export interface AuthCredential {
219
220
  export interface AuthCredentialMethods extends F.Methods<typeof import('../../server/index.js').baseShutro, 'auth.credential'> {
220
221
  }
221
222
 
223
+ /** `auth.policy` (owner: base). */
224
+ export interface AuthPolicy {
225
+ readonly name: 'auth.policy';
226
+ readonly fields: {
227
+ readonly id: F.Id<'auth.policy'>;
228
+ readonly createdAt: F.Datetime<{ readonly required: true; readonly readonly: true }>;
229
+ readonly updatedAt: F.Datetime<{ readonly required: true; readonly readonly: true }>;
230
+ readonly createdBy: F.Many2one<'res.users', { readonly readonly: true }>;
231
+ readonly updatedBy: F.Many2one<'res.users', { readonly readonly: true }>;
232
+ readonly displayName: F.Char<{ readonly required: true; readonly readonly: true; readonly compute: true }>;
233
+ readonly twoFactor: F.Selection<'administrators' | 'everyone', { readonly required: true; readonly default: true }>;
234
+ readonly sessionDays: F.Integer;
235
+ };
236
+ readonly methods: AuthPolicyMethods;
237
+ }
238
+
239
+ /** Methods of `auth.policy`: declared ones and transitions. */
240
+ export interface AuthPolicyMethods extends F.Methods<typeof import('../../server/index.js').baseShutro, 'auth.policy'> {
241
+ }
242
+
222
243
  /** `auth.session` (owner: base). */
223
244
  export interface AuthSession {
224
245
  readonly name: 'auth.session';
@@ -631,6 +652,13 @@ export interface ResCompany {
631
652
  readonly name: F.Char<{ readonly required: true }>;
632
653
  readonly currency: F.Many2one<'res.currency', { readonly required: true }>;
633
654
  readonly numberGrouping: F.Selection<'international' | 'lakh', { readonly required: true; readonly default: true }>;
655
+ readonly accentColor: F.Char;
656
+ readonly street: F.Char;
657
+ readonly city: F.Char;
658
+ readonly zip: F.Char;
659
+ readonly email: F.Char;
660
+ readonly phone: F.Char;
661
+ readonly website: F.Char;
634
662
  };
635
663
  readonly methods: ResCompanyMethods;
636
664
  }
@@ -1,4 +1,4 @@
1
- // GENERATED by `pnpm generate:models` (Shutro’s generator). Do not edit. definitions-hash: 81a33d0265524052
1
+ // GENERATED by `pnpm generate:models` (Shutro’s generator). Do not edit. definitions-hash: 637dfa1606a303a1
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';
@@ -1,4 +1,4 @@
1
- // GENERATED by `pnpm generate:models` (Shutro’s generator). Do not edit. definitions-hash: 81a33d0265524052
1
+ // GENERATED by `pnpm generate:models` (Shutro’s generator). Do not edit. definitions-hash: 637dfa1606a303a1
2
2
  // Schema view of module `purchase_account` (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
 
@@ -24,6 +24,7 @@ export interface SchemaView {
24
24
  readonly 'audit.event': AuditEvent;
25
25
  readonly 'auth.api_key': AuthApiKey;
26
26
  readonly 'auth.credential': AuthCredential;
27
+ readonly 'auth.policy': AuthPolicy;
27
28
  readonly 'auth.session': AuthSession;
28
29
  readonly 'auth.user_grant': AuthUserGrant;
29
30
  readonly 'auth.user_group': AuthUserGroup;
@@ -634,6 +635,26 @@ export interface AuthCredential {
634
635
  export interface AuthCredentialMethods extends F.Methods<typeof import('../../server/index.js').baseShutro, 'auth.credential'> {
635
636
  }
636
637
 
638
+ /** `auth.policy` (owner: base). */
639
+ export interface AuthPolicy {
640
+ readonly name: 'auth.policy';
641
+ readonly fields: {
642
+ readonly id: F.Id<'auth.policy'>;
643
+ readonly createdAt: F.Datetime<{ readonly required: true; readonly readonly: true }>;
644
+ readonly updatedAt: F.Datetime<{ readonly required: true; readonly readonly: true }>;
645
+ readonly createdBy: F.Many2one<'res.users', { readonly readonly: true }>;
646
+ readonly updatedBy: F.Many2one<'res.users', { readonly readonly: true }>;
647
+ readonly displayName: F.Char<{ readonly required: true; readonly readonly: true; readonly compute: true }>;
648
+ readonly twoFactor: F.Selection<'administrators' | 'everyone', { readonly required: true; readonly default: true }>;
649
+ readonly sessionDays: F.Integer;
650
+ };
651
+ readonly methods: AuthPolicyMethods;
652
+ }
653
+
654
+ /** Methods of `auth.policy`: declared ones and transitions. */
655
+ export interface AuthPolicyMethods extends F.Methods<typeof import('../../server/index.js').baseShutro, 'auth.policy'> {
656
+ }
657
+
637
658
  /** `auth.session` (owner: base). */
638
659
  export interface AuthSession {
639
660
  readonly name: 'auth.session';
@@ -1202,6 +1223,13 @@ export interface ResCompany {
1202
1223
  readonly name: F.Char<{ readonly required: true }>;
1203
1224
  readonly currency: F.Many2one<'res.currency', { readonly required: true }>;
1204
1225
  readonly numberGrouping: F.Selection<'international' | 'lakh', { readonly required: true; readonly default: true }>;
1226
+ readonly accentColor: F.Char;
1227
+ readonly street: F.Char;
1228
+ readonly city: F.Char;
1229
+ readonly zip: F.Char;
1230
+ readonly email: F.Char;
1231
+ readonly phone: F.Char;
1232
+ readonly website: F.Char;
1205
1233
  readonly fiscalYearStart: F.Integer<{ readonly required: true; readonly default: true }>; // accounting
1206
1234
  readonly chartTemplate: F.Char; // accounting
1207
1235
  readonly country: F.Char; // accounting
@@ -1,4 +1,4 @@
1
- // GENERATED by `pnpm generate:models` (Shutro’s generator). Do not edit. definitions-hash: 64da9b36804c7c1a
1
+ // GENERATED by `pnpm generate:models` (Shutro’s generator). Do not edit. definitions-hash: 2bbbe12acf870fd9
2
2
  // Bindings of module `purchase_portal`: 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';