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,28 @@
1
+ /**
2
+ * The bKash adapter (Tokenized Checkout v2; RFC 0017 §5.5). Grant a token (cached for its hour), create a payment
3
+ * (its `paymentId` kept as the transaction's provider reference) and send the customer to `bkashURL`. bKash has no
4
+ * server-to-server callback here: it sends the customer back to the return URL with `paymentID` and
5
+ * `status=success|failure|cancel`, and the payment completes only when the merchant **executes** it. The browser's
6
+ * status is a hint, never proof: on any return the adapter executes the transaction's own `paymentId` (never the
7
+ * one in the URL) and believes only bKash's answer — `Completed`, for this invoice number, amount and currency — or,
8
+ * when execute refuses, bKash's query.
9
+ *
10
+ * Credentials come from the environment, never from records: `SHUTRO_ERP_BKASH_USERNAME`, `…_PASSWORD`,
11
+ * `…_APP_KEY`, `…_APP_SECRET`, `…_SANDBOX` (`true` unless `false`) and, optionally, `…_BASE_URL`.
12
+ */
13
+ import type { PaymentAdapter } from './providers.js';
14
+ export interface BkashOptions {
15
+ readonly username?: string | undefined;
16
+ readonly password?: string | undefined;
17
+ readonly appKey?: string | undefined;
18
+ readonly appSecret?: string | undefined;
19
+ /** The sandbox (default) or the live system. */
20
+ readonly sandbox?: boolean;
21
+ /** The API's base, up to `/tokenized-checkout` (default: bKash's sandbox or live address). */
22
+ readonly baseUrl?: string | undefined;
23
+ /** The HTTP client (tests). */
24
+ readonly fetch?: typeof fetch;
25
+ }
26
+ export declare function bkashAdapter(options?: BkashOptions): PaymentAdapter;
27
+ /** bKash with its credentials from the environment, read on first use. */
28
+ export declare function bkashFromEnvironment(env?: NodeJS.ProcessEnv): PaymentAdapter;
@@ -0,0 +1,169 @@
1
+ const BASES = {
2
+ sandbox: 'https://tokenized.sandbox.bka.sh/v2/tokenized-checkout',
3
+ live: 'https://tokenized.pay.bka.sh/v2/tokenized-checkout',
4
+ };
5
+ /** bKash's code for executing a payment that is already completed. */
6
+ const ALREADY_COMPLETED = '2062';
7
+ const text = (v) => (v === undefined || v === null ? '' : String(v));
8
+ const same = (a, b) => a !== '' && b !== '' && Number(a).toFixed(2) === Number(b).toFixed(2);
9
+ export function bkashAdapter(options = {}) {
10
+ const sandbox = options.sandbox ?? true;
11
+ const base = (options.baseUrl || (sandbox ? BASES.sandbox : BASES.live)).replace(/\/$/, '');
12
+ const http = options.fetch ?? fetch;
13
+ const ready = [options.username, options.password, options.appKey, options.appSecret].every((v) => v !== undefined && v !== '');
14
+ let token = null;
15
+ const grant = async () => {
16
+ if (!ready)
17
+ throw new Error('bKash is not configured: set SHUTRO_ERP_BKASH_USERNAME, _PASSWORD, _APP_KEY and _APP_SECRET.');
18
+ if (token !== null && token.until > Date.now())
19
+ return token.value;
20
+ const res = await http(`${base}/auth/grant-token`, {
21
+ method: 'POST',
22
+ headers: {
23
+ 'content-type': 'application/json',
24
+ accept: 'application/json',
25
+ username: options.username,
26
+ password: options.password,
27
+ },
28
+ body: JSON.stringify({ app_key: options.appKey, app_secret: options.appSecret }),
29
+ signal: AbortSignal.timeout(30_000),
30
+ });
31
+ const answer = (await res.json().catch(() => ({})));
32
+ const value = text(answer['id_token']);
33
+ if (value === '')
34
+ throw new Error(`bKash refused the credentials: ${text(answer['statusMessage']) || res.status}.`);
35
+ // Kept for its lifetime less five minutes (an hour by default).
36
+ const seconds = Number(answer['expires_in'] ?? 3600);
37
+ token = { value, until: Date.now() + Math.max(60, seconds - 300) * 1000 };
38
+ return value;
39
+ };
40
+ const post = async (path, body) => {
41
+ const res = await http(`${base}${path}`, {
42
+ method: 'POST',
43
+ headers: {
44
+ 'content-type': 'application/json',
45
+ accept: 'application/json',
46
+ authorization: `Bearer ${await grant()}`,
47
+ 'x-app-key': options.appKey,
48
+ },
49
+ body: JSON.stringify(body),
50
+ signal: AbortSignal.timeout(30_000),
51
+ });
52
+ return (await res.json().catch(() => ({})));
53
+ };
54
+ /** bKash's word on a payment, checked against the transaction. */
55
+ const outcome = (reference, answer, expected = {}) => {
56
+ const status = text(answer['transactionStatus']);
57
+ const invoice = text(answer['merchantInvoiceNumber'] ?? answer['merchantInvoice']);
58
+ if (status !== 'Completed')
59
+ return null;
60
+ if (invoice !== reference ||
61
+ (expected.amount !== undefined && !same(text(answer['amount']), expected.amount)))
62
+ return {
63
+ reference,
64
+ status: 'failed',
65
+ providerReference: text(answer['trxId']) || null,
66
+ error: `bKash completed payment ${text(answer['paymentId'])} for ${invoice}, not this transaction.`,
67
+ };
68
+ return {
69
+ reference,
70
+ status: 'done',
71
+ providerReference: text(answer['trxId']) || null,
72
+ amount: text(answer['amount']),
73
+ currency: text(answer['currency']) || 'BDT',
74
+ };
75
+ };
76
+ const query = (paymentId) => post('/query/payment', { paymentId });
77
+ return {
78
+ code: 'bkash',
79
+ configured: (mode) => ready && (mode === 'test') === sandbox,
80
+ async createPayment(request) {
81
+ if (request.currency !== 'BDT')
82
+ throw new Error(`bKash takes payments in BDT only, not ${request.currency}.`);
83
+ const answer = await post('/payment/create', {
84
+ payerReference: request.customer.phone ?? request.reference,
85
+ callbackURL: request.returnUrl,
86
+ amount: request.amount,
87
+ currency: 'BDT',
88
+ intent: 'sale',
89
+ merchantInvoiceNumber: request.reference,
90
+ });
91
+ const paymentId = text(answer['paymentId'] ?? answer['paymentID']);
92
+ const page = text(answer['bkashURL'] ?? answer['bKashURL']);
93
+ if (paymentId === '' || page === '')
94
+ throw new Error(`bKash refused the payment: ${text(answer['errorMessageEn'] ?? answer['statusMessage']) || 'no payment id'}.`);
95
+ return { redirectUrl: page, providerReference: paymentId };
96
+ },
97
+ // No server-to-server callbacks: every call to the endpoint is refused.
98
+ verifyCallback: () => null,
99
+ readCallback: () => null,
100
+ async returned({ reference, providerReference, query: hint }) {
101
+ if (providerReference === null || providerReference === '')
102
+ return null;
103
+ if (hint['status'] === 'success') {
104
+ // Execute: the payment completes now, or bKash says why not.
105
+ const executed = await post('/payment/execute', { paymentId: providerReference });
106
+ const done = outcome(reference, executed);
107
+ if (done !== null)
108
+ return done;
109
+ const code = text(executed['externalCode'] ?? executed['statusCode']);
110
+ const known = await query(providerReference);
111
+ const completed = outcome(reference, known);
112
+ if (completed !== null)
113
+ return completed;
114
+ if (code === ALREADY_COMPLETED)
115
+ return null;
116
+ return {
117
+ reference,
118
+ status: 'failed',
119
+ providerReference,
120
+ error: text(executed['errorMessageEn'] ?? executed['statusMessage']) ||
121
+ 'bKash did not complete the payment.',
122
+ };
123
+ }
124
+ // Failed or cancelled on bKash's page — unless bKash says it completed.
125
+ const known = await query(providerReference);
126
+ const completed = outcome(reference, known);
127
+ if (completed !== null)
128
+ return completed;
129
+ return {
130
+ reference,
131
+ status: hint['status'] === 'cancel' ? 'cancelled' : 'failed',
132
+ providerReference,
133
+ ...(hint['status'] === 'cancel'
134
+ ? {}
135
+ : { error: 'The payment was not completed on bKash.' }),
136
+ };
137
+ },
138
+ async status(reference, _mode, providerReference) {
139
+ if (!ready || providerReference === null || providerReference === '')
140
+ return null;
141
+ const known = await query(providerReference);
142
+ return (outcome(reference, known) ??
143
+ (text(known['transactionStatus']) === 'Initiated'
144
+ ? { reference, status: 'pending', providerReference }
145
+ : null));
146
+ },
147
+ };
148
+ }
149
+ /** bKash with its credentials from the environment, read on first use. */
150
+ export function bkashFromEnvironment(env = process.env) {
151
+ let made;
152
+ const real = () => (made ??= bkashAdapter({
153
+ username: env['KOSH_BKASH_USERNAME'],
154
+ password: env['KOSH_BKASH_PASSWORD'],
155
+ appKey: env['KOSH_BKASH_APP_KEY'],
156
+ appSecret: env['KOSH_BKASH_APP_SECRET'],
157
+ sandbox: env['KOSH_BKASH_SANDBOX'] !== 'false',
158
+ baseUrl: env['KOSH_BKASH_BASE_URL'],
159
+ }));
160
+ return {
161
+ code: 'bkash',
162
+ configured: (mode) => real().configured(mode),
163
+ createPayment: (request) => real().createPayment(request),
164
+ verifyCallback: (call, secret) => real().verifyCallback(call, secret),
165
+ readCallback: (call) => real().readCallback(call),
166
+ returned: (input) => real().returned?.(input) ?? Promise.resolve(null),
167
+ status: (reference, mode, providerReference) => real().status(reference, mode, providerReference),
168
+ };
169
+ }
@@ -0,0 +1,38 @@
1
+ /**
2
+ * @packageDocumentation
3
+ * `shutro-erp/payment`: online payments (RFC 0017 §5.5, step 4). A company's payment providers (Accounting ›
4
+ * Configuration), Pay now on the portal's open invoices, the provider's callbacks through an inbound webhook (logged,
5
+ * idempotent, retried — `shutro-erp/integrations`), and the payment registered and reconciled in Accounting, once.
6
+ * Routes:
7
+ *
8
+ * - `GET /api/portal/v1/payments/providers` the providers a portal user may pay with
9
+ * - `POST /api/portal/v1/payments` `{ document, id, provider }`: a transaction; where to go
10
+ * - `GET /api/portal/v1/payments/:reference` its state (asking the provider while it is pending)
11
+ * - `GET /api/v1/payment/fake/checkout/:reference` the fake provider's checkout page
12
+ * - `POST /api/v1/payment/fake/checkout/:reference?outcome=paid|declined`
13
+ * - `GET|POST /api/v1/payment/return/:reference` back from the provider: on to the portal
14
+ *
15
+ * The callbacks arrive at `POST /api/v1/hooks/<token>` (the provider's endpoint, made with its first payment).
16
+ */
17
+ import { type KoshModule } from '../modules-sdk/index.js';
18
+ import { type PaymentAdapter } from './providers.js';
19
+ export { type BkashOptions, bkashAdapter, bkashFromEnvironment } from './bkash.js';
20
+ export { newReference, PaymentProvider, PaymentTransaction, PROVIDERS, paymentShutro, } from './module.js';
21
+ export { decimalsOf, fromSubunits, toSubunits } from './money.js';
22
+ export { ADAPTERS, FAKE_SIGNATURE, fakeAdapter, type PaymentAdapter, type PaymentRequest, type PaymentResult, type PaymentStatus, } from './providers.js';
23
+ export { type RazorpayOptions, razorpayAdapter, razorpayFromEnvironment } from './razorpay.js';
24
+ export { type Settled, settle } from './settle.js';
25
+ export { type SslcommerzOptions, sslcommerzAdapter, sslcommerzFromEnvironment, } from './sslcommerz.js';
26
+ export { type StripeOptions, stripeAdapter, stripeFromEnvironment } from './stripe.js';
27
+ export interface PaymentOptions {
28
+ /** The adapters by code (tests; default: the fake). */
29
+ readonly adapters?: ReadonlyMap<string, PaymentAdapter>;
30
+ /** The portal's address: where providers send customers back (`SHUTRO_ERP_PORTAL_URL`). */
31
+ readonly portalUrl?: string;
32
+ /** The API's public address: where providers call back (`SHUTRO_ERP_API_URL`). */
33
+ readonly apiUrl?: string;
34
+ }
35
+ /** Online payments with explicit options (tests, installations wiring their own adapters). */
36
+ export declare function paymentModule(options?: PaymentOptions): KoshModule;
37
+ /** Online payments (the fake adapter; addresses from the environment). */
38
+ export declare const payment: KoshModule;