payment-kit 1.14.13 → 1.14.15
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/routes/checkout-sessions.ts +4 -0
- package/api/src/routes/payment-links.ts +5 -0
- package/api/src/routes/prices.ts +21 -0
- package/api/src/routes/products.ts +24 -1
- package/api/src/routes/subscriptions.ts +1 -1
- package/blocklet.yml +2 -1
- package/package.json +4 -4
- package/src/components/payment-link/item.tsx +9 -2
- package/src/components/price/form.tsx +10 -1
- package/src/pages/admin/products/prices/actions.tsx +1 -1
|
@@ -83,6 +83,10 @@ export async function validateInventory(line_items: LineItem[], includePendingQu
|
|
|
83
83
|
const priceId = item.price_id;
|
|
84
84
|
const quantity = Number(item.quantity || 0);
|
|
85
85
|
|
|
86
|
+
if (quantity < 1) {
|
|
87
|
+
throw new Error(`Quantity should be greater or equal to 1 for price: ${priceId}`);
|
|
88
|
+
}
|
|
89
|
+
|
|
86
90
|
const price = await Price.findOne({ where: { id: priceId } });
|
|
87
91
|
|
|
88
92
|
let delta = quantity;
|
|
@@ -114,6 +114,11 @@ export async function createPaymentLink(payload: any) {
|
|
|
114
114
|
throw new Error('line_items should not be empty for payment link');
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
+
const invalidQuantityIndex = raw.line_items.findIndex((x) => Number(x?.quantity || 0) < 1);
|
|
118
|
+
if (invalidQuantityIndex > -1) {
|
|
119
|
+
throw new Error(`line_items[${invalidQuantityIndex}].quantity should be greater or equal to 1`);
|
|
120
|
+
}
|
|
121
|
+
|
|
117
122
|
const items = await Price.expand(raw.line_items);
|
|
118
123
|
if (items.find((x) => x.price.custom_unit_amount) && items.length > 1) {
|
|
119
124
|
throw new Error('Multiple items with custom unit amount are not supported in payment link');
|
package/api/src/routes/prices.ts
CHANGED
|
@@ -172,6 +172,18 @@ const priceQuantitySchema = Joi.object({
|
|
|
172
172
|
quantity_limit_per_checkout: Joi.number().integer().min(0).optional().default(0),
|
|
173
173
|
});
|
|
174
174
|
|
|
175
|
+
const priceAmountSchema = Joi.object({
|
|
176
|
+
currency_options: Joi.array()
|
|
177
|
+
.items(
|
|
178
|
+
Joi.object({
|
|
179
|
+
unit_amount: Joi.number().greater(0).required(),
|
|
180
|
+
// 其他属性
|
|
181
|
+
}).unknown(true)
|
|
182
|
+
)
|
|
183
|
+
.optional(),
|
|
184
|
+
unit_amount: Joi.number().greater(0).required(),
|
|
185
|
+
});
|
|
186
|
+
|
|
175
187
|
// FIXME: @wangshijun use schema validation
|
|
176
188
|
// create price
|
|
177
189
|
// eslint-disable-next-line consistent-return
|
|
@@ -183,6 +195,10 @@ router.post('/', auth, async (req, res) => {
|
|
|
183
195
|
if (error) {
|
|
184
196
|
return res.status(400).json({ error: `Price create request invalid: ${error.message}` });
|
|
185
197
|
}
|
|
198
|
+
const { error: priceAmountError } = priceAmountSchema.validate(pick(req.body, ['currency_options', 'unit_amount']));
|
|
199
|
+
if (priceAmountError) {
|
|
200
|
+
return res.status(400).json({ error: `Price create request invalid: ${priceAmountError.message}` });
|
|
201
|
+
}
|
|
186
202
|
const result = await createPrice({
|
|
187
203
|
...req.body,
|
|
188
204
|
livemode: !!req.livemode,
|
|
@@ -248,6 +264,11 @@ router.put('/:id', auth, async (req, res) => {
|
|
|
248
264
|
if (error) {
|
|
249
265
|
return res.status(400).json({ error: `Price update request invalid: ${error.message}` });
|
|
250
266
|
}
|
|
267
|
+
|
|
268
|
+
const { error: priceAmountError } = priceAmountSchema.validate(pick(req.body, ['currency_options', 'unit_amount']));
|
|
269
|
+
if (priceAmountError) {
|
|
270
|
+
return res.status(400).json({ error: `Price update request invalid: ${priceAmountError.message}` });
|
|
271
|
+
}
|
|
251
272
|
const doc = await Price.findByPkOrLookupKey(req.params.id as string);
|
|
252
273
|
|
|
253
274
|
if (!doc) {
|
|
@@ -18,6 +18,24 @@ const router = Router();
|
|
|
18
18
|
|
|
19
19
|
const auth = authenticate<Product>({ component: true, roles: ['owner', 'admin'] });
|
|
20
20
|
|
|
21
|
+
const priceAmountSchema = Joi.object({
|
|
22
|
+
prices: Joi.array()
|
|
23
|
+
.items(
|
|
24
|
+
Joi.object({
|
|
25
|
+
currency_options: Joi.array()
|
|
26
|
+
.items(
|
|
27
|
+
Joi.object({
|
|
28
|
+
unit_amount: Joi.number().greater(0).required(),
|
|
29
|
+
// 其他属性
|
|
30
|
+
}).unknown(true)
|
|
31
|
+
)
|
|
32
|
+
.optional(),
|
|
33
|
+
unit_amount: Joi.number().greater(0).required(),
|
|
34
|
+
}).unknown(true)
|
|
35
|
+
)
|
|
36
|
+
.required(),
|
|
37
|
+
});
|
|
38
|
+
|
|
21
39
|
export async function createProductAndPrices(payload: any) {
|
|
22
40
|
const raw: Partial<Product> = pick(payload, [
|
|
23
41
|
'name',
|
|
@@ -107,8 +125,13 @@ export async function createProductAndPrices(payload: any) {
|
|
|
107
125
|
|
|
108
126
|
// FIXME: @wangshijun use schema validation
|
|
109
127
|
// create product and price
|
|
128
|
+
// eslint-disable-next-line consistent-return
|
|
110
129
|
router.post('/', auth, async (req, res) => {
|
|
111
130
|
try {
|
|
131
|
+
const { error: priceAmountError } = priceAmountSchema.validate(pick(req.body, ['prices']));
|
|
132
|
+
if (priceAmountError) {
|
|
133
|
+
return res.status(400).json({ error: `Product create request invalid: ${priceAmountError.message}` });
|
|
134
|
+
}
|
|
112
135
|
const result = await createProductAndPrices({
|
|
113
136
|
...req.body,
|
|
114
137
|
active: true,
|
|
@@ -121,7 +144,7 @@ router.post('/', auth, async (req, res) => {
|
|
|
121
144
|
res.json(result);
|
|
122
145
|
} catch (err) {
|
|
123
146
|
logger.error('create product error', err);
|
|
124
|
-
res.status(400).json({ error: err.message });
|
|
147
|
+
return res.status(400).json({ error: err.message });
|
|
125
148
|
}
|
|
126
149
|
});
|
|
127
150
|
|
|
@@ -251,7 +251,7 @@ router.put('/:id/cancel', authPortal, async (req, res) => {
|
|
|
251
251
|
if (req.user?.via === 'portal') {
|
|
252
252
|
updates.cancel_at_period_end = true;
|
|
253
253
|
updates.cancel_at = subscription.current_period_end;
|
|
254
|
-
updates.cancelation_details = { reason: 'cancellation_requested', feedback, comment };
|
|
254
|
+
updates.cancelation_details = { reason: 'cancellation_requested', feedback, comment, return_stake: canReturnStake };
|
|
255
255
|
updates.canceled_at = now;
|
|
256
256
|
await addSubscriptionJob(subscription, 'cancel', true, updates.cancel_at);
|
|
257
257
|
} else {
|
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.14.
|
|
17
|
+
version: 1.14.15
|
|
18
18
|
logo: logo.png
|
|
19
19
|
files:
|
|
20
20
|
- dist
|
|
@@ -44,6 +44,7 @@ interfaces:
|
|
|
44
44
|
ignoreUrls:
|
|
45
45
|
- /api/did/**
|
|
46
46
|
- /api/integrations/stripe/webhook
|
|
47
|
+
- /api/products/**
|
|
47
48
|
blockUnauthorized: false
|
|
48
49
|
community: ''
|
|
49
50
|
documentation: ''
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "payment-kit",
|
|
3
|
-
"version": "1.14.
|
|
3
|
+
"version": "1.14.15",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"dev": "blocklet dev --open",
|
|
6
6
|
"eject": "vite eject",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"@arcblock/validator": "^1.18.127",
|
|
53
53
|
"@blocklet/js-sdk": "1.16.28",
|
|
54
54
|
"@blocklet/logger": "1.16.28",
|
|
55
|
-
"@blocklet/payment-react": "1.14.
|
|
55
|
+
"@blocklet/payment-react": "1.14.15",
|
|
56
56
|
"@blocklet/sdk": "1.16.28",
|
|
57
57
|
"@blocklet/ui-react": "^2.10.11",
|
|
58
58
|
"@blocklet/uploader": "^0.1.20",
|
|
@@ -118,7 +118,7 @@
|
|
|
118
118
|
"devDependencies": {
|
|
119
119
|
"@abtnode/types": "1.16.28",
|
|
120
120
|
"@arcblock/eslint-config-ts": "^0.3.2",
|
|
121
|
-
"@blocklet/payment-types": "1.14.
|
|
121
|
+
"@blocklet/payment-types": "1.14.15",
|
|
122
122
|
"@types/cookie-parser": "^1.4.7",
|
|
123
123
|
"@types/cors": "^2.8.17",
|
|
124
124
|
"@types/debug": "^4.1.12",
|
|
@@ -160,5 +160,5 @@
|
|
|
160
160
|
"parser": "typescript"
|
|
161
161
|
}
|
|
162
162
|
},
|
|
163
|
-
"gitHead": "
|
|
163
|
+
"gitHead": "a2bc07ca48172f040a2874ee1b4bb751cc41e873"
|
|
164
164
|
}
|
|
@@ -80,12 +80,19 @@ export default function LineItem({ prefix, product, valid, onUpdate, onRemove }:
|
|
|
80
80
|
render={({ field }) => (
|
|
81
81
|
<Stack direction="row" alignItems="center" mt={1}>
|
|
82
82
|
<TextField
|
|
83
|
-
sx={{ width:
|
|
83
|
+
sx={{ width: 80, mr: 1 }}
|
|
84
84
|
inputProps={{ style: { padding: '4px 8px' } }}
|
|
85
85
|
size="small"
|
|
86
|
+
type="number"
|
|
86
87
|
{...field}
|
|
88
|
+
onChange={(e) => {
|
|
89
|
+
const intValue = parseInt(e.target.value || '1', 10);
|
|
90
|
+
if (intValue >= 1) {
|
|
91
|
+
field.onChange(intValue);
|
|
92
|
+
}
|
|
93
|
+
}}
|
|
87
94
|
/>
|
|
88
|
-
<FormLabel style={{ marginBottom: 0 }}>
|
|
95
|
+
<FormLabel style={{ marginBottom: 0 }}>{t('common.quantity')}</FormLabel>
|
|
89
96
|
</Stack>
|
|
90
97
|
)}
|
|
91
98
|
/>
|
|
@@ -127,7 +127,7 @@ export default function PriceForm({ prefix, simple }: PriceFormProps) {
|
|
|
127
127
|
const isLocked = priceLocked && window.blocklet?.PAYMENT_CHANGE_LOCKED_PRICE !== '1';
|
|
128
128
|
|
|
129
129
|
const validateAmount = (v: number, currency: { maximum_precision?: number }) => {
|
|
130
|
-
if (Number(v)
|
|
130
|
+
if (Number(v) <= 0) {
|
|
131
131
|
return t('admin.price.unit_amount.positive');
|
|
132
132
|
}
|
|
133
133
|
const validPrecision = formatAmountPrecisionLimit(v.toString(), locale, currency?.maximum_precision || 6);
|
|
@@ -201,6 +201,15 @@ export default function PriceForm({ prefix, simple }: PriceFormProps) {
|
|
|
201
201
|
</InputAdornment>
|
|
202
202
|
),
|
|
203
203
|
}}
|
|
204
|
+
onChange={(e) => {
|
|
205
|
+
const { value } = e.target;
|
|
206
|
+
field.onChange(value);
|
|
207
|
+
const index = currencies.fields.findIndex((x: any) => x.currency_id === settings.baseCurrency.id);
|
|
208
|
+
if (index === -1) {
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
setValue(getFieldName(`currency_options.${index}.unit_amount`), value, { shouldValidate: true });
|
|
212
|
+
}}
|
|
204
213
|
/>
|
|
205
214
|
</Box>
|
|
206
215
|
)}
|
|
@@ -132,7 +132,7 @@ export default function PriceActions({ data, onChange, variant, setAsDefault }:
|
|
|
132
132
|
disabled: true,
|
|
133
133
|
},
|
|
134
134
|
{ label: t('admin.paymentLink.add'), handler: onCreatePaymentLink, color: 'primary' },
|
|
135
|
-
{ label: t('admin.pricingTable.add'), handler: onCreatePricingTable, color: 'primary' },
|
|
135
|
+
{ label: t('admin.pricingTable.add'), handler: onCreatePricingTable, color: 'primary', disabled: !data.recurring },
|
|
136
136
|
];
|
|
137
137
|
|
|
138
138
|
if (setAsDefault) {
|