@opengis/pay 2.0.3 → 2.0.5

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/package.json CHANGED
@@ -1,39 +1,39 @@
1
- {
2
- "name": "@opengis/pay",
3
- "version": "2.0.3",
4
- "type": "module",
5
- "description": "pay plugins for billing",
6
- "main": "plugin.js",
7
- "browser": "plugin.js",
8
- "files": [
9
- "server/*",
10
- "module/*",
11
- "plugin.js",
12
- "config.js",
13
- "utils.js"
14
- ],
15
- "scripts": {
16
- "patch": "npm version patch && git push && npm publish",
17
- "test": "node --test",
18
- "start": "node --watch-path=server server",
19
- "admin": "set NODE_ENV=admin&& npm run start",
20
- "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore"
21
- },
22
- "dependencies": {
23
- "liqpayjs-sdk": "3.3.1",
24
- "request-promise": "4.2.6"
25
- },
26
- "devDependencies": {
27
- "dotenv": "^17.2.2",
28
- "eslint": "8.49.0",
29
- "eslint-config-airbnb": "19.0.4",
30
- "fastify": "5.3.3",
31
- "fastify-plugin": "5.0.1",
32
- "ioredis": "5.3.2",
33
- "nodemailer": "6.5.0",
34
- "pg": "8.11.3",
35
- "vitest": "^3.2.4"
36
- },
37
- "author": "Softpro",
38
- "license": "ISC"
39
- }
1
+ {
2
+ "name": "@opengis/pay",
3
+ "version": "2.0.5",
4
+ "type": "module",
5
+ "description": "pay plugins for billing",
6
+ "main": "plugin.js",
7
+ "browser": "plugin.js",
8
+ "files": [
9
+ "server/*",
10
+ "module/*",
11
+ "plugin.js",
12
+ "config.js",
13
+ "utils.js"
14
+ ],
15
+ "scripts": {
16
+ "patch": "npm version patch && git push && npm publish",
17
+ "test": "node --test",
18
+ "start": "node --watch-path=server server",
19
+ "admin": "set NODE_ENV=admin&& npm run start",
20
+ "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore"
21
+ },
22
+ "dependencies": {
23
+ "liqpayjs-sdk": "3.3.1",
24
+ "request-promise": "4.2.6"
25
+ },
26
+ "devDependencies": {
27
+ "dotenv": "^17.2.2",
28
+ "eslint": "8.49.0",
29
+ "eslint-config-airbnb": "19.0.4",
30
+ "fastify": "5.3.3",
31
+ "fastify-plugin": "5.0.1",
32
+ "ioredis": "5.3.2",
33
+ "nodemailer": "6.5.0",
34
+ "pg": "8.11.3",
35
+ "vitest": "^3.2.4"
36
+ },
37
+ "author": "Softpro",
38
+ "license": "ISC"
39
+ }
@@ -28,6 +28,7 @@ alter table pay.transactions add column if not exists paytypes text;
28
28
  alter table pay.transactions add column if not exists paytype text;
29
29
  alter table pay.transactions add column if not exists customer text;
30
30
  alter table pay.transactions add column if not exists receipt text;
31
+ alter table pay.transactions add column if not exists redirect_url text;
31
32
 
32
33
  COMMENT ON TABLE pay.transactions IS 'Транзакції';
33
34
 
@@ -52,6 +53,7 @@ COMMENT ON COLUMN pay.transactions.paytypes IS 'Дозволені типи оп
52
53
  COMMENT ON COLUMN pay.transactions.paytype IS 'Використаний тип оплати';
53
54
  COMMENT ON COLUMN pay.transactions.customer IS 'Унікальний ідентифікатор користувача на сайті мерчанта';
54
55
  COMMENT ON COLUMN pay.transactions.receipt IS 'Посилання на квітанцію сервісу оплати';
56
+ COMMENT ON COLUMN pay.transactions.redirect_url IS 'Посилання на сторінку сервісу платежів';
55
57
 
56
58
  CREATE INDEX if not exists pay_transactions_transactions_status_btree_idx ON pay.transactions USING btree (status COLLATE pg_catalog."default");
57
59
 
