payment-kit 1.20.5 → 1.20.6
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/api/src/crons/index.ts +11 -3
- package/api/src/index.ts +18 -14
- package/api/src/libs/adapters/launcher-adapter.ts +177 -0
- package/api/src/libs/env.ts +7 -0
- package/api/src/libs/url.ts +77 -0
- package/api/src/libs/vendor-adapter-factory.ts +22 -0
- package/api/src/libs/vendor-adapter.ts +109 -0
- package/api/src/libs/vendor-fulfillment.ts +321 -0
- package/api/src/queues/payment.ts +14 -10
- package/api/src/queues/payout.ts +1 -0
- package/api/src/queues/vendor/vendor-commission.ts +192 -0
- package/api/src/queues/vendor/vendor-fulfillment-coordinator.ts +627 -0
- package/api/src/queues/vendor/vendor-fulfillment.ts +97 -0
- package/api/src/queues/vendor/vendor-status-check.ts +179 -0
- package/api/src/routes/checkout-sessions.ts +3 -0
- package/api/src/routes/index.ts +2 -0
- package/api/src/routes/products.ts +72 -1
- package/api/src/routes/vendor.ts +526 -0
- package/api/src/store/migrations/20250820-add-product-vendor.ts +102 -0
- package/api/src/store/migrations/20250822-add-vendor-config-to-products.ts +56 -0
- package/api/src/store/models/checkout-session.ts +84 -18
- package/api/src/store/models/index.ts +3 -0
- package/api/src/store/models/payout.ts +11 -0
- package/api/src/store/models/product-vendor.ts +118 -0
- package/api/src/store/models/product.ts +15 -0
- package/blocklet.yml +8 -2
- package/doc/vendor_fulfillment_system.md +931 -0
- package/package.json +5 -4
- package/src/components/collapse.tsx +1 -0
- package/src/components/product/edit.tsx +9 -0
- package/src/components/product/form.tsx +11 -0
- package/src/components/product/vendor-config.tsx +249 -0
- package/src/components/vendor/actions.tsx +145 -0
- package/src/locales/en.tsx +89 -0
- package/src/locales/zh.tsx +89 -0
- package/src/pages/admin/products/index.tsx +11 -1
- package/src/pages/admin/products/products/detail.tsx +79 -2
- package/src/pages/admin/products/vendors/create.tsx +418 -0
- package/src/pages/admin/products/vendors/index.tsx +313 -0
|
@@ -29,6 +29,7 @@ import type {
|
|
|
29
29
|
} from './types';
|
|
30
30
|
import { Invoice } from './invoice';
|
|
31
31
|
import { Subscription } from './subscription';
|
|
32
|
+
import { PaymentIntent } from './payment-intent';
|
|
32
33
|
|
|
33
34
|
export const nextCheckoutSessionId = createIdGenerator('cs', 58);
|
|
34
35
|
|
|
@@ -195,24 +196,47 @@ export class CheckoutSession extends Model<InferAttributes<CheckoutSession>, Inf
|
|
|
195
196
|
|
|
196
197
|
declare cross_sell_behavior?: LiteralUnion<'auto' | 'required', string>;
|
|
197
198
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
199
|
+
declare fulfillment_status?: LiteralUnion<
|
|
200
|
+
| 'pending'
|
|
201
|
+
| 'processing'
|
|
202
|
+
| 'completed'
|
|
203
|
+
| 'failed'
|
|
204
|
+
| 'cancelled'
|
|
205
|
+
| 'max_retries_exceeded'
|
|
206
|
+
| 'return_requested'
|
|
207
|
+
| 'sent',
|
|
208
|
+
string
|
|
209
|
+
>;
|
|
210
|
+
declare vendor_info?: Array<{
|
|
211
|
+
vendor_id: string;
|
|
212
|
+
vendor_key: string;
|
|
213
|
+
order_id: string;
|
|
214
|
+
status:
|
|
215
|
+
| 'pending'
|
|
216
|
+
| 'processing'
|
|
217
|
+
| 'completed'
|
|
218
|
+
| 'failed'
|
|
219
|
+
| 'cancelled'
|
|
220
|
+
| 'max_retries_exceeded'
|
|
221
|
+
| 'return_requested'
|
|
222
|
+
| 'sent';
|
|
223
|
+
service_url?: string;
|
|
224
|
+
app_url?: string;
|
|
225
|
+
error_message?: string;
|
|
226
|
+
amount: string;
|
|
227
|
+
|
|
228
|
+
attempts?: number;
|
|
229
|
+
lastAttemptAt?: string;
|
|
230
|
+
completedAt?: string;
|
|
231
|
+
commissionAmount?: string;
|
|
232
|
+
|
|
233
|
+
returnRequest?: {
|
|
234
|
+
reason: string;
|
|
235
|
+
requestedAt: string;
|
|
236
|
+
status: 'pending' | 'accepted' | 'rejected';
|
|
237
|
+
returnDetails?: string;
|
|
238
|
+
};
|
|
239
|
+
}>;
|
|
216
240
|
|
|
217
241
|
declare created_at: CreationOptional<Date>;
|
|
218
242
|
declare created_via: LiteralUnion<'api' | 'dashboard' | 'portal', string>;
|
|
@@ -438,6 +462,14 @@ export class CheckoutSession extends Model<InferAttributes<CheckoutSession>, Inf
|
|
|
438
462
|
type: DataTypes.INTEGER,
|
|
439
463
|
defaultValue: 0,
|
|
440
464
|
},
|
|
465
|
+
fulfillment_status: {
|
|
466
|
+
type: DataTypes.STRING,
|
|
467
|
+
allowNull: true,
|
|
468
|
+
},
|
|
469
|
+
vendor_info: {
|
|
470
|
+
type: DataTypes.JSON,
|
|
471
|
+
allowNull: true,
|
|
472
|
+
},
|
|
441
473
|
},
|
|
442
474
|
{
|
|
443
475
|
sequelize,
|
|
@@ -542,6 +574,40 @@ export class CheckoutSession extends Model<InferAttributes<CheckoutSession>, Inf
|
|
|
542
574
|
}
|
|
543
575
|
return checkoutSession;
|
|
544
576
|
}
|
|
577
|
+
|
|
578
|
+
public static async findByPaymentIntentId(paymentIntentId: string): Promise<CheckoutSession | null> {
|
|
579
|
+
try {
|
|
580
|
+
// Method 1: Direct lookup by payment_intent_id
|
|
581
|
+
let checkoutSession = await CheckoutSession.findOne({
|
|
582
|
+
where: { payment_intent_id: paymentIntentId },
|
|
583
|
+
});
|
|
584
|
+
|
|
585
|
+
if (checkoutSession) {
|
|
586
|
+
return checkoutSession;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
// Method 2: Lookup via Invoice -> Subscription for original CheckoutSession
|
|
590
|
+
// This typically occurs during subscription renewals
|
|
591
|
+
const paymentIntent = await PaymentIntent.findByPk(paymentIntentId);
|
|
592
|
+
if (!paymentIntent || !paymentIntent.invoice_id) {
|
|
593
|
+
return null;
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
const invoice = await Invoice.findByPk(paymentIntent.invoice_id);
|
|
597
|
+
if (!invoice || !invoice.subscription_id) {
|
|
598
|
+
return null;
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
// Find original CheckoutSession through subscription
|
|
602
|
+
checkoutSession = await CheckoutSession.findBySubscriptionId(invoice.subscription_id);
|
|
603
|
+
if (checkoutSession) {
|
|
604
|
+
return checkoutSession;
|
|
605
|
+
}
|
|
606
|
+
return null;
|
|
607
|
+
} catch (error: any) {
|
|
608
|
+
return null;
|
|
609
|
+
}
|
|
610
|
+
}
|
|
545
611
|
}
|
|
546
612
|
|
|
547
613
|
export type TCheckoutSession = InferAttributes<CheckoutSession>;
|
|
@@ -32,6 +32,7 @@ import { CreditTransaction, TCreditTransaction } from './credit-transaction';
|
|
|
32
32
|
import { Meter, TMeter } from './meter';
|
|
33
33
|
import { MeterEvent, TMeterEvent } from './meter-event';
|
|
34
34
|
import { AutoRechargeConfig } from './auto-recharge-config';
|
|
35
|
+
import { ProductVendor } from './product-vendor';
|
|
35
36
|
|
|
36
37
|
const models = {
|
|
37
38
|
CheckoutSession,
|
|
@@ -67,6 +68,7 @@ const models = {
|
|
|
67
68
|
Meter,
|
|
68
69
|
MeterEvent,
|
|
69
70
|
AutoRechargeConfig,
|
|
71
|
+
ProductVendor,
|
|
70
72
|
};
|
|
71
73
|
|
|
72
74
|
export function initialize(sequelize: any) {
|
|
@@ -116,6 +118,7 @@ export * from './credit-transaction';
|
|
|
116
118
|
export * from './meter';
|
|
117
119
|
export * from './meter-event';
|
|
118
120
|
export * from './auto-recharge-config';
|
|
121
|
+
export * from './product-vendor';
|
|
119
122
|
|
|
120
123
|
export type TPriceExpanded = TPrice & {
|
|
121
124
|
object: 'price';
|
|
@@ -31,6 +31,13 @@ export class Payout extends Model<InferAttributes<Payout>, InferCreationAttribut
|
|
|
31
31
|
|
|
32
32
|
declare metadata?: Record<string, any>;
|
|
33
33
|
|
|
34
|
+
declare vendor_info?: {
|
|
35
|
+
vendor_id: string;
|
|
36
|
+
app_pid?: string;
|
|
37
|
+
order_id: string;
|
|
38
|
+
commission_amount: string;
|
|
39
|
+
};
|
|
40
|
+
|
|
34
41
|
declare status: LiteralUnion<'pending' | 'paid' | 'failed' | 'canceled' | 'in_transit', string>;
|
|
35
42
|
|
|
36
43
|
// retry logic
|
|
@@ -168,6 +175,10 @@ export class Payout extends Model<InferAttributes<Payout>, InferCreationAttribut
|
|
|
168
175
|
this.init(
|
|
169
176
|
{
|
|
170
177
|
...Payout.GENESIS_ATTRIBUTES,
|
|
178
|
+
vendor_info: {
|
|
179
|
+
type: DataTypes.JSON,
|
|
180
|
+
allowNull: true,
|
|
181
|
+
},
|
|
171
182
|
},
|
|
172
183
|
{
|
|
173
184
|
sequelize,
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/lines-between-class-members */
|
|
2
|
+
import { CreationOptional, DataTypes, InferAttributes, InferCreationAttributes, Model } from 'sequelize';
|
|
3
|
+
|
|
4
|
+
import { createIdGenerator } from '../../libs/util';
|
|
5
|
+
|
|
6
|
+
export const nextProductVendorId = createIdGenerator('pv', 24);
|
|
7
|
+
|
|
8
|
+
export class ProductVendor extends Model<InferAttributes<ProductVendor>, InferCreationAttributes<ProductVendor>> {
|
|
9
|
+
declare id: CreationOptional<string>;
|
|
10
|
+
declare vendor_key: string;
|
|
11
|
+
declare name: string;
|
|
12
|
+
declare description: string;
|
|
13
|
+
|
|
14
|
+
declare app_url: string;
|
|
15
|
+
declare webhook_path?: string;
|
|
16
|
+
|
|
17
|
+
declare default_commission_rate: number;
|
|
18
|
+
declare default_commission_type: 'percentage' | 'fixed_amount';
|
|
19
|
+
|
|
20
|
+
declare order_create_params: Record<string, any>;
|
|
21
|
+
|
|
22
|
+
declare app_pid?: string;
|
|
23
|
+
declare app_logo?: string;
|
|
24
|
+
|
|
25
|
+
declare status: 'active' | 'inactive';
|
|
26
|
+
declare metadata: Record<string, any>;
|
|
27
|
+
|
|
28
|
+
declare created_by: string;
|
|
29
|
+
declare created_at: CreationOptional<Date>;
|
|
30
|
+
declare updated_at: CreationOptional<Date>;
|
|
31
|
+
|
|
32
|
+
public static readonly GENESIS_ATTRIBUTES = {
|
|
33
|
+
id: {
|
|
34
|
+
type: DataTypes.STRING(30),
|
|
35
|
+
primaryKey: true,
|
|
36
|
+
allowNull: false,
|
|
37
|
+
defaultValue: nextProductVendorId,
|
|
38
|
+
},
|
|
39
|
+
vendor_key: {
|
|
40
|
+
type: DataTypes.STRING(50),
|
|
41
|
+
allowNull: false,
|
|
42
|
+
unique: true,
|
|
43
|
+
},
|
|
44
|
+
name: {
|
|
45
|
+
type: DataTypes.STRING(255),
|
|
46
|
+
allowNull: false,
|
|
47
|
+
},
|
|
48
|
+
description: {
|
|
49
|
+
type: DataTypes.TEXT,
|
|
50
|
+
allowNull: true,
|
|
51
|
+
},
|
|
52
|
+
app_url: {
|
|
53
|
+
type: DataTypes.STRING(512),
|
|
54
|
+
allowNull: false,
|
|
55
|
+
},
|
|
56
|
+
webhook_path: {
|
|
57
|
+
type: DataTypes.STRING(255),
|
|
58
|
+
allowNull: true,
|
|
59
|
+
},
|
|
60
|
+
default_commission_rate: {
|
|
61
|
+
type: DataTypes.DECIMAL(7, 4),
|
|
62
|
+
allowNull: false,
|
|
63
|
+
},
|
|
64
|
+
default_commission_type: {
|
|
65
|
+
type: DataTypes.ENUM('percentage', 'fixed_amount'),
|
|
66
|
+
allowNull: false,
|
|
67
|
+
},
|
|
68
|
+
order_create_params: {
|
|
69
|
+
type: DataTypes.JSON,
|
|
70
|
+
allowNull: true,
|
|
71
|
+
defaultValue: {},
|
|
72
|
+
},
|
|
73
|
+
app_pid: {
|
|
74
|
+
type: DataTypes.STRING(255),
|
|
75
|
+
allowNull: true,
|
|
76
|
+
},
|
|
77
|
+
app_logo: {
|
|
78
|
+
type: DataTypes.STRING(512),
|
|
79
|
+
allowNull: true,
|
|
80
|
+
},
|
|
81
|
+
status: {
|
|
82
|
+
type: DataTypes.ENUM('active', 'inactive'),
|
|
83
|
+
allowNull: false,
|
|
84
|
+
defaultValue: 'active',
|
|
85
|
+
},
|
|
86
|
+
metadata: {
|
|
87
|
+
type: DataTypes.JSON,
|
|
88
|
+
allowNull: true,
|
|
89
|
+
defaultValue: {},
|
|
90
|
+
},
|
|
91
|
+
created_by: {
|
|
92
|
+
type: DataTypes.STRING(30),
|
|
93
|
+
allowNull: true,
|
|
94
|
+
},
|
|
95
|
+
created_at: {
|
|
96
|
+
type: DataTypes.DATE,
|
|
97
|
+
defaultValue: DataTypes.NOW,
|
|
98
|
+
allowNull: false,
|
|
99
|
+
},
|
|
100
|
+
updated_at: {
|
|
101
|
+
type: DataTypes.DATE,
|
|
102
|
+
defaultValue: DataTypes.NOW,
|
|
103
|
+
allowNull: false,
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
public static initialize(sequelize: any) {
|
|
108
|
+
this.init(ProductVendor.GENESIS_ATTRIBUTES, {
|
|
109
|
+
sequelize,
|
|
110
|
+
modelName: 'ProductVendor',
|
|
111
|
+
tableName: 'product_vendors',
|
|
112
|
+
createdAt: 'created_at',
|
|
113
|
+
updatedAt: 'updated_at',
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export type TProductVendor = InferAttributes<ProductVendor>;
|
|
@@ -51,6 +51,17 @@ export class Product extends Model<InferAttributes<Product>, InferCreationAttrib
|
|
|
51
51
|
cross_sells_to_id: string;
|
|
52
52
|
};
|
|
53
53
|
|
|
54
|
+
declare vendor_config?: Array<{
|
|
55
|
+
vendor_id: string;
|
|
56
|
+
vendor_key: string;
|
|
57
|
+
name?: string;
|
|
58
|
+
description?: string;
|
|
59
|
+
commission_rate?: number;
|
|
60
|
+
commission_type?: 'percentage' | 'fixed_amount';
|
|
61
|
+
amount?: string;
|
|
62
|
+
custom_params?: Record<string, any>;
|
|
63
|
+
}>;
|
|
64
|
+
|
|
54
65
|
// TODO: goods related props are not supported
|
|
55
66
|
// declare package_dimensions?: any;
|
|
56
67
|
// declare shippable?: boolean;
|
|
@@ -138,6 +149,10 @@ export class Product extends Model<InferAttributes<Product>, InferCreationAttrib
|
|
|
138
149
|
type: DataTypes.JSON,
|
|
139
150
|
allowNull: true,
|
|
140
151
|
},
|
|
152
|
+
vendor_config: {
|
|
153
|
+
type: DataTypes.JSON,
|
|
154
|
+
allowNull: true,
|
|
155
|
+
},
|
|
141
156
|
},
|
|
142
157
|
{
|
|
143
158
|
sequelize,
|
package/blocklet.yml
CHANGED
|
@@ -14,7 +14,7 @@ repository:
|
|
|
14
14
|
type: git
|
|
15
15
|
url: git+https://github.com/blocklet/payment-kit.git
|
|
16
16
|
specVersion: 1.2.8
|
|
17
|
-
version: 1.20.
|
|
17
|
+
version: 1.20.6
|
|
18
18
|
logo: logo.png
|
|
19
19
|
files:
|
|
20
20
|
- dist
|
|
@@ -66,7 +66,13 @@ scripts:
|
|
|
66
66
|
preStart: node api/hooks/pre-start.js
|
|
67
67
|
preFlight: node api/hooks/pre-flight.js
|
|
68
68
|
dev: pnpm run start
|
|
69
|
-
environments:
|
|
69
|
+
environments:
|
|
70
|
+
- name: SHORT_URL_API_KEY
|
|
71
|
+
description: Short URL service API Key
|
|
72
|
+
required: false
|
|
73
|
+
default: ''
|
|
74
|
+
secure: true
|
|
75
|
+
shared: false
|
|
70
76
|
capabilities:
|
|
71
77
|
navigation: true
|
|
72
78
|
clusterMode: false
|