payment-kit 1.13.106 → 1.13.107

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.
@@ -0,0 +1,12 @@
1
+ /* eslint-disable global-require */
2
+
3
+ const isDevelopment = process.env.BLOCKLET_MODE === 'development';
4
+
5
+ if (isDevelopment) {
6
+ // rename `require` to skip deps resolve when bundling
7
+ const r = require;
8
+ r('ts-node').register();
9
+ r('../src/hooks/pre-flight');
10
+ } else {
11
+ require('../dist/hooks/pre-flight');
12
+ }
@@ -0,0 +1,18 @@
1
+ import '@blocklet/sdk/lib/error-handler';
2
+
3
+ import dotenv from 'dotenv-flow';
4
+
5
+ import { ensureSqliteBinaryFile } from '../libs/hooks';
6
+
7
+ dotenv.config({ silent: true });
8
+
9
+ (async () => {
10
+ try {
11
+ await ensureSqliteBinaryFile();
12
+ await import('../store/migrate').then((m) => m.default());
13
+ process.exit(0);
14
+ } catch (err) {
15
+ console.error('pre-flight error', err.message);
16
+ process.exit(1);
17
+ }
18
+ })();
@@ -2,20 +2,19 @@ import '@blocklet/sdk/lib/error-handler';
2
2
 
3
3
  import dotenv from 'dotenv-flow';
4
4
 
5
- import { ensureSqliteBinaryFile } from '../libs/hooks';
6
- import logger from '../libs/logger';
5
+ import { initPaywallResources } from '../libs/resource';
6
+ import { initialize } from '../store/models';
7
+ import { sequelize } from '../store/sequelize';
7
8
 
8
- dotenv.config();
9
-
10
- const { name } = require('../../../package.json');
9
+ dotenv.config({ silent: true });
11
10
 
12
11
  (async () => {
13
12
  try {
14
- await ensureSqliteBinaryFile();
15
- await import('../store/migrate').then((m) => m.default());
13
+ initialize(sequelize);
14
+ await initPaywallResources();
16
15
  process.exit(0);
17
16
  } catch (err) {
18
- logger.error(`${name} pre-start error`, err.message);
17
+ console.error('pre-start error', err.message);
19
18
  process.exit(1);
20
19
  }
21
20
  })();
@@ -137,3 +137,12 @@ export async function ensurePassportRevoked(subscription: Subscription) {
137
137
  merge(info, { did: checkoutSession.customer_did, passports })
138
138
  );
139
139
  }
140
+
141
+ export async function updatePassportExtra(name: string, updates: any) {
142
+ const { role } = await blocklet.getRole(name);
143
+ if (!role) {
144
+ throw new Error(`passport ${name} not found`);
145
+ }
146
+ const result = await blocklet.updateRole(name, { extra: JSON.stringify(merge(role.extra, updates)) });
147
+ return result.role;
148
+ }
@@ -1,23 +1,20 @@
1
+ /* eslint-disable no-console */
1
2
  import { spawnSync } from 'child_process';
2
3
  import { chmodSync, existsSync, mkdirSync, symlinkSync } from 'fs';
3
4
  import { dirname, join } from 'path';
4
5
 
5
- import logger from './logger';
6
-
7
- const { name } = require('../../../package.json');
8
-
9
6
  // eslint-disable-next-line import/prefer-default-export
10
7
  export async function ensureSqliteBinaryFile() {
11
- logger.info(`${name} ensure sqlite3 installed`);
8
+ console.info('ensure sqlite3 installed');
12
9
 
13
10
  try {
14
11
  await import('sqlite3');
15
- logger.info(`${name} sqlite3 already installed`);
12
+ console.info('sqlite3 already installed');
16
13
  return;
17
14
  } catch {
18
15
  /* empty */
19
16
  }
20
- logger.info(`${name} try install sqlite3`);
17
+ console.info('try install sqlite3');
21
18
 
22
19
  const appDir = process.env.BLOCKLET_APP_DIR!;
23
20
 
@@ -31,7 +28,7 @@ export async function ensureSqliteBinaryFile() {
31
28
  chmodSync(binPath, '755');
32
29
  }
33
30
  } catch (error) {
34
- logger.warn(error.message);
31
+ console.warn(error.message);
35
32
  }
36
33
 
