shutro-erp 0.3.2 → 0.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/account_portal/.kosh/bindings.js +1 -1
- package/dist/account_portal/.kosh/schema.d.ts +156 -1
- package/dist/accounting/.kosh/bindings.js +1 -1
- package/dist/accounting/.kosh/schema.d.ts +156 -1
- package/dist/assistant/index.js +1 -1
- package/dist/contacts/.kosh/bindings.js +1 -1
- package/dist/contacts/.kosh/schema.d.ts +156 -1
- package/dist/integrations/index.js +12 -0
- package/dist/integrations/web/OAuthAppsPage.d.ts +9 -0
- package/dist/integrations/web/OAuthAppsPage.js +79 -0
- package/dist/integrations/web/index.d.ts +1 -0
- package/dist/integrations/web/index.js +3 -0
- package/dist/integrations/web/messages.js +58 -0
- package/dist/l10n_bd/.kosh/bindings.js +1 -1
- package/dist/l10n_bd/.kosh/schema.d.ts +156 -1
- package/dist/l10n_in/.kosh/bindings.js +1 -1
- package/dist/l10n_in/.kosh/schema.d.ts +156 -4
- package/dist/l10n_in/module.d.ts +0 -62
- package/dist/l10n_in/module.js +2 -4
- package/dist/messaging/web/index.js +1 -1
- package/dist/notify/web/index.js +1 -1
- package/dist/payment/.kosh/bindings.js +1 -1
- package/dist/payment/.kosh/schema.d.ts +157 -2
- package/dist/payment/bkash.d.ts +28 -0
- package/dist/payment/bkash.js +169 -0
- package/dist/payment/index.d.ts +4 -0
- package/dist/payment/index.js +80 -24
- package/dist/payment/module.d.ts +7 -4
- package/dist/payment/module.js +3 -0
- package/dist/payment/money.d.ts +7 -0
- package/dist/payment/money.js +37 -0
- package/dist/payment/providers.d.ts +13 -2
- package/dist/payment/razorpay.d.ts +12 -0
- package/dist/payment/razorpay.js +149 -0
- package/dist/payment/sslcommerz.js +1 -1
- package/dist/payment/stripe.d.ts +15 -0
- package/dist/payment/stripe.js +182 -0
- package/dist/permissions/admin.d.ts +3 -0
- package/dist/permissions/admin.js +108 -10
- package/dist/permissions/index.d.ts +1 -0
- package/dist/permissions/index.js +3 -0
- package/dist/permissions/roles.d.ts +2 -0
- package/dist/permissions/roles.js +236 -0
- package/dist/portal/.kosh/bindings.js +1 -1
- package/dist/portal/.kosh/schema.d.ts +156 -1
- package/dist/product/.kosh/bindings.js +1 -1
- package/dist/product/.kosh/schema.d.ts +156 -1
- package/dist/project/.kosh/bindings.js +1 -1
- package/dist/project/.kosh/schema.d.ts +156 -1
- package/dist/project_portal/.kosh/bindings.js +1 -1
- package/dist/project_portal/.kosh/schema.d.ts +156 -1
- package/dist/purchase/.kosh/bindings.js +1 -1
- package/dist/purchase/.kosh/schema.d.ts +156 -1
- package/dist/purchase_account/.kosh/bindings.js +1 -1
- package/dist/purchase_account/.kosh/schema.d.ts +156 -1
- package/dist/purchase_portal/.kosh/bindings.js +1 -1
- package/dist/purchase_portal/.kosh/schema.d.ts +156 -1
- package/dist/sale_account/.kosh/bindings.js +1 -1
- package/dist/sale_account/.kosh/schema.d.ts +156 -1
- package/dist/sale_portal/.kosh/bindings.js +1 -1
- package/dist/sale_portal/.kosh/schema.d.ts +156 -1
- package/dist/sale_project/.kosh/bindings.js +1 -1
- package/dist/sale_project/.kosh/schema.d.ts +156 -1
- package/dist/sales/.kosh/bindings.js +1 -1
- package/dist/sales/.kosh/schema.d.ts +156 -1
- package/dist/server/auth/base.js +98 -0
- package/dist/server/auth/oauth.d.ts +21 -0
- package/dist/server/auth/oauth.js +579 -0
- package/dist/server/auth/routes.d.ts +3 -0
- package/dist/server/auth/routes.js +29 -0
- package/dist/server/auth/service.d.ts +56 -0
- package/dist/server/auth/service.js +185 -3
- package/dist/server/identity.d.ts +4 -0
- package/dist/server/images.d.ts +12 -0
- package/dist/server/images.js +139 -0
- package/dist/server/index.d.ts +2 -1
- package/dist/server/index.js +1 -0
- package/dist/server/server.d.ts +4 -0
- package/dist/server/server.js +20 -4
- package/dist/settings/company.d.ts +34 -0
- package/dist/settings/company.js +189 -0
- package/dist/settings/index.d.ts +10 -10
- package/dist/settings/index.js +159 -30
- package/dist/settings/people.d.ts +16 -0
- package/dist/settings/people.js +507 -0
- package/dist/settings/security.d.ts +13 -0
- package/dist/settings/security.js +158 -0
- package/dist/settings/web/AuditPage.d.ts +8 -0
- package/dist/settings/web/AuditPage.js +74 -0
- package/dist/settings/web/CompaniesPage.d.ts +8 -0
- package/dist/settings/web/CompaniesPage.js +52 -0
- package/dist/settings/web/CompanyPage.d.ts +9 -0
- package/dist/settings/web/CompanyPage.js +105 -0
- package/dist/settings/web/ConnectedAppsPage.d.ts +7 -0
- package/dist/settings/web/ConnectedAppsPage.js +33 -0
- package/dist/settings/web/OverviewPage.d.ts +9 -0
- package/dist/settings/web/OverviewPage.js +77 -0
- package/dist/settings/web/PeoplePage.d.ts +9 -0
- package/dist/settings/web/PeoplePage.js +154 -0
- package/dist/settings/web/ProfilePage.d.ts +14 -0
- package/dist/settings/web/ProfilePage.js +196 -0
- package/dist/settings/web/RolesEditor.d.ts +35 -0
- package/dist/settings/web/RolesEditor.js +49 -0
- package/dist/settings/web/RolesPage.d.ts +9 -0
- package/dist/settings/web/RolesPage.js +296 -0
- package/dist/settings/web/SecurityPage.d.ts +8 -0
- package/dist/settings/web/SecurityPage.js +81 -0
- package/dist/settings/web/index.d.ts +10 -0
- package/dist/settings/web/index.js +31 -1
- package/dist/settings/web/messages.js +594 -0
- package/dist/ui/api.d.ts +8 -0
- package/dist/ui/app.d.ts +5 -0
- package/dist/ui/app.js +143 -33
- package/dist/ui/components/AppIcon.js +11 -1
- package/dist/ui/components/Avatar.d.ts +21 -0
- package/dist/ui/components/Avatar.js +71 -0
- package/dist/ui/components/primitives.d.ts +9 -1
- package/dist/ui/components/primitives.js +12 -4
- package/dist/ui/context.d.ts +10 -1
- package/dist/ui/context.js +60 -2
- package/dist/ui/i18n/messages.d.ts +76 -0
- package/dist/ui/i18n/messages.js +152 -0
- package/dist/ui/index.d.ts +3 -1
- package/dist/ui/index.js +3 -1
- package/dist/ui/lib/accent.d.ts +13 -0
- package/dist/ui/lib/accent.js +36 -0
- package/dist/ui/registry.d.ts +7 -1
- package/dist/ui/registry.js +10 -1
- package/dist/ui/search/ViewTabs.d.ts +14 -0
- package/dist/ui/search/ViewTabs.js +42 -0
- package/dist/ui/shell/Activate.d.ts +6 -0
- package/dist/ui/shell/Activate.js +39 -0
- package/dist/ui/shell/CommandPalette.d.ts +7 -1
- package/dist/ui/shell/CommandPalette.js +16 -2
- package/dist/ui/shell/Consent.d.ts +5 -0
- package/dist/ui/shell/Consent.js +35 -0
- package/dist/ui/shell/Home.js +85 -16
- package/dist/ui/shell/Sidebar.d.ts +27 -0
- package/dist/ui/shell/Sidebar.js +77 -0
- package/dist/ui/shell/TwoFactorSetup.d.ts +5 -0
- package/dist/ui/shell/TwoFactorSetup.js +32 -0
- package/dist/ui/shell/shortcuts.d.ts +3 -0
- package/dist/ui/shell/shortcuts.js +13 -4
- package/dist/ui/styles.css +70 -28
- package/dist/ui/views/DateField.d.ts +10 -0
- package/dist/ui/views/DateField.js +129 -0
- package/dist/ui/views/FormView.js +161 -21
- package/dist/ui/views/ListView.d.ts +2 -0
- package/dist/ui/views/ListView.js +57 -25
- package/dist/ui/views/StatusChip.d.ts +10 -0
- package/dist/ui/views/StatusChip.js +22 -0
- package/dist/ui/views/widgets.d.ts +3 -0
- package/dist/ui/views/widgets.js +26 -8
- package/dist/views/types.d.ts +7 -0
- package/dist/views/validate.js +4 -0
- package/package.json +2 -2
package/dist/l10n_in/module.d.ts
CHANGED
|
@@ -51,37 +51,6 @@ export declare const CompanyGst: import("../server/orm.js").Extension<"res.compa
|
|
|
51
51
|
readonly hasDefault: false;
|
|
52
52
|
readonly readonly: false;
|
|
53
53
|
}, string>;
|
|
54
|
-
/** Its principal place of business: the seller's address on e-invoices and e-way bills. */
|
|
55
|
-
readonly street: import("../server/orm.js").CharField<{
|
|
56
|
-
readonly required: false;
|
|
57
|
-
readonly computed: false;
|
|
58
|
-
readonly inverse: false;
|
|
59
|
-
readonly sequence: false;
|
|
60
|
-
readonly computeName: undefined;
|
|
61
|
-
readonly store: true;
|
|
62
|
-
readonly hasDefault: false;
|
|
63
|
-
readonly readonly: false;
|
|
64
|
-
}, string>;
|
|
65
|
-
readonly city: import("../server/orm.js").CharField<{
|
|
66
|
-
readonly required: false;
|
|
67
|
-
readonly computed: false;
|
|
68
|
-
readonly inverse: false;
|
|
69
|
-
readonly sequence: false;
|
|
70
|
-
readonly computeName: undefined;
|
|
71
|
-
readonly store: true;
|
|
72
|
-
readonly hasDefault: false;
|
|
73
|
-
readonly readonly: false;
|
|
74
|
-
}, string>;
|
|
75
|
-
readonly zip: import("../server/orm.js").CharField<{
|
|
76
|
-
readonly required: false;
|
|
77
|
-
readonly computed: false;
|
|
78
|
-
readonly inverse: false;
|
|
79
|
-
readonly sequence: false;
|
|
80
|
-
readonly computeName: undefined;
|
|
81
|
-
readonly store: true;
|
|
82
|
-
readonly hasDefault: false;
|
|
83
|
-
readonly readonly: false;
|
|
84
|
-
}, string>;
|
|
85
54
|
/** Customer invoices and notes are registered with the IRP when posted (turnover above the threshold). */
|
|
86
55
|
readonly einvoiceEnabled: import("../server/orm.js").ScalarField<"boolean", boolean, boolean, {
|
|
87
56
|
readonly required: true;
|
|
@@ -7506,37 +7475,6 @@ export declare const l10nInShutro: import("../server/orm.js").Module<readonly [i
|
|
|
7506
7475
|
readonly hasDefault: false;
|
|
7507
7476
|
readonly readonly: false;
|
|
7508
7477
|
}, string>;
|
|
7509
|
-
/** Its principal place of business: the seller's address on e-invoices and e-way bills. */
|
|
7510
|
-
readonly street: import("../server/orm.js").CharField<{
|
|
7511
|
-
readonly required: false;
|
|
7512
|
-
readonly computed: false;
|
|
7513
|
-
readonly inverse: false;
|
|
7514
|
-
readonly sequence: false;
|
|
7515
|
-
readonly computeName: undefined;
|
|
7516
|
-
readonly store: true;
|
|
7517
|
-
readonly hasDefault: false;
|
|
7518
|
-
readonly readonly: false;
|
|
7519
|
-
}, string>;
|
|
7520
|
-
readonly city: import("../server/orm.js").CharField<{
|
|
7521
|
-
readonly required: false;
|
|
7522
|
-
readonly computed: false;
|
|
7523
|
-
readonly inverse: false;
|
|
7524
|
-
readonly sequence: false;
|
|
7525
|
-
readonly computeName: undefined;
|
|
7526
|
-
readonly store: true;
|
|
7527
|
-
readonly hasDefault: false;
|
|
7528
|
-
readonly readonly: false;
|
|
7529
|
-
}, string>;
|
|
7530
|
-
readonly zip: import("../server/orm.js").CharField<{
|
|
7531
|
-
readonly required: false;
|
|
7532
|
-
readonly computed: false;
|
|
7533
|
-
readonly inverse: false;
|
|
7534
|
-
readonly sequence: false;
|
|
7535
|
-
readonly computeName: undefined;
|
|
7536
|
-
readonly store: true;
|
|
7537
|
-
readonly hasDefault: false;
|
|
7538
|
-
readonly readonly: false;
|
|
7539
|
-
}, string>;
|
|
7540
7478
|
/** Customer invoices and notes are registered with the IRP when posted (turnover above the threshold). */
|
|
7541
7479
|
readonly einvoiceEnabled: import("../server/orm.js").ScalarField<"boolean", boolean, boolean, {
|
|
7542
7480
|
readonly required: true;
|
package/dist/l10n_in/module.js
CHANGED
|
@@ -101,10 +101,8 @@ export const CompanyGst = extendModel('res.company', {
|
|
|
101
101
|
fields: {
|
|
102
102
|
gstin: f.char({ size: 15, label: 'GSTIN' }),
|
|
103
103
|
pan: f.char({ size: 10, label: 'PAN' }),
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
city: f.char({ label: 'City' }),
|
|
107
|
-
zip: f.char({ size: 6, label: 'PIN code' }),
|
|
104
|
+
// Its principal place of business (`street`, `city`, `zip`: the base's company address) is the seller's
|
|
105
|
+
// address on e-invoices and e-way bills.
|
|
108
106
|
/** Customer invoices and notes are registered with the IRP when posted (turnover above the threshold). */
|
|
109
107
|
einvoiceEnabled: f.boolean({ required: true, default: false, label: 'E-invoicing' }),
|
|
110
108
|
},
|
|
@@ -16,7 +16,7 @@ export { Chatter } from './Chatter.js';
|
|
|
16
16
|
export function registerMessagingWeb(registry, i18n) {
|
|
17
17
|
registry.registerComponent('chatter', Chatter);
|
|
18
18
|
registry.registerPage('messaging.Chat', ChatPage);
|
|
19
|
-
registry.registerHeaderItem('messaging.Dock', ChatDock);
|
|
19
|
+
registry.registerHeaderItem('messaging.Dock', ChatDock, { home: true });
|
|
20
20
|
if (i18n !== undefined)
|
|
21
21
|
addMessages(i18n, 'messaging', messages);
|
|
22
22
|
return registry;
|
package/dist/notify/web/index.js
CHANGED
|
@@ -10,7 +10,7 @@ export { NotificationSettings } from './NotificationSettings.js';
|
|
|
10
10
|
export { usePush } from './push.js';
|
|
11
11
|
/** Registers the bell (and its messages in `i18n`, when given). */
|
|
12
12
|
export function registerNotifyWeb(registry, i18n) {
|
|
13
|
-
registry.registerHeaderItem('notify.Bell', NotificationBell);
|
|
13
|
+
registry.registerHeaderItem('notify.Bell', NotificationBell, { home: true });
|
|
14
14
|
if (i18n !== undefined)
|
|
15
15
|
addMessages(i18n, 'notify', messages);
|
|
16
16
|
return registry;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// GENERATED by `pnpm generate:models` (Shutro’s generator). Do not edit. definitions-hash:
|
|
1
|
+
// GENERATED by `pnpm generate:models` (Shutro’s generator). Do not edit. definitions-hash: 7de15337289f5e89
|
|
2
2
|
// Bindings of module `payment`: 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:
|
|
1
|
+
// GENERATED by `pnpm generate:models` (Shutro’s generator). Do not edit. definitions-hash: 7de15337289f5e89
|
|
2
2
|
// Schema view of module `payment` (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,9 +24,11 @@ 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;
|
|
31
|
+
readonly 'kosh.image': KoshImage;
|
|
30
32
|
readonly 'kosh.saved_view': KoshSavedView;
|
|
31
33
|
readonly 'mail.activity': MailActivity;
|
|
32
34
|
readonly 'mail.activity.type': MailActivityType;
|
|
@@ -35,6 +37,10 @@ export interface SchemaView {
|
|
|
35
37
|
readonly 'mail.follower': MailFollower;
|
|
36
38
|
readonly 'mail.message': MailMessage;
|
|
37
39
|
readonly 'mail.message.reaction': MailMessageReaction;
|
|
40
|
+
readonly 'oauth.app': OauthApp;
|
|
41
|
+
readonly 'oauth.code': OauthCode;
|
|
42
|
+
readonly 'oauth.grant': OauthGrant;
|
|
43
|
+
readonly 'oauth.token': OauthToken;
|
|
38
44
|
readonly 'payment.provider': PaymentProvider;
|
|
39
45
|
readonly 'payment.transaction': PaymentTransaction;
|
|
40
46
|
readonly 'portal.announcement': PortalAnnouncement;
|
|
@@ -640,6 +646,26 @@ export interface AuthCredential {
|
|
|
640
646
|
export interface AuthCredentialMethods extends F.Methods<typeof import('../../server/index.js').baseShutro, 'auth.credential'> {
|
|
641
647
|
}
|
|
642
648
|
|
|
649
|
+
/** `auth.policy` (owner: base). */
|
|
650
|
+
export interface AuthPolicy {
|
|
651
|
+
readonly name: 'auth.policy';
|
|
652
|
+
readonly fields: {
|
|
653
|
+
readonly id: F.Id<'auth.policy'>;
|
|
654
|
+
readonly createdAt: F.Datetime<{ readonly required: true; readonly readonly: true }>;
|
|
655
|
+
readonly updatedAt: F.Datetime<{ readonly required: true; readonly readonly: true }>;
|
|
656
|
+
readonly createdBy: F.Many2one<'res.users', { readonly readonly: true }>;
|
|
657
|
+
readonly updatedBy: F.Many2one<'res.users', { readonly readonly: true }>;
|
|
658
|
+
readonly displayName: F.Char<{ readonly required: true; readonly readonly: true; readonly compute: true }>;
|
|
659
|
+
readonly twoFactor: F.Selection<'administrators' | 'everyone', { readonly required: true; readonly default: true }>;
|
|
660
|
+
readonly sessionDays: F.Integer;
|
|
661
|
+
};
|
|
662
|
+
readonly methods: AuthPolicyMethods;
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
/** Methods of `auth.policy`: declared ones and transitions. */
|
|
666
|
+
export interface AuthPolicyMethods extends F.Methods<typeof import('../../server/index.js').baseShutro, 'auth.policy'> {
|
|
667
|
+
}
|
|
668
|
+
|
|
643
669
|
/** `auth.session` (owner: base). */
|
|
644
670
|
export interface AuthSession {
|
|
645
671
|
readonly name: 'auth.session';
|
|
@@ -712,6 +738,29 @@ export interface AuthUserGroup {
|
|
|
712
738
|
export interface AuthUserGroupMethods extends F.Methods<typeof import('../../server/index.js').baseShutro, 'auth.user_group'> {
|
|
713
739
|
}
|
|
714
740
|
|
|
741
|
+
/** `kosh.image` (owner: base). */
|
|
742
|
+
export interface KoshImage {
|
|
743
|
+
readonly name: 'kosh.image';
|
|
744
|
+
readonly fields: {
|
|
745
|
+
readonly id: F.Id<'kosh.image'>;
|
|
746
|
+
readonly createdAt: F.Datetime<{ readonly required: true; readonly readonly: true }>;
|
|
747
|
+
readonly updatedAt: F.Datetime<{ readonly required: true; readonly readonly: true }>;
|
|
748
|
+
readonly createdBy: F.Many2one<'res.users', { readonly readonly: true }>;
|
|
749
|
+
readonly updatedBy: F.Many2one<'res.users', { readonly readonly: true }>;
|
|
750
|
+
readonly displayName: F.Char<{ readonly required: true; readonly readonly: true; readonly compute: true }>;
|
|
751
|
+
readonly ownerModel: F.Char<{ readonly required: true }>;
|
|
752
|
+
readonly ownerId: F.Integer<{ readonly required: true }>;
|
|
753
|
+
readonly mime: F.Char<{ readonly required: true }>;
|
|
754
|
+
readonly data: F.Text<{ readonly required: true }>;
|
|
755
|
+
readonly hash: F.Char<{ readonly required: true }>;
|
|
756
|
+
};
|
|
757
|
+
readonly methods: KoshImageMethods;
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
/** Methods of `kosh.image`: declared ones and transitions. */
|
|
761
|
+
export interface KoshImageMethods extends F.Methods<typeof import('../../server/index.js').baseShutro, 'kosh.image'> {
|
|
762
|
+
}
|
|
763
|
+
|
|
715
764
|
/** `kosh.saved_view` (owner: base). */
|
|
716
765
|
export interface KoshSavedView {
|
|
717
766
|
readonly name: 'kosh.saved_view';
|
|
@@ -914,6 +963,105 @@ export interface MailMessageReaction {
|
|
|
914
963
|
export interface MailMessageReactionMethods extends F.Methods<typeof import('../../messaging/index.js').messagingShutro, 'mail.message.reaction'> {
|
|
915
964
|
}
|
|
916
965
|
|
|
966
|
+
/** `oauth.app` (owner: base). */
|
|
967
|
+
export interface OauthApp {
|
|
968
|
+
readonly name: 'oauth.app';
|
|
969
|
+
readonly fields: {
|
|
970
|
+
readonly id: F.Id<'oauth.app'>;
|
|
971
|
+
readonly createdAt: F.Datetime<{ readonly required: true; readonly readonly: true }>;
|
|
972
|
+
readonly updatedAt: F.Datetime<{ readonly required: true; readonly readonly: true }>;
|
|
973
|
+
readonly createdBy: F.Many2one<'res.users', { readonly readonly: true }>;
|
|
974
|
+
readonly updatedBy: F.Many2one<'res.users', { readonly readonly: true }>;
|
|
975
|
+
readonly displayName: F.Char<{ readonly required: true; readonly readonly: true; readonly compute: true }>;
|
|
976
|
+
readonly name: F.Char<{ readonly required: true }>;
|
|
977
|
+
readonly clientId: F.Char<{ readonly required: true }>;
|
|
978
|
+
readonly secretHash: F.Char;
|
|
979
|
+
readonly confidential: F.Bool<{ readonly required: true; readonly default: true }>;
|
|
980
|
+
readonly redirectUris: F.Text<{ readonly required: true }>;
|
|
981
|
+
readonly scopes: F.Char<{ readonly required: true }>;
|
|
982
|
+
readonly homepage: F.Char;
|
|
983
|
+
readonly active: F.Bool<{ readonly required: true; readonly default: true }>;
|
|
984
|
+
readonly owner: F.Many2one<'res.users'>;
|
|
985
|
+
};
|
|
986
|
+
readonly methods: OauthAppMethods;
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
/** Methods of `oauth.app`: declared ones and transitions. */
|
|
990
|
+
export interface OauthAppMethods extends F.Methods<typeof import('../../server/index.js').baseShutro, 'oauth.app'> {
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
/** `oauth.code` (owner: base). */
|
|
994
|
+
export interface OauthCode {
|
|
995
|
+
readonly name: 'oauth.code';
|
|
996
|
+
readonly fields: {
|
|
997
|
+
readonly id: F.Id<'oauth.code'>;
|
|
998
|
+
readonly createdAt: F.Datetime<{ readonly required: true; readonly readonly: true }>;
|
|
999
|
+
readonly updatedAt: F.Datetime<{ readonly required: true; readonly readonly: true }>;
|
|
1000
|
+
readonly createdBy: F.Many2one<'res.users', { readonly readonly: true }>;
|
|
1001
|
+
readonly updatedBy: F.Many2one<'res.users', { readonly readonly: true }>;
|
|
1002
|
+
readonly displayName: F.Char<{ readonly required: true; readonly readonly: true; readonly compute: true }>;
|
|
1003
|
+
readonly codeHash: F.Char<{ readonly required: true }>;
|
|
1004
|
+
readonly grant: F.Many2one<'oauth.grant', { readonly required: true }>;
|
|
1005
|
+
readonly redirectUri: F.Char<{ readonly required: true }>;
|
|
1006
|
+
readonly challenge: F.Char;
|
|
1007
|
+
readonly expiresAt: F.Datetime<{ readonly required: true }>;
|
|
1008
|
+
readonly used: F.Bool<{ readonly required: true; readonly default: true }>;
|
|
1009
|
+
};
|
|
1010
|
+
readonly methods: OauthCodeMethods;
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
/** Methods of `oauth.code`: declared ones and transitions. */
|
|
1014
|
+
export interface OauthCodeMethods extends F.Methods<typeof import('../../server/index.js').baseShutro, 'oauth.code'> {
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
/** `oauth.grant` (owner: base). */
|
|
1018
|
+
export interface OauthGrant {
|
|
1019
|
+
readonly name: 'oauth.grant';
|
|
1020
|
+
readonly fields: {
|
|
1021
|
+
readonly id: F.Id<'oauth.grant'>;
|
|
1022
|
+
readonly createdAt: F.Datetime<{ readonly required: true; readonly readonly: true }>;
|
|
1023
|
+
readonly updatedAt: F.Datetime<{ readonly required: true; readonly readonly: true }>;
|
|
1024
|
+
readonly createdBy: F.Many2one<'res.users', { readonly readonly: true }>;
|
|
1025
|
+
readonly updatedBy: F.Many2one<'res.users', { readonly readonly: true }>;
|
|
1026
|
+
readonly displayName: F.Char<{ readonly required: true; readonly readonly: true; readonly compute: true }>;
|
|
1027
|
+
readonly user: F.Many2one<'res.users', { readonly required: true }>;
|
|
1028
|
+
readonly app: F.Many2one<'oauth.app', { readonly required: true }>;
|
|
1029
|
+
readonly scopes: F.Char<{ readonly required: true }>;
|
|
1030
|
+
readonly revoked: F.Bool<{ readonly required: true; readonly default: true }>;
|
|
1031
|
+
readonly lastUsedAt: F.Datetime;
|
|
1032
|
+
};
|
|
1033
|
+
readonly methods: OauthGrantMethods;
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
/** Methods of `oauth.grant`: declared ones and transitions. */
|
|
1037
|
+
export interface OauthGrantMethods extends F.Methods<typeof import('../../server/index.js').baseShutro, 'oauth.grant'> {
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
/** `oauth.token` (owner: base). */
|
|
1041
|
+
export interface OauthToken {
|
|
1042
|
+
readonly name: 'oauth.token';
|
|
1043
|
+
readonly fields: {
|
|
1044
|
+
readonly id: F.Id<'oauth.token'>;
|
|
1045
|
+
readonly createdAt: F.Datetime<{ readonly required: true; readonly readonly: true }>;
|
|
1046
|
+
readonly updatedAt: F.Datetime<{ readonly required: true; readonly readonly: true }>;
|
|
1047
|
+
readonly createdBy: F.Many2one<'res.users', { readonly readonly: true }>;
|
|
1048
|
+
readonly updatedBy: F.Many2one<'res.users', { readonly readonly: true }>;
|
|
1049
|
+
readonly displayName: F.Char<{ readonly required: true; readonly readonly: true; readonly compute: true }>;
|
|
1050
|
+
readonly grant: F.Many2one<'oauth.grant', { readonly required: true }>;
|
|
1051
|
+
readonly accessHash: F.Char<{ readonly required: true }>;
|
|
1052
|
+
readonly refreshHash: F.Char<{ readonly required: true }>;
|
|
1053
|
+
readonly accessExpiresAt: F.Datetime<{ readonly required: true }>;
|
|
1054
|
+
readonly refreshExpiresAt: F.Datetime<{ readonly required: true }>;
|
|
1055
|
+
readonly revoked: F.Bool<{ readonly required: true; readonly default: true }>;
|
|
1056
|
+
readonly rotated: F.Bool<{ readonly required: true; readonly default: true }>;
|
|
1057
|
+
};
|
|
1058
|
+
readonly methods: OauthTokenMethods;
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
/** Methods of `oauth.token`: declared ones and transitions. */
|
|
1062
|
+
export interface OauthTokenMethods extends F.Methods<typeof import('../../server/index.js').baseShutro, 'oauth.token'> {
|
|
1063
|
+
}
|
|
1064
|
+
|
|
917
1065
|
/** `payment.provider` (owner: payment). */
|
|
918
1066
|
export interface PaymentProvider {
|
|
919
1067
|
readonly name: 'payment.provider';
|
|
@@ -926,7 +1074,7 @@ export interface PaymentProvider {
|
|
|
926
1074
|
readonly displayName: F.Char<{ readonly required: true; readonly readonly: true; readonly compute: true }>;
|
|
927
1075
|
readonly company: F.Many2one<'res.company', { readonly required: true; readonly default: true }>;
|
|
928
1076
|
readonly name: F.Char<{ readonly required: true }>;
|
|
929
|
-
readonly code: F.Selection<'fake' | 'sslcommerz', { readonly required: true; readonly default: true }>;
|
|
1077
|
+
readonly code: F.Selection<'fake' | 'sslcommerz' | 'bkash' | 'razorpay' | 'stripe', { readonly required: true; readonly default: true }>;
|
|
930
1078
|
readonly state: F.Selection<'disabled' | 'test' | 'live', { readonly required: true; readonly default: true }>;
|
|
931
1079
|
readonly journal: F.Many2one<'account.journal', { readonly required: true }>;
|
|
932
1080
|
readonly endpoint: F.Many2one<'webhook.endpoint'>;
|
|
@@ -1261,6 +1409,13 @@ export interface ResCompany {
|
|
|
1261
1409
|
readonly name: F.Char<{ readonly required: true }>;
|
|
1262
1410
|
readonly currency: F.Many2one<'res.currency', { readonly required: true }>;
|
|
1263
1411
|
readonly numberGrouping: F.Selection<'international' | 'lakh', { readonly required: true; readonly default: true }>;
|
|
1412
|
+
readonly accentColor: F.Char;
|
|
1413
|
+
readonly street: F.Char;
|
|
1414
|
+
readonly city: F.Char;
|
|
1415
|
+
readonly zip: F.Char;
|
|
1416
|
+
readonly email: F.Char;
|
|
1417
|
+
readonly phone: F.Char;
|
|
1418
|
+
readonly website: F.Char;
|
|
1264
1419
|
readonly fiscalYearStart: F.Integer<{ readonly required: true; readonly default: true }>; // accounting
|
|
1265
1420
|
readonly chartTemplate: F.Char; // accounting
|
|
1266
1421
|
readonly country: F.Char; // accounting
|
|
@@ -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
|
+
}
|
package/dist/payment/index.d.ts
CHANGED
|
@@ -16,10 +16,14 @@
|
|
|
16
16
|
*/
|
|
17
17
|
import { type KoshModule } from '../modules-sdk/index.js';
|
|
18
18
|
import { type PaymentAdapter } from './providers.js';
|
|
19
|
+
export { type BkashOptions, bkashAdapter, bkashFromEnvironment } from './bkash.js';
|
|
19
20
|
export { newReference, PaymentProvider, PaymentTransaction, PROVIDERS, paymentShutro, } from './module.js';
|
|
21
|
+
export { decimalsOf, fromSubunits, toSubunits } from './money.js';
|
|
20
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';
|
|
21
24
|
export { type Settled, settle } from './settle.js';
|
|
22
25
|
export { type SslcommerzOptions, sslcommerzAdapter, sslcommerzFromEnvironment, } from './sslcommerz.js';
|
|
26
|
+
export { type StripeOptions, stripeAdapter, stripeFromEnvironment } from './stripe.js';
|
|
23
27
|
export interface PaymentOptions {
|
|
24
28
|
/** The adapters by code (tests; default: the fake). */
|
|
25
29
|
readonly adapters?: ReadonlyMap<string, PaymentAdapter>;
|