@@ -2,18 +2,16 @@ import config from '../../../config.js';
2
2
  import pgClients from '../pg/pgClients.js';
3
3
  import dataInsert from '../crud/dataInsert.js';
4
4
 
5
- const { paymentRedirect, table = 'pay.transactions' } = config.integrations?.pay || {};
5
+ const { table = 'pay.transactions' } = config.integrations?.pay || {};
6
6
 
7
7
  export default async function createPayment({
8
- paymentId, orderId, amount, referer, uid, service, expiredDate, description, action = 'pay', currency = 'uah', language = 'uk', paytypes,
8
+ orderId, amount, referer, uid, service, expiredDate, description, action = 'pay', currency = 'uah', language = 'uk', paytypes,
9
9
  }, pg = pgClients.client) {
10
- if (!paymentId) { throw new Error('not enough params: paymentId'); }
11
10
  if (!uid) { throw new Error('not enough params: uid'); }
12
11
  if (!service) { throw new Error('not enough params: service'); }
13
12
  if (!amount) { throw new Error('not enough params: amount'); }
14
13
 
15
14
  const result = await dataInsert({
16
- id: paymentId,
17
15
  pg,
18
16
  table,
19
17
  data: {
@@ -32,5 +30,5 @@ export default async function createPayment({
32
30
  },
33
31
  uid,
34
32
  }).then(el => el.rows?.[0]);
35
- return { id: paymentId, ...result || {} };
33
+ return { id: result?.[pg.pk?.[table]], ...result || {} };
36
34
  }
@@ -13,11 +13,11 @@ const controller = {
13
13
  };
14
14
 
15
15
  export default async function createTransaction({
16
- orderId, amount, referer, uid, debug, service, expiredDate, description, action, language, paytypes, currency,
16
+ orderId, amount, referer, uid, debug, service, expiredDate, description, action, language, paytypes, currency, deliveryEmails,
17
17
  }, pg = pgClients.client) {
18
18
  if (!service) throw new Error('not enough params: service');
19
19
  if (!controller[service]) { throw new Error('invalid params: service'); }
20
- if (amount && !uid) throw new Error('not enough params: uid');
20
+ if (!amount || !uid || !referer) throw new Error('not enough params: uid / amount / referer');
21
21
 
22
22
  if (currency && !['uah', 'usd', 'eur'].includes(currency)) {
23
23
  throw new Error('invalid params: currency');
@@ -38,6 +38,7 @@ export default async function createTransaction({
38
38
  description,
39
39
  language,
40
40
  paytypes,
41
+ deliveryEmails,
41
42
  }, pg);
42
43
  return result;
43
44
  }
@@ -3,11 +3,12 @@ import LiqPay from 'liqpayjs-sdk';
3
3
 
4
4
  import config from '../../../config.js';
5
5
  import pgClients from '../pg/pgClients.js';
6
+ import dataUpdate from '../crud/dataUpdate.js';
6
7
 
7
8
  import createPayment from './createPayment.js';
8
9
 
9
10
  const { prefix = '/api' } = config;
10
- const { table = 'pay.transactions', backUrl: bUrl } = config.integrations?.pay || {};
11
+ const { table = 'pay.transactions', backUrl } = config.integrations?.pay || {};
11
12
 
12
13
  const {
13
14
  host = 'https://www.liqpay.ua',
@@ -17,9 +18,9 @@ const {
17
18
  const liqpay = new LiqPay(publicKey, privateKey);
18
19
 
19
20
  export default async function liqpayCreateTransaction({
20
- id, orderId, amount, referer, uid, debug, expiredDate, description, paytypes, action = 'pay', currency = 'uah', language = 'uk',
21
+ id, orderId, amount, referer, uid, debug, expiredDate, description, paytypes, action = 'pay', currency = 'uah', language = 'uk', deliveryEmails,
21
22
  }, pg = pgClients.client) {
22
- const backUrl = bUrl || referer.slice(0, referer.indexOf('/', 7));
23
+ const rootUrl = referer.slice(0, referer.indexOf('/', 7));
23
24
 
24
25
  if (!publicKey || !privateKey) {
25
26
  throw new Error('invalid liqpay integration settings');
@@ -41,13 +42,10 @@ export default async function liqpayCreateTransaction({
41
42
  throw new Error('not enough params: uid required');
42
43
  }
43
44
 
44
- const paymentId = !id ? await pg.query('select next_id()').then(el => el.rows?.[0]?.next_id) : id;
45
-
46
45
  const paymentData = id && pg.pk?.[table]
47
46
  ? await pg.query(`select ${pg.pk?.[table]} as id, * from ${table} where ${pg.pk?.[table]}=$1`, [id]).then(el => el.rows?.[0])
48
47
  : await createPayment({
49
48
  service: 'liqpay',
50
- paymentId,
51
49
  orderId,
52
50
  amount,
53
51
  referer,
@@ -61,27 +59,42 @@ export default async function liqpayCreateTransaction({
61
59
  });
62
60
 
63
61
  if (!paymentData?.id) {
64
- throw new Error('payment not found / creation failed');
62
+ throw new Error('Payment not found / creation failed');
65
63
  }
66
64
 
67
65
  const paymentAmount = id ? paymentData.amount : amount;
68
66
 
69
67
  if (!paymentAmount) {
70
- throw new Error('invalid payment amount');
68
+ throw new Error('Invalid payment amount');
69
+ }
70
+
71
+ if (id && paymentData?.expired_date
72
+ && new Date(paymentData.expired_date)
73
+ && new Date() > new Date(paymentData.expired_date)) {
74
+ throw new Error('Transaction date already expired');
75
+ }
76
+
77
+ if (id && paymentData?.redirect_url) {
78
+ return paymentData.redirect_url;
71
79
  }
72
80
 
81
+ const resultUrl = `${rootUrl}${backUrl ? backUrl.replace(/{{service}}/, 'liqpay').replace(/{{id}}/, paymentData.id) : `${prefix}/liqpay/${paymentData.id}/success`}`;
82
+
73
83
  const paymentOptions = {
74
84
  action,
75
85
  amount: paymentAmount,
76
86
  currency: currency.toUpperCase(),
77
- description: description || 'regular payment',
87
+ description: description || `Послуга - поповнення рахунку на суму ${paymentAmount} грн`,
78
88
  order_id: paymentData.id,
79
89
  version: '3',
80
90
  language,
81
91
  paytypes,
82
92
  expired_date: expiredDate && new Date(expiredDate) ? new Date(expiredDate).toISOString().split('.')[0].replace('T', ' ') : undefined,
83
- // server_url: `${backUrl}${prefix}/liqpay/${paymentData.id}/success`, // update payment info - api url, does not work on sdk package out of the box
84
- result_url: `${backUrl}${prefix}/liqpay/${paymentData.id}/success`, // redirect user after payment - page url
93
+ // server_url: resultUrl, // update payment info - api url, does not work on sdk package out of the box
94
+ result_url: resultUrl, // redirect user after payment - page url
95
+ rro_info: Array.isArray(deliveryEmails) && deliveryEmails.length ? {
96
+ delivery_emails: deliveryEmails,
97
+ } : undefined,
85
98
  };
86
99
 
87
100
  // html interface for debug via browser only
@@ -110,9 +123,18 @@ export default async function liqpayCreateTransaction({
110
123
  throw new Error(response.headers?.location);
111
124
  }
112
125
 
113
- // debug via unt test
126
+ await dataUpdate({
127
+ table,
128
+ id: paymentData.id,
129
+ data: {
130
+ redirect_url: response.headers.location,
131
+ },
132
+ uid,
133
+ });
134
+
135
+ // debug via unit test
114
136
  if (process.env.NODE_ENV === 'test' && debug) {
115
- return { url: response.headers.location, id: paymentData.id };
137
+ return { id: paymentData.id, url: response.headers.location };
116
138
  }
117
139
 
118
140
  return response.headers.location;
@@ -24,7 +24,9 @@ const ccyObj = {
24
24
  export default async function monopayCreateTransaction({
25
25
  id, orderId, amount, referer, uid, debug, expiredDate, description, action, currency, language,
26
26
  }, pg = pgClients.client) {
27
- if (!host || !token || !backUrl) {
27
+ const rootUrl = referer.slice(0, referer.indexOf('/', 7));
28
+
29
+ if (!host || !token) {
28
30
  throw new Error('invalid monopay integration settings');
29
31
  }
30
32
 
@@ -36,13 +38,10 @@ export default async function monopayCreateTransaction({
36
38
  throw new Error('not enough params: uid required');
37
39
  }
38
40
 
39
- const paymentId = !id ? await pg.query('select next_id()').then(el => el.rows?.[0]?.next_id) : id;
40
-
41
41
  const paymentData = id && pg.pk?.[table]
42
42
  ? await pg.query(`select ${pg.pk?.[table]} as id, * from ${table} where ${pg.pk?.[table]}=$1`, [id]).then(el => el.rows?.[0])
43
43
  : await createPayment({
44
44
  service: 'monopay',
45
- paymentId,
46
45
  orderId,
47
46
  amount,
48
47
  referer,
@@ -64,8 +63,18 @@ export default async function monopayCreateTransaction({
64
63
  throw new Error('invalid payment amount');
65
64
  }
66
65
 
66
+ if (id && paymentData?.expired_date
67
+ && new Date(paymentData.expired_date)
68
+ && new Date() > new Date(paymentData.expired_date)) {
69
+ throw new Error('Transaction date already expired');
70
+ }
71
+
72
+ if (id && paymentData?.redirect_url) {
73
+ return paymentData.redirect_url;
74
+ }
75
+
67
76
  // redirect to api to check payment status and redirect user to page afterwards
68
- const serverUrl = `${backUrl}${prefix}/monopay/${paymentId}/success`;
77
+ const resultUrl = `${rootUrl}${backUrl ? backUrl.replace(/{{service}}/, 'monopay').replace(/{{id}}/, paymentData.id) : `${prefix}/monopay/${paymentData.id}/success`}`;
69
78
 
70
79
  const validity = expiredDate && new Date(expiredDate) ? Math.max(((new Date(expiredDate).setHours(0, 0, 0, 0) - new Date().setHours(0, 0, 0, 0)) / 1000 || 0), 86400) : 86400;
71
80
 
@@ -73,9 +82,9 @@ export default async function monopayCreateTransaction({
73
82
  amount: paymentAmount * 100, // amount=1 === 0.01 uah
74
83
  ccy: ccyObj[currency] || 980, // ISO 4217, 980 = UAH
75
84
  merchantPaymInfo,
76
- redirectUrl: serverUrl,
77
- // redirectUrl: (paymentRedirect ? `${rootPageUrl}${paymentRedirect.replace(/{{id}}/g, paymentId)}` : headers?.referer) || rootPageUrl,
78
- webHookUrl: serverUrl,
85
+ redirectUrl: resultUrl,
86
+ // redirectUrl: (paymentRedirect ? `${rootPageUrl}${paymentRedirect.replace(/{{id}}/g, paymentData.id)}` : headers?.referer) || rootPageUrl,
87
+ webHookUrl: resultUrl,
79
88
  validity, // 1 day by default, then invalid
80
89
  paymentType: 'debit',
81
90
  // displayType: 'iframe', // default = null > url to mono
@@ -97,11 +106,12 @@ export default async function monopayCreateTransaction({
97
106
  // !save invoice ID to check status later
98
107
  await dataUpdate({
99
108
  table,
100
- id: paymentId,
109
+ id: paymentData.id,
101
110
  data: {
102
111
  invoice_id: response?.invoiceId,
103
112
  data: resp.status === 200 ? undefined : { response },
104
113
  status: resp.status === 200 ? 'inprogress' : 'error',
114
+ redirect_url: response?.pageUrl,
105
115
  },
106
116
  uid,
107
117
  });
@@ -116,7 +126,7 @@ export default async function monopayCreateTransaction({
116
126
  }
117
127
 
118
128
  if (process.env.NODE_ENV === 'test' && debug) {
119
- return { id: paymentId, url: response.pageUrl };
129
+ return { id: paymentData.id, url: response.pageUrl };
120
130
  }
121
131
 
122
132
  return response.pageUrl;
@@ -2,6 +2,7 @@ import request from 'request-promise';
2
2
 
3
3
  import config from '../../../config.js';
4
4
  import pgClients from '../pg/pgClients.js';
5
+ import dataUpdate from '../crud/dataUpdate.js';
5
6
 
6
7
  import createPayment from './createPayment.js';
7
8
 
@@ -13,7 +14,9 @@ const { host = 'https://www.portmone.com.ua', payeeId } = config.integrations?.p
13
14
  export default async function portmoneCreateTransaction({
14
15
  id, orderId, amount, referer, uid, debug, expiredDate, description, action, currency = 'uah', language = 'uk', paytypes,
15
16
  }, pg = pgClients.client) {
16
- if (!host || !payeeId || !backUrl) {
17
+ const rootUrl = referer.slice(0, referer.indexOf('/', 7));
18
+
19
+ if (!payeeId) {
17
20
  throw new Error('invalid portmone integration settings');
18
21
  }
19
22
 
@@ -29,13 +32,10 @@ export default async function portmoneCreateTransaction({
29
32
  throw new Error('not enough params: uid required');
30
33
  }
31
34
 
32
- const paymentId = !id ? await pg.query('select next_id()').then(el => el.rows?.[0]?.next_id) : id;
33
-
34
35
  const paymentData = id && pg.pk?.[table]
35
36
  ? await pg.query(`select ${pg.pk?.[table]} as id, * from ${table} where ${pg.pk?.[table]}=$1`, [id]).then(el => el.rows?.[0])
36
37
  : await createPayment({
37
38
  service: 'portmone',
38
- paymentId,
39
39
  orderId,
40
40
  amount,
41
41
  referer,
@@ -49,13 +49,25 @@ export default async function portmoneCreateTransaction({
49
49
  });
50
50
 
51
51
  if (!paymentData?.id) {
52
- throw new Error('payment not found / creation failed');
52
+ throw new Error('Payment not found / creation failed');
53
53
  }
54
54
 
55
55
  const paymentAmount = id ? paymentData.amount : amount;
56
56
 
57
57
  if (!paymentAmount) {
58
- throw new Error('invalid payment amount');
58
+ throw new Error('Invalid payment amount');
59
+ }
60
+
61
+ if (id && paymentData?.expired_date
62
+ && new Date(paymentData.expired_date)
63
+ && new Date() > new Date(paymentData.expired_date)) {
64
+ throw new Error('Transaction date already expired');
65
+ }
66
+
67
+ const resultUrl = `${rootUrl}${backUrl ? backUrl.replace(/{{service}}/, 'portmone').replace(/{{id}}/, paymentData.id) : `${prefix}/portmone/${paymentData.id}/success`}`;
68
+
69
+ if (id && paymentData?.redirect_url) {
70
+ return paymentData.redirect_url;
59
71
  }
60
72
 
61
73
  const formData = {
@@ -64,8 +76,8 @@ export default async function portmoneCreateTransaction({
64
76
  shop_order_number: paymentData.id,
65
77
  bill_amount: paymentAmount,
66
78
  bill_currency: currency.toUpperCase(),
67
- success_url: `${backUrl}${prefix}/portmone/${paymentData.id}/success`,
68
- failure_url: `${backUrl}${prefix}/portmone/${paymentData.id}/error`,
79
+ success_url: resultUrl,
80
+ failure_url: resultUrl.replace(/\/success$/, '/error'),
69
81
  lang: language === 'uk' ? 'ua' : language,
70
82
  };
71
83
 
@@ -90,8 +102,17 @@ export default async function portmoneCreateTransaction({
90
102
  throw new Error(response);
91
103
  }
92
104
 
105
+ await dataUpdate({
106
+ table,
107
+ id: paymentData.id,
108
+ data: {
109
+ redirect_url: response.headers.location,
110
+ },
111
+ uid,
112
+ });
113
+
93
114
  if (process.env.NODE_ENV === 'test' && debug) {
94
- return { id: paymentData?.id, url: response.headers.location };
115
+ return { id: paymentData.id, url: response.headers.location };
95
116
  }
96
117
 
97
118
  return response.headers.location;