37
34
  spawnSync('npm', ['run', 'install'], {
@@ -8,19 +8,12 @@ interface Logger {
8
8
  warn: (...args: any[]) => void;
9
9
  }
10
10
 
11
- const consoleLogger: Logger = {
12
- debug: console.log,
13
- info: console.log,
14
- error: console.log,
15
- warn: console.warn,
16
- };
17
-
18
11
  const init = (label: string): Logger => {
19
12
  const instance = createLogger(label || '');
20
13
  return instance;
21
14
  };
22
15
 
23
- const logger = process.env.BLOCKLET_ENV === 'production' ? consoleLogger : init('app');
16
+ const logger = init('app');
24
17
 
25
18
  export default logger;
26
19
 
@@ -0,0 +1,265 @@
1
+ /* eslint-disable no-continue */
2
+ /* eslint-disable no-await-in-loop */
3
+ /* eslint-disable no-console */
4
+ import fs from 'fs';
5
+ import path from 'path';
6
+
7
+ import { getPackResources, getResources } from '@blocklet/sdk/lib/component';
8
+ import { env } from '@blocklet/sdk/lib/config';
9
+ import { fromTokenToUnit } from '@ocap/util';
10
+
11
+ import { updatePassportExtra } from '../integrations/blocklet/passport';
12
+ import { replace } from '../locales';
13
+ import { createPaymentLink } from '../routes/payment-links';
14
+ import { createPrice } from '../routes/prices';
15
+ import { createProductAndPrices } from '../routes/products';
16
+ import { PaymentCurrency, Price, Product, nextPriceId } from '../store/models';
17
+
18
+ export async function getPackResource(type: string) {
19
+ const resources = await getPackResources({
20
+ types: [
21
+ {
22
+ did: env.componentDid,
23
+ type,
24
+ },
25
+ ],
26
+ });
27
+
28
+ if (resources) {
29
+ return resources[0] || null;
30
+ }
31
+
32
+ return null;
33
+ }
34
+
35
+ export async function getResourcesByType(type: string) {
36
+ const pack = await getPackResource(type);
37
+ const resources = await getResources({ types: [{ did: env.componentDid, type }] });
38
+ return pack ? [pack, ...resources] : resources;
39
+ }
40
+
41
+ export async function initPaywallResources() {
42
+ const resources = await getResourcesByType('paywall');
43
+ if (!resources.length) {
44
+ console.info('No paywall resource found');
45
+ return;
46
+ }
47
+
48
+ // TODO: use schema validation
49
+ for (const resource of resources) {
50
+ const configPath = resource.path;
51
+ try {
52
+ console.info('try import paywall resource', resource);
53
+
54
+ const config: any = JSON.parse(
55
+ replace(fs.readFileSync(path.join(configPath!, 'config.json'), 'utf8'), {
56
+ ...env,
57
+ // @ts-ignore
58
+ monthPrice: resource.env?.MONTH_PRICE || '5',
59
+ // @ts-ignore
60
+ yearPrice: resource.env?.YEAR_PRICE || '30',
61
+ })
62
+ );
63
+ console.info('try import paywall config', config);
64
+
65
+ if (!Array.isArray(config.passports) || !config.passports.length) {
66
+ console.warn(`invalid paywall resource from ${configPath}: passport empty`);
67
+ continue;
68
+ }
69
+
70
+ if (!config.product) {
71
+ console.warn(`invalid paywall resource from ${configPath}: product empty`);
72
+ continue;
73
+ }
74
+ if (!config.product.price) {
75
+ console.warn(`invalid paywall resource from ${configPath}: product price empty`);
76
+ continue;
77
+ }
78
+
79
+ const metadata = { source: resource.did };
80
+ const currency = await PaymentCurrency.findOne({
81
+ where: { is_base_currency: true, livemode: config.product.livemode },
82
+ });
83
+ if (!currency) {
84
+ console.warn(`invalid paywall resource from ${configPath}: base currency not found`);
85
+ continue;
86
+ }
87
+
88
+ const exist = await Product.findOne({
89
+ where: { 'metadata.source': resource.did },
90
+ include: [{ model: Price, as: 'prices', order: [['created_at', 'DESC']] }],
91
+ });
92
+ if (exist) {
93
+ console.warn(`paywall resource already imported from path: ${configPath}`);
94
+
95
+ // @ts-ignore
96
+ const monthPrice = exist.prices.find(
97
+ // @ts-ignore
98
+ (price) =>
99
+ price.nickname === 'monthly-member-price' &&
100
+ price.unit_amount === fromTokenToUnit(config.product.price.month, currency.decimal).toString()
101
+ );
102
+ // @ts-ignore
103
+ const yearPrice = exist.prices.find(
104
+ // @ts-ignore
105
+ (price) =>
106
+ price.nickname === 'yearly-member-price' &&
107
+ price.unit_amount === fromTokenToUnit(config.product.price.year, currency.decimal).toString()
108
+ );
109
+
110
+ let newMonthPriceId = '';
111
+ if (!monthPrice) {
112
+ newMonthPriceId = nextPriceId();
113
+ await createPrice({
114
+ id: newMonthPriceId,
115
+ product_id: exist.id,
116
+ type: 'recurring',
117
+ model: 'standard',
118
+ nickname: 'monthly-member-price',
119
+ unit_amount: +config.product.price.month,
120
+ currency_id: currency.id,
121
+ recurring: {
122
+ interval: 'month',
123
+ interval_count: 1,
124
+ usage_type: 'licensed',
125
+ },
126
+ metadata,
127
+ });
128
+ console.warn(`paywall resource month price recreated from path: ${configPath}`);
129
+ }
130
+
131
+ let newYearPriceId = '';
132
+ if (!yearPrice) {
133
+ newYearPriceId = nextPriceId();
134
+ await createPrice({
135
+ id: newYearPriceId,
136
+ product_id: exist.id,
137
+ type: 'recurring',
138
+ model: 'standard',
139
+ nickname: 'yearly-member-price',
140
+ unit_amount: +config.product.price.year,
141
+ currency_id: currency.id,
142
+ recurring: {
143
+ interval: 'year',
144
+ interval_count: 1,
145
+ usage_type: 'licensed',
146
+ },
147
+ metadata,
148
+ });
149
+ console.warn(`paywall resource year price recreated from path: ${configPath}`);
150
+ }
151
+
152
+ // update upsell relation
153
+ if (newYearPriceId) {
154
+ console.warn(`paywall resource upsell recreated from path: ${configPath}`);
155
+ if (newMonthPriceId) {
156
+ await Price.update({ upsell: { upsells_to_id: newYearPriceId } }, { where: { id: newMonthPriceId } });
157
+ } else {
158
+ await Price.update({ upsell: { upsells_to_id: newYearPriceId } }, { where: { id: monthPrice.id } });
159
+ }
160
+ }
161
+
162
+ // Create another payment link and redo updatePassportExtra
163
+ if (newMonthPriceId) {
164
+ await Product.update({ default_price_id: newMonthPriceId }, { where: { id: exist.id }, limit: 1 });
165
+
166
+ const link = await createPaymentLink({
167
+ name: `Paywall for membership of ${config.product.name}`,
168
+ livemode: config.product.livemode,
169
+ currency_id: currency.id,
170
+ line_items: [
171
+ {
172
+ price_id: newMonthPriceId,
173
+ quantity: 1,
174
+ },
175
+ ],
176
+ metadata,
177
+ });
178
+ console.info('payment link recreated for paywall resource', { link: link.id });
179
+
180
+ await Promise.all(
181
+ config.passports.map((x: string) =>
182
+ updatePassportExtra(x, {
183
+ payment: { product: exist.id },
184
+ acquire: { pay: link.id },
185
+ })
186
+ )
187
+ );
188
+ console.info('product and payment link reassociated with passport');
189
+ }
190
+ } else {
191
+ const monthPriceId = nextPriceId();
192
+ const yearPriceId = nextPriceId();
193
+
194
+ const product = await createProductAndPrices({
195
+ name: config.product.name,
196
+ type: 'service',
197
+ description: config.product.description,
198
+ livemode: config.product.livemode,
199
+ images: [],
200
+ features: [],
201
+ metadata,
202
+ prices: [
203
+ {
204
+ id: monthPriceId,
205
+ type: 'recurring',
206
+ model: 'standard',
207
+ nickname: 'monthly-member-price',
208
+ unit_amount: +config.product.price.month,
209
+ currency_id: currency.id,
210
+ recurring: {
211
+ interval: 'month',
212
+ interval_count: 1,
213
+ usage_type: 'licensed',
214
+ },
215
+ upsell: config.product.price.upsell ? { upsells_to_id: yearPriceId } : undefined,
216
+ metadata,
217
+ },
218
+ {
219
+ id: yearPriceId,
220
+ type: 'recurring',
221
+ model: 'standard',
222
+ nickname: 'yearly-member-price',
223
+ unit_amount: +config.product.price.year,
224
+ currency_id: currency.id,
225
+ recurring: {
226
+ interval: 'year',
227
+ interval_count: 1,
228
+ usage_type: 'licensed',
229
+ },
230
+ metadata,
231
+ },
232
+ ],
233
+ });
234
+ console.info('product created for paywall resource', { product: product.id });
235
+
236
+ const link = await createPaymentLink({
237
+ name: `Paywall for membership of ${config.product.name}`,
238
+ livemode: config.product.livemode,
239
+ currency_id: currency.id,
240
+ line_items: [
241
+ {
242
+ price_id: monthPriceId,
243
+ quantity: 1,
244
+ },
245
+ ],
246
+ metadata,
247
+ });
248
+ console.info('payment link created for paywall resource', { link: link.id });
249
+
250
+ await Promise.all(
251
+ config.passports.map((x: string) =>
252
+ updatePassportExtra(x, {
253
+ payment: { product: product.id },
254
+ acquire: { pay: link.id },
255
+ })
256
+ )
257
+ );
258
+ console.info('product and payment link associated with passport');
259
+ }
260
+ console.info(`paywall resource successfully imported from path: ${configPath}`);
261
+ } catch (err) {
262
+ console.error(`failed to import paywall resource from ${configPath}`, err);
263
+ }
264
+ }
265
+ }
@@ -14,6 +14,8 @@ export const MAX_SUBSCRIPTION_ITEM_COUNT = 20;
14
14
  export const MAX_RETRY_COUNT = 20; // 2^20 seconds ~~ 12 days, total retry time: 24 days
15
15
  export const MIN_RETRY_MAIL = 13; // total retry time before sending first mail: 6 hours
16
16
 
17
+ export const CHECKOUT_SESSION_TTL = 24 * 60 * 60; // expires in 24 hours
18
+
17
19
  export const STRIPE_API_VERSION = '2023-08-16';
18
20
  export const STRIPE_ENDPOINT: string = getUrl('/api/integrations/stripe/webhook');
19
21
  export const STRIPE_EVENTS: any[] = [
@@ -1,10 +1,71 @@
1
+ /* eslint-disable no-await-in-loop */
2
+ import { Op } from 'sequelize';
3
+
1
4
  import { mintNftForCheckoutSession } from '../integrations/blockchain/nft';
2
5
  import { ensurePassportIssued, ensurePassportRevoked } from '../integrations/blocklet/passport';
6
+ import dayjs from '../libs/dayjs';
3
7
  import { events } from '../libs/event';
4
8
  import logger from '../libs/logger';
5
- import { CheckoutSession, Price, Subscription } from '../store/models';
9
+ import createQueue from '../libs/queue';
10
+ import {
11
+ CheckoutSession,
12
+ Invoice,
13
+ InvoiceItem,
14
+ PaymentIntent,
15
+ Price,
16
+ SetupIntent,
17
+ Subscription,
18
+ SubscriptionItem,
19
+ } from '../store/models';
6
20
  import { subscriptionQueue } from './subscription';
7
21
 
22
+ type CheckoutSessionJob = {
23
+ id: string;
24
+ action: 'expire';
25
+ };
26
+
27
+ export const checkoutSessionQueue = createQueue<CheckoutSessionJob>({
28
+ name: 'checkoutSession',
29
+ onJob: handleCheckoutSessionJob,
30
+ options: {
31
+ concurrency: 10,
32
+ maxRetries: 3,
33
+ enableScheduledJob: true,
34
+ },
35
+ });
36
+
37
+ export async function handleCheckoutSessionJob(job: CheckoutSessionJob): Promise<void> {
38
+ const checkoutSession = await CheckoutSession.findByPk(job.id);
39
+ if (!checkoutSession) {
40
+ return;
41
+ }
42
+ if (job.action === 'expire') {
43
+ if (checkoutSession.status !== 'open') {
44
+ return;
45
+ }
46
+ if (checkoutSession.payment_status === 'paid') {
47
+ logger.info('Skip expire CheckoutSession since payment status is paid', {
48
+ checkoutSession: checkoutSession.id,
49
+ paymentIntent: checkoutSession.payment_intent_id,
50
+ });
51
+ return;
52
+ }
53
+
54
+ const now = dayjs().unix();
55
+ if (checkoutSession.expires_at > now) {
56
+ checkoutSessionQueue.push({
57
+ id: checkoutSession.id,
58
+ job: { id: checkoutSession.id, action: 'expire' },
59
+ runAt: checkoutSession.expires_at,
60
+ });
61
+ return;
62
+ }
63
+
64
+ await checkoutSession.update({ status: 'expired' });
65
+ logger.info('CheckoutSession expired', { checkoutSession: checkoutSession.id });
66
+ }
67
+ }
68
+
8
69
  // eslint-disable-next-line require-await
9
70
  export async function startCheckoutSessionQueue() {
10
71
  events.on('checkout.session.completed', (checkoutSession: CheckoutSession) => {
@@ -42,4 +103,83 @@ export async function startCheckoutSessionQueue() {
42
103
  runAt: subscription.current_period_end,
43
104
  });
44
105
  });
106
+
107
+ events.on('checkout.session.created', (checkoutSession: CheckoutSession) => {
108
+ if (checkoutSession.expires_at) {
109
+ checkoutSessionQueue.push({
110
+ id: checkoutSession.id,
111
+ job: { id: checkoutSession.id, action: 'expire' },
112
+ runAt: checkoutSession.expires_at,
113
+ });
114
+ }
115
+ });
116
+
117
+ events.on('checkout.session.expired', async (checkoutSession: CheckoutSession) => {
118
+ // Do some cleanup
119
+ if (checkoutSession.invoice_id) {
120
+ await InvoiceItem.destroy({ where: { invoice_id: checkoutSession.invoice_id } });
121
+ await Invoice.destroy({ where: { id: checkoutSession.invoice_id } });
122
+ logger.info('Invoice and InvoiceItem for checkout session deleted on expire', {
123
+ checkoutSession: checkoutSession.id,
124
+ invoice: checkoutSession.invoice_id,
125
+ });
126
+ }
127
+ if (checkoutSession.setup_intent_id) {
128
+ await SetupIntent.destroy({ where: { id: checkoutSession.setup_intent_id } });
129
+ logger.info('SetupIntent for checkout session deleted on expire', {
130
+ checkoutSession: checkoutSession.id,
131
+ setupIntent: checkoutSession.setup_intent_id,
132
+ });
133
+ }
134
+ if (checkoutSession.payment_intent_id && checkoutSession.payment_status !== 'paid') {
135
+ await PaymentIntent.destroy({ where: { id: checkoutSession.payment_intent_id } });
136
+ logger.info('PaymentIntent for checkout session deleted on expire', {
137
+ checkoutSession: checkoutSession.id,
138
+ paymentIntent: checkoutSession.payment_intent_id,
139
+ });
140
+ }
141
+ if (checkoutSession.subscription_id) {
142
+ await SubscriptionItem.destroy({ where: { subscription_id: checkoutSession.subscription_id } });
143
+ await Subscription.destroy({ where: { id: checkoutSession.subscription_id } });
144
+ logger.info('Subscription and SubscriptionItem for checkout session deleted on expire', {
145
+ checkoutSession: checkoutSession.id,
146
+ subscription: checkoutSession.subscription_id,
147
+ });
148
+ }
149
+
150
+ // update price lock status
151
+ for (const item of checkoutSession.line_items) {
152
+ const price = await Price.findByPk(item.price_id);
153
+ if (price?.locked) {
154
+ const used = await price.isUsed();
155
+ if (!used) {
156
+ await price.update({ locked: false });
157
+ logger.info('Price for checkout session unlocked on expire', {
158
+ checkoutSession: checkoutSession.id,
159
+ priceId: item.price_id,
160
+ });
161
+ }
162
+ }
163
+ }
164
+ });
165
+
166
+ // Auto populate subscription queue
167
+ const now = dayjs().unix();
168
+ const checkoutSessions = await CheckoutSession.findAll({
169
+ where: {
170
+ status: 'open',
171
+ expires_at: { [Op.lte]: now },
172
+ },
173
+ });
174
+
175
+ checkoutSessions.forEach(async (checkoutSession) => {
176
+ const exist = await checkoutSessionQueue.get(checkoutSession.id);
177
+ if (!exist) {
178
+ checkoutSessionQueue.push({
179
+ id: checkoutSession.id,
180
+ job: { id: checkoutSession.id, action: 'expire' },
181
+ runAt: checkoutSession.expires_at,
182
+ });
183
+ }
184
+ });
45
185
  }
@@ -33,7 +33,7 @@ import {
33
33
  isLineItemAligned,
34
34
  } from '../libs/session';
35
35
  import { getDaysUntilDue } from '../libs/subscription';
36
- import { createCodeGenerator, formatMetadata, getDataObjectFromQuery } from '../libs/util';
36
+ import { CHECKOUT_SESSION_TTL, createCodeGenerator, formatMetadata, getDataObjectFromQuery } from '../libs/util';
37
37
  import { invoiceQueue } from '../queues/invoice';
38
38
  import { paymentQueue } from '../queues/payment';
39
39
  import { subscriptionQueue } from '../queues/subscription';
@@ -127,7 +127,7 @@ export const formatCheckoutSession = async (payload: any, throwOnEmptyItems = tr
127
127
  }
128
128
 
129
129
  if (!raw.expires_at) {
130
- raw.expires_at = dayjs().unix() + 60 * 60 * 24; // 24 hours after creation
130
+ raw.expires_at = dayjs().unix() + CHECKOUT_SESSION_TTL; // 24 hours after creation
131
131
  }
132
132
 
133
133
  if (raw.nft_mint_settings?.enabled) {
@@ -924,6 +924,16 @@ router.put('/:id/downsell', user, ensureCheckoutSessionOpen, async (req, res) =>
924
924
  router.put('/:id/expire', auth, ensureCheckoutSessionOpen, async (req, res) => {
925
925
  const doc = req.doc as CheckoutSession;
926
926
 
927
+ if (doc.status === 'complete') {
928
+ return res.status(400).json({ error: 'Cannot expire checkout session that is already completed' });
929
+ }
930
+ if (doc.status === 'expired') {
931
+ return res.status(400).json({ error: 'Cannot expire checkout session that is already expired' });
932
+ }
933
+ if (doc.payment_status === 'paid') {
934
+ return res.status(400).json({ error: 'Cannot expire checkout session that is already paid' });
935
+ }
936
+
927
937
  await doc.update({ status: 'expired', expires_at: dayjs().unix() });
928
938
 
929
939
  res.json(doc);
@@ -1,6 +1,6 @@
1
1
  import { Router } from 'express';
2
- import merge from 'lodash/merge';
3
2
 
3
+ import { updatePassportExtra } from '../integrations/blocklet/passport';
4
4
  import { blocklet } from '../libs/auth';
5
5
  import { authenticate } from '../libs/security';
6
6
  import { PaymentLink, PricingTable, Product } from '../store/models';
@@ -13,15 +13,6 @@ router.get('/', auth, async (_, res) => {
13
13
  res.json(result.roles);
14
14
  });
15
15
 
16
- const updateRoleExtra = async (name: string, updates: any) => {
17
- const { role } = await blocklet.getRole(name);
18
- if (!role) {
19
- throw new Error(`passport ${name} not found`);
20
- }
21
- const result = await blocklet.updateRole(name, { extra: JSON.stringify(merge(role.extra, updates)) });
22
- return result.role;
23
- };
24
-
25
16
  router.put('/assign', auth, async (req, res) => {
26
17
  const { name, id } = req.body;
27
18
 
@@ -38,7 +29,7 @@ router.put('/assign', auth, async (req, res) => {
38
29
  return res.status(400).json({ message: 'payment link is not active' });
39
30
  }
40
31
 
41
- const result = await updateRoleExtra(name, { acquire: { pay: id } });
32
+ const result = await updatePassportExtra(name, { acquire: { pay: id } });
42
33
  return res.json(result);
43
34
  }
44
35
 
@@ -48,7 +39,7 @@ router.put('/assign', auth, async (req, res) => {
48
39
  return res.status(400).json({ message: 'pricing table is not active' });
49
40
  }
50
41
 
51
- const result = await updateRoleExtra(name, { acquire: { pay: id } });
42
+ const result = await updatePassportExtra(name, { acquire: { pay: id } });
52
43
  return res.json(result);
53
44
  }
54
45
 
@@ -59,7 +50,7 @@ router.put('/assign', auth, async (req, res) => {
59
50
  }
60
51
 
61
52
  await doc.update({ metadata: { ...doc.metadata, passport: name } });
62
- const result = await updateRoleExtra(name, { payment: { product: id } });
53
+ const result = await updatePassportExtra(name, { payment: { product: id } });
63
54
  return res.json(result);
64
55
  }
65
56
 
@@ -67,7 +58,10 @@ router.put('/assign', auth, async (req, res) => {
67
58
  });
68
59
 
69
60
  router.delete('/assign/:name', auth, async (req, res) => {
70
- const result = await updateRoleExtra(req.params.name as string, { payment: { product: '' }, acquire: { pay: '' } });
61
+ const result = await updatePassportExtra(req.params.name as string, {
62
+ payment: { product: '' },
63
+ acquire: { pay: '' },
64
+ });
71
65
  return res.json(result);
72
66
  });
73
67