payment-kit 1.16.2 → 1.16.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/api/src/crons/index.ts
CHANGED
|
@@ -97,7 +97,7 @@ function init() {
|
|
|
97
97
|
name: 'metering.subscription.detection',
|
|
98
98
|
time: meteringSubscriptionDetectionCronTime,
|
|
99
99
|
fn: () => createMeteringSubscriptionDetection(),
|
|
100
|
-
options: { runOnInit:
|
|
100
|
+
options: { runOnInit: true },
|
|
101
101
|
},
|
|
102
102
|
],
|
|
103
103
|
onError: (error: Error, name: string) => {
|
|
@@ -124,10 +124,10 @@ export class MeteringSubscriptionDetectionTemplate implements BaseEmailTemplate<
|
|
|
124
124
|
}
|
|
125
125
|
})
|
|
126
126
|
);
|
|
127
|
-
const meteringInvoiceIds = meteringInvoices.map((invoice) => invoice.id);
|
|
128
|
-
const meteringSubscriptionIds =
|
|
129
|
-
.map((invoice) => invoice?.subscription_id)
|
|
130
|
-
|
|
127
|
+
const meteringInvoiceIds = Array.from(new Set(meteringInvoices.map((invoice) => invoice.id)));
|
|
128
|
+
const meteringSubscriptionIds = Array.from(
|
|
129
|
+
new Set(meteringInvoices.map((invoice) => invoice?.subscription_id).filter(Boolean) as string[])
|
|
130
|
+
);
|
|
131
131
|
|
|
132
132
|
const abnormalSubscriptions = await this.getAbnormalSubscriptions(meteringInvoiceIds, meteringSubscriptionIds);
|
|
133
133
|
const userDid = await getOwnerDid();
|
|
@@ -141,7 +141,7 @@ export class MeteringSubscriptionDetectionTemplate implements BaseEmailTemplate<
|
|
|
141
141
|
locale,
|
|
142
142
|
userDid,
|
|
143
143
|
summary: {
|
|
144
|
-
totalCount:
|
|
144
|
+
totalCount: meteringSubscriptionIds.length,
|
|
145
145
|
normalCount: Math.max(0, meteringSubscriptionIds.length - abnormalSubscriptions.subscriptions.length),
|
|
146
146
|
unreportedCount: abnormalSubscriptions.unreported.length,
|
|
147
147
|
discrepantCount: abnormalSubscriptions.discrepant.length,
|
package/api/src/libs/util.ts
CHANGED
|
@@ -319,6 +319,26 @@ export async function getOwnerDid() {
|
|
|
319
319
|
}
|
|
320
320
|
}
|
|
321
321
|
|
|
322
|
+
export async function getDidListByRole(role: string | string[]) {
|
|
323
|
+
try {
|
|
324
|
+
if (Array.isArray(role)) {
|
|
325
|
+
const didSet = new Set<string>();
|
|
326
|
+
await Promise.all(
|
|
327
|
+
role.map(async (r: string) => {
|
|
328
|
+
const { users } = await blocklet.getUsers({ query: { role: r } });
|
|
329
|
+
users.forEach((u) => didSet.add(u.did));
|
|
330
|
+
})
|
|
331
|
+
);
|
|
332
|
+
return Array.from(didSet);
|
|
333
|
+
}
|
|
334
|
+
const { users } = await blocklet.getUsers({ query: { role } });
|
|
335
|
+
return users.map((x: any) => x?.did);
|
|
336
|
+
} catch (error) {
|
|
337
|
+
logger.error('getDidListByRole error', error);
|
|
338
|
+
return null;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
322
342
|
export function getSubscriptionNotificationCustomActions(
|
|
323
343
|
subscription: Subscription,
|
|
324
344
|
eventType: string,
|
|
@@ -2,8 +2,11 @@
|
|
|
2
2
|
import type { Transaction } from '@ocap/client';
|
|
3
3
|
import { fromAddress } from '@ocap/wallet';
|
|
4
4
|
|
|
5
|
+
import { toBase58 } from '@ocap/util';
|
|
6
|
+
import { encodeTransferItx } from 'api/src/integrations/ethereum/token';
|
|
7
|
+
import { waitForEvmTxConfirm, waitForEvmTxReceipt } from 'api/src/integrations/ethereum/tx';
|
|
5
8
|
import type { CallbackArgs } from '../../libs/auth';
|
|
6
|
-
import { wallet } from '../../libs/auth';
|
|
9
|
+
import { ethWallet, wallet } from '../../libs/auth';
|
|
7
10
|
import { getGasPayerExtra } from '../../libs/payment';
|
|
8
11
|
import { getTxMetadata } from '../../libs/util';
|
|
9
12
|
import { invoiceQueue } from '../../queues/invoice';
|
|
@@ -59,30 +62,30 @@ export default {
|
|
|
59
62
|
return claims;
|
|
60
63
|
}
|
|
61
64
|
|
|
65
|
+
if (paymentMethod.type === 'ethereum') {
|
|
66
|
+
return {
|
|
67
|
+
signature: {
|
|
68
|
+
type: 'eth:transaction',
|
|
69
|
+
data: toBase58(
|
|
70
|
+
Buffer.from(
|
|
71
|
+
JSON.stringify({
|
|
72
|
+
network: paymentMethod.settings?.ethereum?.chain_id,
|
|
73
|
+
tx: encodeTransferItx(ethWallet.address, amount!, paymentCurrency.contract),
|
|
74
|
+
}),
|
|
75
|
+
'utf-8'
|
|
76
|
+
)
|
|
77
|
+
),
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
62
82
|
throw new Error(`Payment method ${paymentMethod.type} not supported`);
|
|
63
83
|
},
|
|
64
84
|
onAuth: async ({ request, userDid, claims, extraParams }: CallbackArgs) => {
|
|
65
85
|
const { subscriptionId, currencyId } = extraParams;
|
|
66
86
|
const { invoices, paymentMethod } = await ensureSubscriptionForCollectBatch(subscriptionId, currencyId);
|
|
67
87
|
|
|
68
|
-
|
|
69
|
-
const client = paymentMethod.getOcapClient();
|
|
70
|
-
const claim = claims.find((x) => x.type === 'prepareTx');
|
|
71
|
-
|
|
72
|
-
const tx: Partial<Transaction> = client.decodeTx(claim.finalTx);
|
|
73
|
-
if (claim.delegator && claim.from) {
|
|
74
|
-
tx.delegator = claim.delegator;
|
|
75
|
-
tx.from = claim.from;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// @ts-ignore
|
|
79
|
-
const { buffer } = await client.encodeTransferV3Tx({ tx });
|
|
80
|
-
const txHash = await client.sendTransferV3Tx(
|
|
81
|
-
// @ts-ignore
|
|
82
|
-
{ tx, wallet: fromAddress(userDid) },
|
|
83
|
-
getGasPayerExtra(buffer, client.pickGasPayerHeaders(request))
|
|
84
|
-
);
|
|
85
|
-
|
|
88
|
+
const afterTxExecution = async (paymentDetails: any) => {
|
|
86
89
|
const paymentIntents = await PaymentIntent.findAll({
|
|
87
90
|
where: {
|
|
88
91
|
invoice_id: invoices,
|
|
@@ -95,11 +98,7 @@ export default {
|
|
|
95
98
|
capture_method: 'manual',
|
|
96
99
|
last_payment_error: null,
|
|
97
100
|
payment_details: {
|
|
98
|
-
|
|
99
|
-
tx_hash: txHash,
|
|
100
|
-
payer: userDid,
|
|
101
|
-
type: 'transfer',
|
|
102
|
-
},
|
|
101
|
+
[paymentMethod.type]: paymentDetails,
|
|
103
102
|
},
|
|
104
103
|
});
|
|
105
104
|
|
|
@@ -117,10 +116,52 @@ export default {
|
|
|
117
116
|
}
|
|
118
117
|
}
|
|
119
118
|
}
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
if (paymentMethod.type === 'arcblock') {
|
|
122
|
+
const client = paymentMethod.getOcapClient();
|
|
123
|
+
const claim = claims.find((x) => x.type === 'prepareTx');
|
|
124
|
+
|
|
125
|
+
const tx: Partial<Transaction> = client.decodeTx(claim.finalTx);
|
|
126
|
+
if (claim.delegator && claim.from) {
|
|
127
|
+
tx.delegator = claim.delegator;
|
|
128
|
+
tx.from = claim.from;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// @ts-ignore
|
|
132
|
+
const { buffer } = await client.encodeTransferV3Tx({ tx });
|
|
133
|
+
const txHash = await client.sendTransferV3Tx(
|
|
134
|
+
// @ts-ignore
|
|
135
|
+
{ tx, wallet: fromAddress(userDid) },
|
|
136
|
+
getGasPayerExtra(buffer, client.pickGasPayerHeaders(request))
|
|
137
|
+
);
|
|
138
|
+
await afterTxExecution({ tx_hash: txHash, payer: userDid, type: 'transfer' });
|
|
120
139
|
|
|
121
140
|
return { hash: txHash };
|
|
122
141
|
}
|
|
142
|
+
if (paymentMethod.type === 'ethereum') {
|
|
143
|
+
const client = paymentMethod.getEvmClient();
|
|
144
|
+
const claim = claims.find((x) => x.type === 'signature');
|
|
123
145
|
|
|
146
|
+
const receipt = await waitForEvmTxReceipt(client, claim.hash);
|
|
147
|
+
if (!receipt.status) {
|
|
148
|
+
throw new Error(`EVM Transaction failed: ${claim.hash}`);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
waitForEvmTxConfirm(client, Number(receipt.blockNumber), paymentMethod.confirmation.block)
|
|
152
|
+
.then(async () => {
|
|
153
|
+
await afterTxExecution({
|
|
154
|
+
tx_hash: claim.hash,
|
|
155
|
+
block_height: receipt.blockNumber.toString(),
|
|
156
|
+
gas_used: receipt.gasUsed.toString(),
|
|
157
|
+
gas_price: receipt.gasPrice.toString(),
|
|
158
|
+
payer: userDid,
|
|
159
|
+
type: 'transfer',
|
|
160
|
+
});
|
|
161
|
+
})
|
|
162
|
+
.catch(console.error);
|
|
163
|
+
return { hash: claim.hash };
|
|
164
|
+
}
|
|
124
165
|
throw new Error(`Payment method ${paymentMethod.type} not supported`);
|
|
125
166
|
},
|
|
126
167
|
};
|
|
@@ -6,7 +6,8 @@ import isObject from 'lodash/isObject';
|
|
|
6
6
|
import pick from 'lodash/pick';
|
|
7
7
|
import uniq from 'lodash/uniq';
|
|
8
8
|
|
|
9
|
-
import { literal, OrderItem } from 'sequelize';
|
|
9
|
+
import { literal, Op, OrderItem } from 'sequelize';
|
|
10
|
+
import { BN } from '@ocap/util';
|
|
10
11
|
import { createEvent } from '../libs/audit';
|
|
11
12
|
import {
|
|
12
13
|
ensureStripeCustomer,
|
|
@@ -1858,4 +1859,60 @@ router.get('/:id/recharge', authMine, async (req, res) => {
|
|
|
1858
1859
|
return res.status(400).json({ error: err.message });
|
|
1859
1860
|
}
|
|
1860
1861
|
});
|
|
1862
|
+
|
|
1863
|
+
router.get('/:id/overdue/invoices', authPortal, async (req, res) => {
|
|
1864
|
+
try {
|
|
1865
|
+
const subscription = await Subscription.findByPk(req.params.id, {
|
|
1866
|
+
include: [{ model: Customer, as: 'customer' }],
|
|
1867
|
+
});
|
|
1868
|
+
if (!subscription) {
|
|
1869
|
+
return res.status(404).json({ error: 'Subscription not found' });
|
|
1870
|
+
}
|
|
1871
|
+
// @ts-ignore
|
|
1872
|
+
if (subscription.customer?.did !== req.user?.did) {
|
|
1873
|
+
return res.status(403).json({ error: 'You are not allowed to access this subscription' });
|
|
1874
|
+
}
|
|
1875
|
+
const { rows: invoices, count } = await Invoice.findAndCountAll({
|
|
1876
|
+
where: {
|
|
1877
|
+
subscription_id: subscription.id,
|
|
1878
|
+
status: ['uncollectible'],
|
|
1879
|
+
amount_remaining: { [Op.gt]: '0' },
|
|
1880
|
+
},
|
|
1881
|
+
include: [
|
|
1882
|
+
{ model: PaymentCurrency, as: 'paymentCurrency' },
|
|
1883
|
+
{ model: PaymentMethod, as: 'paymentMethod' },
|
|
1884
|
+
],
|
|
1885
|
+
});
|
|
1886
|
+
if (count === 0) {
|
|
1887
|
+
return res.json({ subscription, invoices: [], summary: null });
|
|
1888
|
+
}
|
|
1889
|
+
const summary: Record<string, { amount: string; currency: PaymentCurrency; method: PaymentMethod }> = {};
|
|
1890
|
+
invoices.forEach((invoice) => {
|
|
1891
|
+
const key = invoice.currency_id;
|
|
1892
|
+
if (!summary[key]) {
|
|
1893
|
+
summary[key] = {
|
|
1894
|
+
amount: '0',
|
|
1895
|
+
// @ts-ignore
|
|
1896
|
+
currency: invoice.paymentCurrency,
|
|
1897
|
+
// @ts-ignore
|
|
1898
|
+
method: invoice.paymentMethod,
|
|
1899
|
+
};
|
|
1900
|
+
}
|
|
1901
|
+
if (invoice && summary[key]) {
|
|
1902
|
+
// @ts-ignore
|
|
1903
|
+
summary[key].amount = new BN(summary[key]?.amount || '0')
|
|
1904
|
+
.add(new BN(invoice.amount_remaining || '0'))
|
|
1905
|
+
.toString();
|
|
1906
|
+
}
|
|
1907
|
+
});
|
|
1908
|
+
return res.json({
|
|
1909
|
+
subscription,
|
|
1910
|
+
summary,
|
|
1911
|
+
invoices,
|
|
1912
|
+
});
|
|
1913
|
+
} catch (err) {
|
|
1914
|
+
console.error(err);
|
|
1915
|
+
return res.status(400).json({ error: err.message });
|
|
1916
|
+
}
|
|
1917
|
+
});
|
|
1861
1918
|
export default router;
|
package/blocklet.yml
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "payment-kit",
|
|
3
|
-
"version": "1.16.
|
|
3
|
+
"version": "1.16.4",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"dev": "blocklet dev --open",
|
|
6
6
|
"eject": "vite eject",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"@arcblock/validator": "^1.18.147",
|
|
54
54
|
"@blocklet/js-sdk": "1.16.33-beta-20241031-073543-49b1ff9b",
|
|
55
55
|
"@blocklet/logger": "1.16.33-beta-20241031-073543-49b1ff9b",
|
|
56
|
-
"@blocklet/payment-react": "1.16.
|
|
56
|
+
"@blocklet/payment-react": "1.16.4",
|
|
57
57
|
"@blocklet/sdk": "1.16.33-beta-20241031-073543-49b1ff9b",
|
|
58
58
|
"@blocklet/ui-react": "^2.10.67",
|
|
59
59
|
"@blocklet/uploader": "^0.1.52",
|
|
@@ -120,7 +120,7 @@
|
|
|
120
120
|
"devDependencies": {
|
|
121
121
|
"@abtnode/types": "1.16.33-beta-20241031-073543-49b1ff9b",
|
|
122
122
|
"@arcblock/eslint-config-ts": "^0.3.3",
|
|
123
|
-
"@blocklet/payment-types": "1.16.
|
|
123
|
+
"@blocklet/payment-types": "1.16.4",
|
|
124
124
|
"@types/cookie-parser": "^1.4.7",
|
|
125
125
|
"@types/cors": "^2.8.17",
|
|
126
126
|
"@types/debug": "^4.1.12",
|
|
@@ -166,5 +166,5 @@
|
|
|
166
166
|
"parser": "typescript"
|
|
167
167
|
}
|
|
168
168
|
},
|
|
169
|
-
"gitHead": "
|
|
169
|
+
"gitHead": "d2c53c8bec3a4a34d0ef3a011ec215b69bc9a5ab"
|
|
170
170
|
}
|