payment-kit 1.13.49 → 1.13.50
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/integrations/stripe/handlers/payment-intent.ts +1 -0
- package/api/src/jobs/payment.ts +11 -3
- package/api/src/libs/payment.ts +13 -1
- package/api/src/routes/checkout-sessions.ts +15 -8
- package/api/src/routes/connect/collect.ts +6 -2
- package/api/src/routes/connect/pay.ts +6 -2
- package/api/src/routes/connect/setup.ts +11 -4
- package/api/src/routes/connect/shared.ts +13 -2
- package/api/src/routes/connect/subscribe.ts +9 -4
- package/api/src/store/models/payment-intent.ts +1 -1
- package/api/src/store/models/setup-intent.ts +1 -1
- package/blocklet.yml +1 -1
- package/package.json +4 -3
- package/src/components/blockchain/tx.tsx +11 -3
- package/src/components/portal/invoice/list.tsx +2 -1
- package/src/pages/customer/invoice.tsx +1 -1
|
@@ -13,6 +13,7 @@ import { handleStripeInvoiceCreated } from './invoice';
|
|
|
13
13
|
export async function handleStripePaymentSucceed(paymentIntent: PaymentIntent, event?: TEventExpanded) {
|
|
14
14
|
await paymentIntent.update({
|
|
15
15
|
status: 'succeeded',
|
|
16
|
+
last_payment_error: null,
|
|
16
17
|
amount_received: paymentIntent.amount,
|
|
17
18
|
payment_details: merge(
|
|
18
19
|
paymentIntent.metadata,
|
package/api/src/jobs/payment.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { wallet } from '../libs/auth';
|
|
|
2
2
|
import dayjs from '../libs/dayjs';
|
|
3
3
|
import CustomError from '../libs/error';
|
|
4
4
|
import logger from '../libs/logger';
|
|
5
|
-
import { isDelegationSufficientForPayment } from '../libs/payment';
|
|
5
|
+
import { getGasPayerExtra, isDelegationSufficientForPayment } from '../libs/payment';
|
|
6
6
|
import createQueue from '../libs/queue';
|
|
7
7
|
import { MAX_RETRY_COUNT, getNextRetry } from '../libs/util';
|
|
8
8
|
import { CheckoutSession } from '../store/models/checkout-session';
|
|
@@ -128,12 +128,14 @@ export const handlePayment = async (job: PaymentJob) => {
|
|
|
128
128
|
amount: paymentIntent.amount,
|
|
129
129
|
});
|
|
130
130
|
if (result.sufficient === false) {
|
|
131
|
+
logger.error('PaymentIntent capture aborted on preCheck', { id: paymentIntent.id, result });
|
|
132
|
+
// FIXME: send email to customer, pause subscription
|
|
131
133
|
throw new CustomError(result.reason, 'payer balance or delegation not sufficient for this payment');
|
|
132
134
|
}
|
|
133
135
|
|
|
134
136
|
// do the capture
|
|
135
137
|
await paymentIntent.update({ status: 'processing' });
|
|
136
|
-
const
|
|
138
|
+
const signed = await client.signTransferV2Tx({
|
|
137
139
|
tx: {
|
|
138
140
|
itx: {
|
|
139
141
|
to: wallet.address,
|
|
@@ -150,14 +152,20 @@ export const handlePayment = async (job: PaymentJob) => {
|
|
|
150
152
|
},
|
|
151
153
|
},
|
|
152
154
|
},
|
|
153
|
-
delegator: payer,
|
|
154
155
|
wallet,
|
|
156
|
+
delegator: payer,
|
|
155
157
|
});
|
|
158
|
+
// @ts-ignore
|
|
159
|
+
const { buffer } = await client.encodeTransferV2Tx({ tx: signed });
|
|
160
|
+
// @ts-ignore
|
|
161
|
+
const txHash = await client.sendTransferV2Tx({ tx: signed, wallet, delegator: payer }, getGasPayerExtra(buffer));
|
|
162
|
+
|
|
156
163
|
logger.info(`PaymentIntent capture done: ${paymentIntent.id} with tx ${txHash}`);
|
|
157
164
|
|
|
158
165
|
await paymentIntent.update({
|
|
159
166
|
status: 'succeeded',
|
|
160
167
|
amount_received: paymentIntent.amount,
|
|
168
|
+
last_payment_error: null,
|
|
161
169
|
payment_details: {
|
|
162
170
|
arcblock: {
|
|
163
171
|
tx_hash: txHash,
|
package/api/src/libs/payment.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { toDelegateAddress } from '@arcblock/did-util';
|
|
2
|
+
import { sign } from '@arcblock/jwt';
|
|
2
3
|
import { getWalletDid } from '@blocklet/sdk/lib/did';
|
|
3
4
|
import type { DelegateState } from '@ocap/client';
|
|
5
|
+
import { toTxHash } from '@ocap/mcrypto';
|
|
4
6
|
import { BN } from '@ocap/util';
|
|
5
7
|
|
|
6
8
|
import type { TPaymentCurrency } from '../store/models/payment-currency';
|
|
@@ -42,7 +44,7 @@ export async function isDelegationSufficientForPayment(args: {
|
|
|
42
44
|
if (!token) {
|
|
43
45
|
return { sufficient: false, reason: 'NO_TOKEN' };
|
|
44
46
|
}
|
|
45
|
-
if (new BN(token.balance).
|
|
47
|
+
if (new BN(token.balance).lt(new BN(amount))) {
|
|
46
48
|
return { sufficient: false, reason: 'NO_ENOUGH_TOKEN' };
|
|
47
49
|
}
|
|
48
50
|
|
|
@@ -55,3 +57,13 @@ export async function isDelegationSufficientForPayment(args: {
|
|
|
55
57
|
|
|
56
58
|
throw new Error(`Payment method ${paymentMethod.type} not supported`);
|
|
57
59
|
}
|
|
60
|
+
|
|
61
|
+
export function getGasPayerExtra(txBuffer: Buffer) {
|
|
62
|
+
const txHash = toTxHash(txBuffer);
|
|
63
|
+
return {
|
|
64
|
+
headers: {
|
|
65
|
+
'x-gas-payer-sig': sign(wallet.address, wallet.secretKey, { txHash }),
|
|
66
|
+
'x-gas-payer-pk': wallet.publicKey,
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
}
|
|
@@ -506,11 +506,17 @@ router.put('/:id/submit', user, ensureCheckoutSessionOpen, async (req, res) => {
|
|
|
506
506
|
return res.status(403).json({ code: 'PAYMENT_PROCESSING', error: 'Checkout session payment processing' });
|
|
507
507
|
}
|
|
508
508
|
paymentIntent = await paymentIntent.update({
|
|
509
|
+
status: 'requires_capture',
|
|
509
510
|
amount: checkoutSession.amount_total,
|
|
510
511
|
customer_id: customer.id,
|
|
511
512
|
currency_id: paymentCurrency.id,
|
|
512
513
|
payment_method_id: paymentMethod.id,
|
|
513
514
|
receipt_email: customer.email,
|
|
515
|
+
last_payment_error: null,
|
|
516
|
+
});
|
|
517
|
+
logger.info('payment intent for checkout session reset', {
|
|
518
|
+
session: checkoutSession.id,
|
|
519
|
+
intent: paymentIntent.id,
|
|
514
520
|
});
|
|
515
521
|
} else {
|
|
516
522
|
paymentIntent = await PaymentIntent.create({
|
|
@@ -547,7 +553,7 @@ router.put('/:id/submit', user, ensureCheckoutSessionOpen, async (req, res) => {
|
|
|
547
553
|
}
|
|
548
554
|
|
|
549
555
|
let setupIntent: SetupIntent | null = null;
|
|
550
|
-
if (checkoutSession.mode === 'setup'
|
|
556
|
+
if (checkoutSession.mode === 'setup' && paymentMethod.type !== 'stripe') {
|
|
551
557
|
if (checkoutSession.setup_intent_id) {
|
|
552
558
|
setupIntent = await SetupIntent.findByPk(checkoutSession.setup_intent_id);
|
|
553
559
|
}
|
|
@@ -563,16 +569,22 @@ router.put('/:id/submit', user, ensureCheckoutSessionOpen, async (req, res) => {
|
|
|
563
569
|
return res.status(403).json({ code: 'SETUP_PROCESSING', error: 'Checkout session setup processing' });
|
|
564
570
|
}
|
|
565
571
|
await setupIntent.update({
|
|
572
|
+
status: 'requires_capture',
|
|
566
573
|
customer_id: customer.id,
|
|
567
574
|
currency_id: paymentCurrency.id,
|
|
568
575
|
payment_method_id: paymentMethod.id,
|
|
576
|
+
last_setup_error: null,
|
|
577
|
+
});
|
|
578
|
+
logger.info('setup intent for checkout session reset', {
|
|
579
|
+
session: checkoutSession.id,
|
|
580
|
+
intent: setupIntent.id,
|
|
569
581
|
});
|
|
570
582
|
} else {
|
|
571
583
|
// ensure payment intent
|
|
572
584
|
setupIntent = await SetupIntent.create({
|
|
573
585
|
livemode: !!checkoutSession.livemode,
|
|
574
586
|
customer_id: customer.id,
|
|
575
|
-
description: '',
|
|
587
|
+
description: checkoutSession.payment_intent_data?.description || '',
|
|
576
588
|
currency_id: paymentCurrency.id,
|
|
577
589
|
payment_method_id: paymentMethod.id,
|
|
578
590
|
status: 'requires_payment_method',
|
|
@@ -698,20 +710,15 @@ router.put('/:id/submit', user, ensureCheckoutSessionOpen, async (req, res) => {
|
|
|
698
710
|
});
|
|
699
711
|
}
|
|
700
712
|
if (checkoutSession.mode === 'payment' && paymentIntent) {
|
|
701
|
-
await paymentIntent.update({ status: 'requires_capture' });
|
|
702
713
|
const { invoice } = await ensureInvoiceForCheckout({ checkoutSession, customer, paymentIntent });
|
|
703
714
|
if (invoice) {
|
|
704
715
|
await invoice.update({ auto_advance: true, payment_settings: paymentSettings });
|
|
705
716
|
invoiceQueue.push({ id: invoice.id, job: { invoiceId: invoice.id, retryOnError: false } });
|
|
706
717
|
} else {
|
|
707
|
-
|
|
718
|
+
paymentQueue.push({
|
|
708
719
|
id: paymentIntent.id,
|
|
709
720
|
job: { paymentIntentId: paymentIntent.id, paymentSettings, retryOnError: false },
|
|
710
721
|
});
|
|
711
|
-
job.on('finished', async () => {
|
|
712
|
-
await checkoutSession.update({ status: 'complete', payment_status: 'paid' });
|
|
713
|
-
logger.info(`CheckoutSession ${checkoutSession.id} updated on payment done ${paymentIntent?.id}`);
|
|
714
|
-
});
|
|
715
722
|
}
|
|
716
723
|
}
|
|
717
724
|
if (checkoutSession.mode === 'setup' && setupIntent && subscription) {
|
|
@@ -5,6 +5,7 @@ import { invoiceQueue } from '../../jobs/invoice';
|
|
|
5
5
|
import { handlePaymentSucceed, paymentQueue } from '../../jobs/payment';
|
|
6
6
|
import type { CallbackArgs } from '../../libs/auth';
|
|
7
7
|
import { wallet } from '../../libs/auth';
|
|
8
|
+
import { getGasPayerExtra } from '../../libs/payment';
|
|
8
9
|
import { getTxMetadata } from '../../libs/util';
|
|
9
10
|
import { ensureInvoiceForCollect, getAuthPrincipalClaim } from './shared';
|
|
10
11
|
|
|
@@ -49,7 +50,7 @@ export default {
|
|
|
49
50
|
|
|
50
51
|
throw new Error(`Payment method ${paymentMethod.type} not supported`);
|
|
51
52
|
},
|
|
52
|
-
onAuth: async ({ userDid, claims,
|
|
53
|
+
onAuth: async ({ userDid, claims, extraParams }: CallbackArgs) => {
|
|
53
54
|
const { invoiceId } = extraParams;
|
|
54
55
|
const { invoice, paymentIntent, paymentMethod } = await ensureInvoiceForCollect(invoiceId);
|
|
55
56
|
|
|
@@ -64,16 +65,19 @@ export default {
|
|
|
64
65
|
tx.from = claim.from;
|
|
65
66
|
}
|
|
66
67
|
|
|
68
|
+
// @ts-ignore
|
|
69
|
+
const { buffer } = await client.encodeTransferV3Tx({ tx });
|
|
67
70
|
const txHash = await client.sendTransferV3Tx(
|
|
68
71
|
// @ts-ignore
|
|
69
72
|
{ tx, wallet: fromAddress(userDid) },
|
|
70
|
-
|
|
73
|
+
getGasPayerExtra(buffer)
|
|
71
74
|
);
|
|
72
75
|
|
|
73
76
|
await paymentIntent.update({
|
|
74
77
|
status: 'succeeded',
|
|
75
78
|
amount_received: invoice.amount_due,
|
|
76
79
|
capture_method: 'manual',
|
|
80
|
+
last_payment_error: null,
|
|
77
81
|
payment_details: {
|
|
78
82
|
arcblock: {
|
|
79
83
|
tx_hash: txHash,
|
|
@@ -4,6 +4,7 @@ import { fromAddress } from '@ocap/wallet';
|
|
|
4
4
|
import { handlePaymentSucceed } from '../../jobs/payment';
|
|
5
5
|
import type { CallbackArgs } from '../../libs/auth';
|
|
6
6
|
import { wallet } from '../../libs/auth';
|
|
7
|
+
import { getGasPayerExtra } from '../../libs/payment';
|
|
7
8
|
import { getTxMetadata } from '../../libs/util';
|
|
8
9
|
import { ensureInvoiceForCheckout, ensurePaymentIntent, getAuthPrincipalClaim } from './shared';
|
|
9
10
|
|
|
@@ -50,7 +51,7 @@ export default {
|
|
|
50
51
|
|
|
51
52
|
throw new Error(`Payment method ${paymentMethod.type} not supported`);
|
|
52
53
|
},
|
|
53
|
-
onAuth: async ({ userDid, claims,
|
|
54
|
+
onAuth: async ({ userDid, claims, extraParams }: CallbackArgs) => {
|
|
54
55
|
const { checkoutSessionId } = extraParams;
|
|
55
56
|
const { checkoutSession, customer, paymentIntent, paymentMethod } = await ensurePaymentIntent(
|
|
56
57
|
checkoutSessionId,
|
|
@@ -73,15 +74,18 @@ export default {
|
|
|
73
74
|
tx.from = claim.from;
|
|
74
75
|
}
|
|
75
76
|
|
|
77
|
+
// @ts-ignore
|
|
78
|
+
const { buffer } = await client.encodeTransferV3Tx({ tx });
|
|
76
79
|
const txHash = await client.sendTransferV3Tx(
|
|
77
80
|
// @ts-ignore
|
|
78
81
|
{ tx, wallet: fromAddress(userDid) },
|
|
79
|
-
|
|
82
|
+
getGasPayerExtra(buffer)
|
|
80
83
|
);
|
|
81
84
|
|
|
82
85
|
await paymentIntent.update({
|
|
83
86
|
status: 'succeeded',
|
|
84
87
|
amount_received: paymentIntent.amount,
|
|
88
|
+
last_payment_error: null,
|
|
85
89
|
payment_details: {
|
|
86
90
|
arcblock: {
|
|
87
91
|
tx_hash: txHash,
|
|
@@ -6,6 +6,7 @@ import { fromPublicKey } from '@ocap/wallet';
|
|
|
6
6
|
import { subscriptionQueue } from '../../jobs/subscription';
|
|
7
7
|
import type { CallbackArgs } from '../../libs/auth';
|
|
8
8
|
import { wallet } from '../../libs/auth';
|
|
9
|
+
import { getGasPayerExtra } from '../../libs/payment';
|
|
9
10
|
import { getFastCheckoutAmount } from '../../libs/session';
|
|
10
11
|
import { getTxMetadata } from '../../libs/util';
|
|
11
12
|
import type { TLineItemExpanded } from '../../store/models';
|
|
@@ -56,7 +57,7 @@ export default {
|
|
|
56
57
|
},
|
|
57
58
|
nonce: checkoutSessionId,
|
|
58
59
|
requirement: {
|
|
59
|
-
tokens: [{ address: paymentCurrency.contract as string, value: amount }],
|
|
60
|
+
tokens: amount === '0' ? [] : [{ address: paymentCurrency.contract as string, value: amount }],
|
|
60
61
|
},
|
|
61
62
|
chainInfo: {
|
|
62
63
|
host: paymentMethod.settings?.arcblock?.api_host as string,
|
|
@@ -68,7 +69,7 @@ export default {
|
|
|
68
69
|
|
|
69
70
|
throw new Error(`Payment method ${paymentMethod.type} not supported`);
|
|
70
71
|
},
|
|
71
|
-
onAuth: async ({ userDid, userPk, claims,
|
|
72
|
+
onAuth: async ({ userDid, userPk, claims, extraParams }: CallbackArgs) => {
|
|
72
73
|
const { checkoutSessionId } = extraParams;
|
|
73
74
|
const { setupIntent, checkoutSession, paymentMethod, subscription } = await ensureSetupIntent(
|
|
74
75
|
checkoutSessionId,
|
|
@@ -80,6 +81,7 @@ export default {
|
|
|
80
81
|
}
|
|
81
82
|
|
|
82
83
|
if (paymentMethod.type === 'arcblock') {
|
|
84
|
+
await setupIntent.update({ status: 'processing' });
|
|
83
85
|
await subscription.update({
|
|
84
86
|
payment_settings: {
|
|
85
87
|
payment_method_types: ['arcblock'],
|
|
@@ -94,15 +96,20 @@ export default {
|
|
|
94
96
|
|
|
95
97
|
// execute the delegate tx
|
|
96
98
|
const tx: Partial<Transaction> = client.decodeTx(claim.origin);
|
|
99
|
+
tx.signature = claim.sig;
|
|
100
|
+
|
|
101
|
+
// @ts-ignore
|
|
102
|
+
const { buffer } = await client.encodeDelegateTx({ tx });
|
|
97
103
|
const txHash = await client.sendDelegateTx(
|
|
98
104
|
// @ts-ignore
|
|
99
|
-
{ tx, wallet: fromPublicKey(userPk, toTypeInfo(userDid))
|
|
100
|
-
|
|
105
|
+
{ tx, wallet: fromPublicKey(userPk, toTypeInfo(userDid)) },
|
|
106
|
+
getGasPayerExtra(buffer)
|
|
101
107
|
);
|
|
102
108
|
|
|
103
109
|
await setupIntent.update({
|
|
104
110
|
status: 'succeeded',
|
|
105
111
|
payment_method_types: ['arcblock'],
|
|
112
|
+
last_setup_error: null,
|
|
106
113
|
payment_method_options: {
|
|
107
114
|
arcblock: { payer: userDid },
|
|
108
115
|
},
|
|
@@ -226,9 +226,20 @@ export async function ensureInvoiceForCheckout({
|
|
|
226
226
|
|
|
227
227
|
// Do not create invoice if it's already created
|
|
228
228
|
if (checkoutSession.invoice_id) {
|
|
229
|
-
logger.
|
|
229
|
+
logger.info(`Invoice already created for checkout session ${checkoutSession.id}: ${checkoutSession.invoice_id}`);
|
|
230
|
+
const invoice = await Invoice.findByPk(checkoutSession.invoice_id);
|
|
231
|
+
if (invoice) {
|
|
232
|
+
await invoice.update({ status: 'open' });
|
|
233
|
+
logger.info(`Invoice status reset for checkout session ${checkoutSession.id}: ${checkoutSession.invoice_id}`);
|
|
234
|
+
if (invoice.payment_intent_id) {
|
|
235
|
+
await PaymentIntent.update({ status: 'requires_capture' }, { where: { id: invoice.payment_intent_id } });
|
|
236
|
+
logger.info(
|
|
237
|
+
`PaymentIntent status reset for checkout session ${checkoutSession.id}: ${invoice.payment_intent_id}`
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
230
241
|
return {
|
|
231
|
-
invoice
|
|
242
|
+
invoice,
|
|
232
243
|
items: await InvoiceItem.findAll({ where: { invoice_id: checkoutSession.invoice_id } }),
|
|
233
244
|
};
|
|
234
245
|
}
|
|
@@ -8,6 +8,7 @@ import { invoiceQueue } from '../../jobs/invoice';
|
|
|
8
8
|
import { subscriptionQueue } from '../../jobs/subscription';
|
|
9
9
|
import type { CallbackArgs } from '../../libs/auth';
|
|
10
10
|
import { wallet } from '../../libs/auth';
|
|
11
|
+
import { getGasPayerExtra } from '../../libs/payment';
|
|
11
12
|
import { getFastCheckoutAmount } from '../../libs/session';
|
|
12
13
|
import { getTxMetadata } from '../../libs/util';
|
|
13
14
|
import type { TLineItemExpanded } from '../../store/models';
|
|
@@ -58,7 +59,7 @@ export default {
|
|
|
58
59
|
},
|
|
59
60
|
nonce: checkoutSessionId,
|
|
60
61
|
requirement: {
|
|
61
|
-
tokens: [{ address: paymentCurrency.contract as string, value: amount }],
|
|
62
|
+
tokens: amount === '0' ? [] : [{ address: paymentCurrency.contract as string, value: amount }],
|
|
62
63
|
},
|
|
63
64
|
chainInfo: {
|
|
64
65
|
host: paymentMethod.settings?.arcblock?.api_host as string,
|
|
@@ -70,7 +71,7 @@ export default {
|
|
|
70
71
|
|
|
71
72
|
throw new Error(`Payment method ${paymentMethod.type} not supported`);
|
|
72
73
|
},
|
|
73
|
-
onAuth: async ({ userDid, userPk, claims,
|
|
74
|
+
onAuth: async ({ userDid, userPk, claims, extraParams }: CallbackArgs) => {
|
|
74
75
|
const { checkoutSessionId } = extraParams;
|
|
75
76
|
const { checkoutSession, customer, paymentMethod, paymentCurrency, subscription } = await ensurePaymentIntent(
|
|
76
77
|
checkoutSessionId,
|
|
@@ -109,10 +110,14 @@ export default {
|
|
|
109
110
|
|
|
110
111
|
// execute the delegate tx
|
|
111
112
|
const tx: Partial<Transaction> = client.decodeTx(claim.origin);
|
|
113
|
+
tx.signature = claim.sig;
|
|
114
|
+
|
|
115
|
+
// @ts-ignore
|
|
116
|
+
const { buffer } = await client.encodeDelegateTx({ tx });
|
|
112
117
|
const txHash = await client.sendDelegateTx(
|
|
113
118
|
// @ts-ignore
|
|
114
|
-
{ tx, wallet: fromPublicKey(userPk, toTypeInfo(userDid))
|
|
115
|
-
|
|
119
|
+
{ tx, wallet: fromPublicKey(userPk, toTypeInfo(userDid)) },
|
|
120
|
+
getGasPayerExtra(buffer)
|
|
116
121
|
);
|
|
117
122
|
|
|
118
123
|
await subscription.update({
|
|
@@ -35,7 +35,7 @@ export class PaymentIntent extends Model<InferAttributes<PaymentIntent>, InferCr
|
|
|
35
35
|
declare last_charge?: string;
|
|
36
36
|
|
|
37
37
|
// The payment error encountered in the previous PaymentIntent confirmation
|
|
38
|
-
declare last_payment_error
|
|
38
|
+
declare last_payment_error: PaymentError | null;
|
|
39
39
|
|
|
40
40
|
declare metadata?: Record<string, any>;
|
|
41
41
|
|
|
@@ -22,7 +22,7 @@ export class SetupIntent extends Model<InferAttributes<SetupIntent>, InferCreati
|
|
|
22
22
|
declare customer_id: string;
|
|
23
23
|
|
|
24
24
|
// The setup error encountered in the previous SetupIntent confirmation
|
|
25
|
-
declare last_setup_error
|
|
25
|
+
declare last_setup_error: PaymentError | null;
|
|
26
26
|
|
|
27
27
|
declare metadata?: Record<string, any>;
|
|
28
28
|
|
package/blocklet.yml
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "payment-kit",
|
|
3
|
-
"version": "1.13.
|
|
3
|
+
"version": "1.13.50",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"dev": "blocklet dev",
|
|
6
6
|
"eject": "vite eject",
|
|
@@ -44,6 +44,7 @@
|
|
|
44
44
|
"@arcblock/did-auth-storage-nedb": "^1.7.1",
|
|
45
45
|
"@arcblock/did-connect": "^2.8.7",
|
|
46
46
|
"@arcblock/did-util": "^1.18.95",
|
|
47
|
+
"@arcblock/jwt": "^1.18.95",
|
|
47
48
|
"@arcblock/ux": "^2.8.7",
|
|
48
49
|
"@blocklet/logger": "1.16.17",
|
|
49
50
|
"@blocklet/sdk": "1.16.17",
|
|
@@ -103,7 +104,7 @@
|
|
|
103
104
|
"@abtnode/types": "1.16.17",
|
|
104
105
|
"@arcblock/eslint-config": "^0.2.4",
|
|
105
106
|
"@arcblock/eslint-config-ts": "^0.2.4",
|
|
106
|
-
"@did-pay/types": "1.13.
|
|
107
|
+
"@did-pay/types": "1.13.50",
|
|
107
108
|
"@types/cookie-parser": "^1.4.5",
|
|
108
109
|
"@types/cors": "^2.8.15",
|
|
109
110
|
"@types/dotenv-flow": "^3.3.2",
|
|
@@ -140,5 +141,5 @@
|
|
|
140
141
|
"parser": "typescript"
|
|
141
142
|
}
|
|
142
143
|
},
|
|
143
|
-
"gitHead": "
|
|
144
|
+
"gitHead": "7bdfa2019c557823145e8d262c887b9066c90d04"
|
|
144
145
|
}
|
|
@@ -6,7 +6,7 @@ import { joinURL } from 'ufo';
|
|
|
6
6
|
const getTxLink = (method: TPaymentMethod, details: PaymentDetails) => {
|
|
7
7
|
if (method.type === 'arcblock') {
|
|
8
8
|
return {
|
|
9
|
-
link: joinURL(method.settings.arcblock?.explorer_host as string, '/
|
|
9
|
+
link: joinURL(method.settings.arcblock?.explorer_host as string, '/txs', details.arcblock?.tx_hash as string),
|
|
10
10
|
text: details.arcblock?.tx_hash as string,
|
|
11
11
|
};
|
|
12
12
|
}
|
|
@@ -37,8 +37,16 @@ const getTxLink = (method: TPaymentMethod, details: PaymentDetails) => {
|
|
|
37
37
|
return { text: 'N/A', link: '' };
|
|
38
38
|
};
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
TxLink.defaultProps = {
|
|
41
|
+
mode: 'dashboard',
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export default function TxLink(props: {
|
|
45
|
+
details: PaymentDetails;
|
|
46
|
+
method: TPaymentMethod;
|
|
47
|
+
mode?: 'customer' | 'dashboard';
|
|
48
|
+
}) {
|
|
49
|
+
if (!props.details || (props.mode === 'customer' && props.method.type === 'stripe')) {
|
|
42
50
|
return (
|
|
43
51
|
<Typography component="small" color="text.secondary">
|
|
44
52
|
None
|
|
@@ -62,7 +62,7 @@ export default function CustomerInvoiceList({ customer_id }: Props) {
|
|
|
62
62
|
const grouped = groupByDate(data.list);
|
|
63
63
|
|
|
64
64
|
return (
|
|
65
|
-
<Stack direction="column" gap={
|
|
65
|
+
<Stack direction="column" gap={1} sx={{ mt: 1 }}>
|
|
66
66
|
{Object.entries(grouped).map(([date, invoices]) => (
|
|
67
67
|
<Box key={date}>
|
|
68
68
|
<Typography sx={{ fontWeight: 'bold', color: 'text.secondary', mt: 2, mb: 1 }}>{date}</Typography>
|
|
@@ -73,6 +73,7 @@ export default function CustomerInvoiceList({ customer_id }: Props) {
|
|
|
73
73
|
xs: 'column',
|
|
74
74
|
sm: 'row',
|
|
75
75
|
}}
|
|
76
|
+
sx={{ my: 1 }}
|
|
76
77
|
gap={{
|
|
77
78
|
xs: 0.5,
|
|
78
79
|
sm: 1.5,
|
|
@@ -111,7 +111,7 @@ export default function CustomerHome() {
|
|
|
111
111
|
label={t('common.txHash')}
|
|
112
112
|
value={
|
|
113
113
|
data.paymentIntent?.payment_details ? (
|
|
114
|
-
<TxLink details={data.paymentIntent.payment_details} method={data.paymentMethod} />
|
|
114
|
+
<TxLink details={data.paymentIntent.payment_details} method={data.paymentMethod} mode="customer" />
|
|
115
115
|
) : (
|
|
116
116
|
''
|
|
117
117
|
)
|