@opengis/pay 2.0.1 → 2.0.3

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.1",
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.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
+ }
@@ -17,8 +17,20 @@ alter table pay.transactions add column if not exists created_by text NOT NULL d
17
17
  alter table pay.transactions add column if not exists updated_by text;
18
18
  alter table pay.transactions add column if not exists updated_at timestamp without time zone;
19
19
  alter table pay.transactions add column if not exists invoice_id text;
20
+ alter table pay.transactions add column if not exists payment_id text;
21
+ alter table pay.transactions add column if not exists order_id text;
22
+ alter table pay.transactions add column if not exists description text;
23
+ alter table pay.transactions add column if not exists action text;
24
+ alter table pay.transactions add column if not exists currency text;
25
+ alter table pay.transactions add column if not exists expired_date date;
26
+ alter table pay.transactions add column if not exists language text;
27
+ alter table pay.transactions add column if not exists paytypes text;
28
+ alter table pay.transactions add column if not exists paytype text;
29
+ alter table pay.transactions add column if not exists customer text;
30
+ alter table pay.transactions add column if not exists receipt text;
31
+
32
+ COMMENT ON TABLE pay.transactions IS 'Транзакції';
20
33
 
21
- COMMENT ON TABLE pay.transactions IS 'Платежі';
22
34
  COMMENT ON COLUMN pay.transactions.transaction_id IS 'ID';
23
35
  COMMENT ON COLUMN pay.transactions.user_id IS 'ID користувача';
24
36
  COMMENT ON COLUMN pay.transactions.status IS 'Статус транзації';
@@ -28,7 +40,18 @@ COMMENT ON COLUMN pay.transactions.service IS 'Сервіс оплати (portmo
28
40
  COMMENT ON COLUMN pay.transactions.amount IS 'Сума поповнення рахунку';
29
41
  COMMENT ON COLUMN pay.transactions.balance IS 'Поточний баланс';
30
42
  COMMENT ON COLUMN pay.transactions.referer_url IS 'Посилання';
31
- COMMENT ON COLUMN pay.transactions.invoice_id IS 'ID транзакції з сервісу оплати';
43
+ COMMENT ON COLUMN pay.transactions.invoice_id IS 'ID рахунку сервісу оплати';
44
+ COMMENT ON COLUMN pay.transactions.invoice_id IS 'ID платежу сервісу оплати';
45
+ COMMENT ON COLUMN pay.transactions.order_id IS 'Внутрішній ID замовлення';
46
+ COMMENT ON COLUMN pay.transactions.description IS 'Опис';
47
+ COMMENT ON COLUMN pay.transactions.action IS 'Дія';
48
+ COMMENT ON COLUMN pay.transactions.currency IS 'Валюта';
49
+ COMMENT ON COLUMN pay.transactions.expired_date IS 'Термін дії';
50
+ COMMENT ON COLUMN pay.transactions.language IS 'Мова';
51
+ COMMENT ON COLUMN pay.transactions.paytypes IS 'Дозволені типи оплати';
52
+ COMMENT ON COLUMN pay.transactions.paytype IS 'Використаний тип оплати';
53
+ COMMENT ON COLUMN pay.transactions.customer IS 'Унікальний ідентифікатор користувача на сайті мерчанта';
54
+ COMMENT ON COLUMN pay.transactions.receipt IS 'Посилання на квітанцію сервісу оплати';
32
55
 
33
56
  CREATE INDEX if not exists pay_transactions_transactions_status_btree_idx ON pay.transactions USING btree (status COLLATE pg_catalog."default");
34
57
 
@@ -5,23 +5,30 @@ import dataInsert from '../crud/dataInsert.js';
5
5
  const { paymentRedirect, table = 'pay.transactions' } = config.integrations?.pay || {};
6
6
 
7
7
  export default async function createPayment({
8
- paymentId, price, referer, uid, service,
8
+ paymentId, orderId, amount, referer, uid, service, expiredDate, description, action = 'pay', currency = 'uah', language = 'uk', paytypes,
9
9
  }, pg = pgClients.client) {
10
10
  if (!paymentId) { throw new Error('not enough params: paymentId'); }
11
11
  if (!uid) { throw new Error('not enough params: uid'); }
12
12
  if (!service) { throw new Error('not enough params: service'); }
13
- if (!price) { throw new Error('not enough params: price'); }
13
+ if (!amount) { throw new Error('not enough params: amount'); }
14
14
 
15
15
  const result = await dataInsert({
16
16
  id: paymentId,
17
17
  pg,
18
18
  table,
19
19
  data: {
20
- referer_url: paymentRedirect ? paymentRedirect.replace(/{{id}}/g, paymentId) : referer,
21
- amount: price,
20
+ referer_url: referer,
21
+ amount,
22
22
  user_id: uid,
23
+ order_id: orderId,
23
24
  service,
24
25
  status: 'inprogress',
26
+ action,
27
+ expired_date: expiredDate,
28
+ description,
29
+ language,
30
+ currency,
31
+ paytypes,
25
32
  },
26
33
  uid,
27
34
  }).then(el => el.rows?.[0]);
@@ -13,14 +13,31 @@ const controller = {
13
13
  };
14
14
 
15
15
  export default async function createTransaction({
16
- id, price, rootUrl, referer, uid, debug, service,
16
+ orderId, amount, referer, uid, debug, service, expiredDate, description, action, language, paytypes, currency,
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 (price && !uid) throw new Error('not enough params: uid');
20
+ if (amount && !uid) throw new Error('not enough params: uid');
21
+
22
+ if (currency && !['uah', 'usd', 'eur'].includes(currency)) {
23
+ throw new Error('invalid params: currency');
24
+ }
25
+
26
+ if (language && !['uk', 'en'].includes(language)) {
27
+ throw new Error('invalid params: language');
28
+ }
21
29
 
22
30
  const result = await controller[service]({
23
- id, price, rootUrl, referer, uid, debug,
31
+ orderId,
32
+ amount,
33
+ referer,
34
+ uid,
35
+ debug,
36
+ action,
37
+ expiredDate,
38
+ description,
39
+ language,
40
+ paytypes,
24
41
  }, pg);
25
42
  return result;
26
43
  }
@@ -9,7 +9,9 @@ const { host = 'https://www.liqpay.ua', publicKey, privateKey } = config.integra
9
9
 
10
10
  const liqpay = new LiqPay(publicKey, privateKey);
11
11
 
12
- export default async function liqpayCheckStatus(id, origin, pg = pgClients.client) {
12
+ const pg = pgClients.client;
13
+
14
+ export default async function liqpayCheckStatus(id, { origin } = {}) {
13
15
  if (!id) throw new Error('not enough params: id');
14
16
  if (!publicKey || !privateKey) throw new Error('empty integration params: liqpay');
15
17
 
@@ -38,6 +40,26 @@ export default async function liqpayCheckStatus(id, origin, pg = pgClients.clien
38
40
  'Content-Type': 'application/x-www-form-urlencoded',
39
41
  },
40
42
  });
43
+
41
44
  const result = response?.startsWith?.('{') ? JSON.parse(response) : response;
45
+
46
+ // ! receipt can only be sent to email, no link provided by liqpay
47
+ /* const data1 = Buffer.from(JSON.stringify({
48
+ action: 'ticket',
49
+ version: '3',
50
+ order_id: id,
51
+ email: 'email@gmail.com',
52
+ language: result?.language || 'uk',
53
+ })).toString('base64');
54
+ const signature1 = liqpay.str_to_sign(privateKey + data1 + privateKey);
55
+
56
+ const response1 = await request(`${host}/api/request`, {
57
+ method: 'POST',
58
+ form: { data: data1, signature: signature1 },
59
+ headers: {
60
+ 'Content-Type': 'application/x-www-form-urlencoded',
61
+ },
62
+ }); */
63
+
42
64
  return result;
43
65
  }
@@ -7,7 +7,7 @@ import pgClients from '../pg/pgClients.js';
7
7
  import createPayment from './createPayment.js';
8
8
 
9
9
  const { prefix = '/api' } = config;
10
- const { table = 'pay.transactions' } = config.integrations?.pay || {};
10
+ const { table = 'pay.transactions', backUrl: bUrl } = config.integrations?.pay || {};
11
11
 
12
12
  const {
13
13
  host = 'https://www.liqpay.ua',
@@ -17,18 +17,24 @@ const {
17
17
  const liqpay = new LiqPay(publicKey, privateKey);
18
18
 
19
19
  export default async function liqpayCreateTransaction({
20
- id, price, rootUrl, referer, uid, debug,
20
+ id, orderId, amount, referer, uid, debug, expiredDate, description, paytypes, action = 'pay', currency = 'uah', language = 'uk',
21
21
  }, pg = pgClients.client) {
22
+ const backUrl = bUrl || referer.slice(0, referer.indexOf('/', 7));
23
+
22
24
  if (!publicKey || !privateKey) {
23
25
  throw new Error('invalid liqpay integration settings');
24
26
  }
25
27
 
26
- if (!id && !price) {
27
- throw new Error('not enough params: id or price required');
28
+ if (!['pay', 'hold', 'subscribe', 'paydonate'].includes(action)) {
29
+ throw new Error('invalid params: action');
30
+ }
31
+
32
+ if (paytypes && paytypes.split(',').find(el => !['apay', 'gpay', 'card', 'privat24', 'moment_part', 'paypart', 'cash', 'invoice', 'qr'].includes(el))) {
33
+ throw new Error('invalid params: paytypes');
28
34
  }
29
35
 
30
- if (!rootUrl) {
31
- throw new Error('not enough params: rootUrl required');
36
+ if (!id && !amount) {
37
+ throw new Error('not enough params: id or amount required');
32
38
  }
33
39
 
34
40
  if (!uid) {
@@ -40,32 +46,42 @@ export default async function liqpayCreateTransaction({
40
46
  const paymentData = id && pg.pk?.[table]
41
47
  ? await pg.query(`select ${pg.pk?.[table]} as id, * from ${table} where ${pg.pk?.[table]}=$1`, [id]).then(el => el.rows?.[0])
42
48
  : await createPayment({
49
+ service: 'liqpay',
43
50
  paymentId,
44
- price,
51
+ orderId,
52
+ amount,
45
53
  referer,
46
54
  uid,
47
- service: 'liqpay',
55
+ expiredDate,
56
+ description,
57
+ action,
58
+ currency,
59
+ language,
60
+ paytypes,
48
61
  });
49
62
 
50
63
  if (!paymentData?.id) {
51
64
  throw new Error('payment not found / creation failed');
52
65
  }
53
66
 
54
- const paymentAmount = id ? paymentData.amount : price;
67
+ const paymentAmount = id ? paymentData.amount : amount;
55
68
 
56
69
  if (!paymentAmount) {
57
70
  throw new Error('invalid payment amount');
58
71
  }
59
72
 
60
73
  const paymentOptions = {
61
- action: 'pay',
74
+ action,
62
75
  amount: paymentAmount,
63
- currency: 'UAH',
64
- description: 'regular payment',
76
+ currency: currency.toUpperCase(),
77
+ description: description || 'regular payment',
65
78
  order_id: paymentData.id,
66
79
  version: '3',
67
- // server_url: `${rootUrl}${prefix}/liqpay/${paymentData.id}/success`, // update payment info - api url, does not work on sdk package out of the box
68
- result_url: `${rootUrl}${prefix}/liqpay/${paymentData.id}/success`, // redirect user after payment - page url
80
+ language,
81
+ paytypes,
82
+ 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
69
85
  };
70
86
 
71
87
  // html interface for debug via browser only
@@ -10,7 +10,9 @@ const {
10
10
 
11
11
  const timeoutMs = 5000;
12
12
 
13
- export default async function monopayCheckStatus(id, origin, pg = pgClients.client) {
13
+ const pg = pgClients.client;
14
+
15
+ export default async function monopayCheckStatus(id, { origin } = {}) {
14
16
  if (!id) { throw new Error('not enough params: id'); }
15
17
 
16
18
  const {
@@ -44,5 +46,11 @@ export default async function monopayCheckStatus(id, origin, pg = pgClients.clie
44
46
  ? await resp.json()
45
47
  : { error: await resp.text() };
46
48
 
47
- return { ...body, amount: body.amount / 100, status: body.status };
49
+ return {
50
+ ...body,
51
+ paytype: body.paymentInfo?.maskedPan ? 'card' : null,
52
+ payment_id: body.paymentInfo?.tranId,
53
+ amount: body.amount / 100,
54
+ status: body.status,
55
+ };
48
56
  }
@@ -5,7 +5,7 @@ import dataUpdate from '../crud/dataUpdate.js';
5
5
  import createPayment from './createPayment.js';
6
6
 
7
7
  const { prefix = '/api' } = config;
8
- const { table = 'pay.transactions' } = config.integrations?.pay || {};
8
+ const { table = 'pay.transactions', backUrl } = config.integrations?.pay || {};
9
9
 
10
10
  const {
11
11
  host = 'https://api.monobank.ua',
@@ -15,23 +15,21 @@ const {
15
15
 
16
16
  const timeoutMs = 5000;
17
17
 
18
+ const ccyObj = {
19
+ uah: 980,
20
+ usd: 840,
21
+ eur: 978,
22
+ };
23
+
18
24
  export default async function monopayCreateTransaction({
19
- id, price, rootUrl, referer, uid, debug,
25
+ id, orderId, amount, referer, uid, debug, expiredDate, description, action, currency, language,
20
26
  }, pg = pgClients.client) {
21
- if (!host) {
22
- throw new Error('empty integration host');
23
- }
24
-
25
- if (!token) {
26
- throw new Error('empty integration token');
27
- }
28
-
29
- if (!id && !price) {
30
- throw new Error('not enough params: id or price required');
27
+ if (!host || !token || !backUrl) {
28
+ throw new Error('invalid monopay integration settings');
31
29
  }
32
30
 
33
- if (!rootUrl) {
34
- throw new Error('not enough params: rootUrl required');
31
+ if (!id && !amount) {
32
+ throw new Error('not enough params: id or amount required');
35
33
  }
36
34
 
37
35
  if (!uid) {
@@ -43,33 +41,42 @@ export default async function monopayCreateTransaction({
43
41
  const paymentData = id && pg.pk?.[table]
44
42
  ? await pg.query(`select ${pg.pk?.[table]} as id, * from ${table} where ${pg.pk?.[table]}=$1`, [id]).then(el => el.rows?.[0])
45
43
  : await createPayment({
44
+ service: 'monopay',
46
45
  paymentId,
47
- price,
46
+ orderId,
47
+ amount,
48
48
  referer,
49
49
  uid,
50
- service: 'monopay',
50
+ expiredDate,
51
+ description,
52
+ action,
53
+ currency,
54
+ language,
51
55
  });
52
56
 
53
57
  if (!paymentData?.id) {
54
58
  throw new Error('payment not found / creation failed');
55
59
  }
56
- const paymentAmount = id ? paymentData.amount : price;
60
+
61
+ const paymentAmount = id ? paymentData.amount : amount;
57
62
 
58
63
  if (!paymentAmount) {
59
64
  throw new Error('invalid payment amount');
60
65
  }
61
66
 
62
67
  // redirect to api to check payment status and redirect user to page afterwards
63
- const serverUrl = `${rootUrl}${prefix}/monopay/${paymentId}/success`;
68
+ const serverUrl = `${backUrl}${prefix}/monopay/${paymentId}/success`;
69
+
70
+ 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;
64
71
 
65
72
  const paymentOptions = {
66
- amount: paymentAmount * 100, // price=1 === 0.01 uah
67
- ccy: 980, // ISO 4217, 980 = UAH
73
+ amount: paymentAmount * 100, // amount=1 === 0.01 uah
74
+ ccy: ccyObj[currency] || 980, // ISO 4217, 980 = UAH
68
75
  merchantPaymInfo,
69
76
  redirectUrl: serverUrl,
70
77
  // redirectUrl: (paymentRedirect ? `${rootPageUrl}${paymentRedirect.replace(/{{id}}/g, paymentId)}` : headers?.referer) || rootPageUrl,
71
78
  webHookUrl: serverUrl,
72
- validity: 86400, // 1 day by default, then invalid
79
+ validity, // 1 day by default, then invalid
73
80
  paymentType: 'debit',
74
81
  // displayType: 'iframe', // default = null > url to mono
75
82
  };
@@ -10,6 +10,7 @@ export default async function paymentInfo(id, pg = pgClients.client) {
10
10
  amount,
11
11
  status,
12
12
  service,
13
+ order_id: orderId,
13
14
  referer_url: referer,
14
15
  user_id: userId,
15
16
  } = id && pg.pk?.[table] ? await pg.query(`select ${pg.pk?.[table]} as id, * from ${table} where ${pg.pk?.[table]}=$1`, [id])
@@ -17,7 +18,8 @@ export default async function paymentInfo(id, pg = pgClients.client) {
17
18
 
18
19
  return {
19
20
  id, // id for existing transtaction
20
- price: amount, // price for new transtaction as is, else - preCreated
21
+ orderId, // order ID, optional
22
+ amount, // amount for new transtaction as is, else - preCreated
21
23
  status, // payment status
22
24
  service, // service name
23
25
  referer, // redirect user after finish of transaction
@@ -12,7 +12,9 @@ const {
12
12
  payeeId,
13
13
  } = config.integrations?.portmone || {};
14
14
 
15
- export default async function portmoneCheckStatus(id, origin, pg = pgClients.client) {
15
+ const pg = pgClients.client;
16
+
17
+ export default async function portmoneCheckStatus(id, { body, origin } = {}) {
16
18
  if (!payeeId) throw new Error('empty integration params: payeeId');
17
19
  if (!id) throw new Error('not enough params: id');
18
20
 
@@ -31,12 +33,25 @@ export default async function portmoneCheckStatus(id, origin, pg = pgClients.cli
31
33
 
32
34
  const isValidOrigin = origin && origin === host;
33
35
 
34
- if (!(login && password) && !isValidOrigin) {
36
+ /* if (!(login && password) && !isValidOrigin) {
35
37
  throw new Error('empty integration params: portmone 2');
38
+ } */
39
+
40
+ if (!isValidOrigin) {
41
+ throw new Error('access denied');
36
42
  }
37
43
 
44
+ const mockResult = {
45
+ ...body || {},
46
+ paytype: !body?.RESULT || body?.CARD_MASK ? 'card' : null,
47
+ billAmount: body?.BILL_AMOUNT || data.amount,
48
+ receipt_url: body?.RECEIPT_URL,
49
+ payment_id: body?.SHOPBILLID,
50
+ status: !body?.RESULT || body?.RESULT === '0' ? 'success' : 'error',
51
+ };
52
+
38
53
  // ? likely cause timeout, skip be origin check or check credentials i.e.: login, password
39
- const response = isValidOrigin ? { billAmount: data.amount, status: 'success' } : await request({
54
+ const response = isValidOrigin ? mockResult : await request({
40
55
  url: `${host}/gateway/`,
41
56
  method: 'POST',
42
57
  formData,
@@ -7,26 +7,22 @@ import createPayment from './createPayment.js';
7
7
 
8
8
  const { prefix = '/api' } = config;
9
9
 
10
- const { table = 'pay.transactions' } = config.integrations?.pay || {};
10
+ const { table = 'pay.transactions', backUrl } = config.integrations?.pay || {};
11
11
  const { host = 'https://www.portmone.com.ua', payeeId } = config.integrations?.portmone || {};
12
12
 
13
13
  export default async function portmoneCreateTransaction({
14
- id, price, rootUrl, referer, uid, debug,
14
+ id, orderId, amount, referer, uid, debug, expiredDate, description, action, currency = 'uah', language = 'uk', paytypes,
15
15
  }, pg = pgClients.client) {
16
- if (!host) {
17
- throw new Error('empty integration host');
16
+ if (!host || !payeeId || !backUrl) {
17
+ throw new Error('invalid portmone integration settings');
18
18
  }
19
19
 
20
- if (!payeeId) {
21
- throw new Error('empty integration payeeId');
20
+ if (paytypes && paytypes.split(',').find(el => !['card', 'portmone', 'token', 'clicktopay', 'privat', 'gpay', 'createtokenonly', 'gpayonly', 'applepay', 'applepayonly', 'link'].includes(el))) {
21
+ throw new Error('invalid params: paytypes');
22
22
  }
23
23
 
24
- if (!id && !price) {
25
- throw new Error('not enough params: id or price required');
26
- }
27
-
28
- if (!rootUrl) {
29
- throw new Error('not enough params: rootUrl required');
24
+ if (!id && !amount) {
25
+ throw new Error('not enough params: id or amount required');
30
26
  }
31
27
 
32
28
  if (!uid) {
@@ -38,18 +34,25 @@ export default async function portmoneCreateTransaction({
38
34
  const paymentData = id && pg.pk?.[table]
39
35
  ? await pg.query(`select ${pg.pk?.[table]} as id, * from ${table} where ${pg.pk?.[table]}=$1`, [id]).then(el => el.rows?.[0])
40
36
  : await createPayment({
37
+ service: 'portmone',
41
38
  paymentId,
42
- price,
39
+ orderId,
40
+ amount,
43
41
  referer,
44
42
  uid,
45
- service: 'portmone',
43
+ expiredDate,
44
+ description,
45
+ action,
46
+ currency,
47
+ language,
48
+ paytypes,
46
49
  });
47
50
 
48
51
  if (!paymentData?.id) {
49
52
  throw new Error('payment not found / creation failed');
50
53
  }
51
54
 
52
- const paymentAmount = id ? paymentData.amount : price;
55
+ const paymentAmount = id ? paymentData.amount : amount;
53
56
 
54
57
  if (!paymentAmount) {
55
58
  throw new Error('invalid payment amount');
@@ -57,12 +60,13 @@ export default async function portmoneCreateTransaction({
57
60
 
58
61
  const formData = {
59
62
  payee_id: payeeId,
60
- description: `Послуга - поповнення рахунку на суму ${paymentAmount} грн`,
63
+ description: description || `Послуга - поповнення рахунку на суму ${paymentAmount} грн`,
61
64
  shop_order_number: paymentData.id,
62
65
  bill_amount: paymentAmount,
63
- success_url: `${rootUrl}${prefix}/portmone/${paymentData.id}/success`,
64
- failure_url: `${rootUrl}${prefix}/portmone/${paymentData.id}/error`,
65
- lang: 'ua',
66
+ bill_currency: currency.toUpperCase(),
67
+ success_url: `${backUrl}${prefix}/portmone/${paymentData.id}/success`,
68
+ failure_url: `${backUrl}${prefix}/portmone/${paymentData.id}/error`,
69
+ lang: language === 'uk' ? 'ua' : language,
66
70
  };
67
71
 
68
72
  // portmone always returns error without simple: false options
@@ -15,13 +15,15 @@ const controller = {
15
15
  const newDate = () => {
16
16
  const date = new Date();
17
17
  const tzOffset = date.getTimezoneOffset();
18
- const currentTimeWithTimezome = date - tzOffset * 60 * 1000;
19
- return new Date(currentTimeWithTimezome).toISOString();
18
+ const currentTimeWithTimezone = date - tzOffset * 60 * 1000;
19
+ return new Date(currentTimeWithTimezone).toISOString();
20
20
  };
21
21
 
22
22
  const { table = 'pay.transactions' } = config.integrations?.pay || {};
23
23
 
24
- export default async function processTransaction(id, origin, pg = pgClients.client) {
24
+ const pg = pgClients.client;
25
+
26
+ export default async function processTransaction(id, { body, origin } = {}) {
25
27
  if (!id) throw new Error('not enough params: id');
26
28
 
27
29
  const {
@@ -39,7 +41,7 @@ export default async function processTransaction(id, origin, pg = pgClients.clie
39
41
  throw new Error('Transaction was already processed');
40
42
  }
41
43
 
42
- const result = await controller[service](id, origin);
44
+ const result = await controller[service](id, { origin, body });
43
45
 
44
46
  const { status = 'error', err_description: err } = result || {};
45
47
 
@@ -57,6 +59,10 @@ export default async function processTransaction(id, origin, pg = pgClients.clie
57
59
  table,
58
60
  data: {
59
61
  data: result,
62
+ payment_id: result?.payment_id, // payment service ID
63
+ customer: result?.customer, // payee
64
+ paytype: result?.paytype, // card, gpay etc
65
+ receipt_url: result?.receipt_url,
60
66
  status,
61
67
  balance: +result.amount + +balance,
62
68
  success_date: newDate(),
@@ -39,8 +39,8 @@ export default async function paymentInfo({
39
39
  }
40
40
 
41
41
  const { rows = [] } = await pg.query(
42
- `select ${pg.pk?.[table]} as id, * from ${table} where ${pg.pk?.[table]} = $1 and user_id = $2`,
43
- [params.id, user.uid],
42
+ `select ${pg.pk?.[table]} as id, * from ${table} where ${pg.pk?.[table]} = $1 and ${user?.user_type?.includes?.('admin') ? '1=1' : 'user_id = $2'}`,
43
+ [params.id, user?.user_type?.includes?.('admin') ? null : user.uid].filter(Boolean),
44
44
  );
45
45
 
46
46
  if (!rows.length) {
@@ -6,32 +6,27 @@ import createTransaction from '../../../plugins/payment/liqpay.createTransaction
6
6
 
7
7
  export default async function liqpayRedirect(req, reply) {
8
8
  const {
9
- hostname, headers, pg = pgClients.client, query = {}, user = {}, protocol,
9
+ headers, pg = pgClients.client, query = {}, user = {},
10
10
  } = req;
11
11
 
12
12
  if (!user?.uid) {
13
13
  return reply.status(401).send('unauthorized');
14
14
  }
15
15
 
16
- const domain = hostname?.split?.(':')?.shift?.();
17
- const rootUrl = `${protocol || 'https'}://${domain}`;
18
-
19
16
  const paymentData = query.id ? await paymentInfo(query.id) : {
20
- price: query.price, // price for new transtaction as is, else - preCreated
17
+ orderId: query.order_id,
18
+ amount: query.amount, // amount for new transtaction as is, else - preCreated
21
19
  service: 'portmone',
22
20
  referer: headers?.referer, // redirect user after finish of transaction
23
21
  uid: user.uid, // user id
24
22
  };
25
23
 
26
- // redirect back from payment service to API endpoint, provide protocol + domain
27
- Object.assign(paymentData, { rootUrl });
28
-
29
24
  if (query.id && paymentData.status === 'success') {
30
25
  return reply.status(400).send('already processed');
31
26
  }
32
27
 
33
- if (!paymentData?.price) {
34
- return reply.status(400).send('price is required');
28
+ if (!paymentData?.amount) {
29
+ return reply.status(400).send('amount is required');
35
30
  }
36
31
 
37
32
  // create if not exists, then request to payment service
@@ -7,6 +7,7 @@
7
7
  import pgClients from '../../../plugins/pg/pgClients.js';
8
8
 
9
9
  import processTransaction from '../../../plugins/payment/processTransaction.js';
10
+ import dataUpdate from '../../../plugins/crud/dataUpdate.js';
10
11
 
11
12
  // import sendNotification from '../../../utils/sendNotification.js';
12
13
 
@@ -4,36 +4,31 @@ import pgClients from '../../../plugins/pg/pgClients.js';
4
4
  import paymentInfo from '../../../plugins/payment/paymentInfo.js';
5
5
  import createTransaction from '../../../plugins/payment/monopay.createTransaction.js';
6
6
 
7
- // http://billing.local.ua/api/monopay-redirect?price=50
7
+ // http://billing.local.ua/api/monopay-redirect?amount=50
8
8
 
9
9
  export default async function monopayRedirect(req, reply) {
10
10
  const {
11
- hostname, headers, pg = pgClients.client, query = {}, user = {}, protocol,
11
+ headers, pg = pgClients.client, query = {}, user = {},
12
12
  } = req;
13
13
 
14
14
  if (!user?.uid) {
15
15
  return reply.status(401).send('unauthrized');
16
16
  }
17
17
 
18
- const domain = hostname?.split?.(':')?.shift?.();
19
- const rootUrl = `${protocol || 'https'}://${domain}`;
20
-
21
18
  const paymentData = query.id ? await paymentInfo(query.id) : {
22
- price: query.price, // price for new transtaction as is, else - preCreated
19
+ orderId: query.order_id, // order ID, optional
20
+ amount: query.amount, // amount for new transtaction as is, else - preCreated
23
21
  service: 'portmone',
24
22
  referer: headers?.referer, // redirect user after finish of transaction
25
23
  uid: user.uid, // user id
26
24
  };
27
25
 
28
- // redirect back from payment service to API endpoint, provide protocol + domain
29
- Object.assign(paymentData, { rootUrl });
30
-
31
26
  if (query.id && paymentData.status === 'success') {
32
27
  return reply.status(400).send('already processed');
33
28
  }
34
29
 
35
- if (!paymentData?.price) {
36
- return reply.status(400).send('price is required');
30
+ if (!paymentData?.amount) {
31
+ return reply.status(400).send('amount is required');
37
32
  }
38
33
 
39
34
  // create if not exists, then request to payment service
@@ -5,7 +5,7 @@ const schema = {
5
5
  querystring: {
6
6
  type: 'object',
7
7
  properties: {
8
- price: {
8
+ amount: {
9
9
  type: 'number',
10
10
  exclusiveMinimum: 0,
11
11
  },
@@ -11,7 +11,7 @@ import createTransaction from '../../../plugins/payment/portmone.createTransacti
11
11
  * @alias PortmonePaymentRedirect
12
12
  * @summary redirect на сервіс оплати карткою
13
13
  * @type api
14
- * @param {String} price - Сума поповнення рахунку
14
+ * @param {String} amount - Сума поповнення рахунку
15
15
  * @returns {Number} status - номер помилки. Повертається, якщо була допущенна помилка в отриманих параметрах, або з бази. Це може бути 400 або 500
16
16
  * @returns {String} error - опис помилки
17
17
  * @returns {String} redirect - шлях до переадресації
@@ -22,31 +22,26 @@ import createTransaction from '../../../plugins/payment/portmone.createTransacti
22
22
 
23
23
  export default async function portmoneRedirect(req, reply) {
24
24
  const {
25
- hostname, headers, pg = pgClients.client, user = {}, query = {}, protocol,
25
+ headers, pg = pgClients.client, user = {}, query = {},
26
26
  } = req;
27
27
  if (!user?.uid) {
28
28
  return reply.status(401).send('unauthrized');
29
29
  }
30
30
 
31
- const domain = hostname?.split?.(':')?.shift?.();
32
- const rootUrl = `${protocol || 'https'}://${domain}`;
33
-
34
31
  const paymentData = query.id ? await paymentInfo(query.id) : {
35
- price: query.price, // price for new transtaction as is, else - preCreated
32
+ orderId: query.order_id, // order ID, optional
33
+ amount: query.amount, // amount for new transtaction as is, else - preCreated
36
34
  service: 'portmone',
37
35
  referer: headers?.referer, // redirect user after finish of transaction
38
36
  uid: user.uid, // user id
39
37
  };
40
38
 
41
- // redirect back from payment service to API endpoint, provide protocol + domain
42
- Object.assign(paymentData, { rootUrl });
43
-
44
39
  if (query.id && paymentData.status === 'success') {
45
40
  return reply.status(400).send('already processed');
46
41
  }
47
42
 
48
- if (!paymentData?.price) {
49
- return reply.status(400).send('price is required');
43
+ if (!paymentData?.amount) {
44
+ return reply.status(400).send('amount is required');
50
45
  }
51
46
 
52
47
  // create if not exists, then request to payment service
@@ -48,7 +48,7 @@ export default async function portmoneStatus(req, reply) {
48
48
 
49
49
  const paymentId = body?.shopOrderNumber || params?.id;
50
50
 
51
- const trx = await processTransaction(paymentId, origin);
51
+ const trx = await processTransaction(paymentId, { body, origin });
52
52
 
53
53
  if (!trx) {
54
54
  return reply.status(404).send('Transaction not found');