simplepay-js-sdk 0.3.6 → 0.5.0

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/README.md CHANGED
@@ -4,6 +4,8 @@ A lightweight utility for integrating Hungary's SimplePay payments in Node.js ap
4
4
 
5
5
  ![SimplePay Logo](simplepay_logo.jpg)
6
6
 
7
+ Please read the [SimplePay documentation](https://simplepay.hu/fejlesztoknek) for more information.
8
+
7
9
  ## Installation
8
10
 
9
11
  ```bash
@@ -22,8 +24,8 @@ pnpm add simplepay-js-sdk
22
24
  Set the following environment variables in your `.env` file:
23
25
 
24
26
  - `SIMPLEPAY_LOGGER` If it set to `true`, it will log varibles - useful only for debugging.
25
- - `SIMPLEPAY_MERCHANT_KEY_HUF` Your Simplepay secret merchant key.
26
- - `SIMPLEPAY_MERCHANT_ID_HUF` Your Simplepay merchant id.
27
+ - `SIMPLEPAY_MERCHANT_KEY_HUF` Your Simplepay secret merchant key. Set `SIMPLEPAY_MERCHANT_KEY_EUR` and `SIMPLEPAY_MERCHANT_KEY_USD` for accepting EUR and USD payments.
28
+ - `SIMPLEPAY_MERCHANT_ID_HUF` Your Simplepay merchant id. Set `SIMPLEPAY_MERCHANT_ID_EUR` and `SIMPLEPAY_MERCHANT_ID_USD` for accepting EUR and USD payments.
27
29
  - `SIMPLEPAY_PRODUCTION` If it set to `true`, it will use production environment, otherwise it will use sandbox environment.
28
30
  - `SIMPLEPAY_REDIRECT_URL` The URL of your site, where the customer will be redirected after the payment.
29
31
 
@@ -40,9 +42,9 @@ try {
40
42
  const response = await startPayment({
41
43
  orderRef: 'order-12',
42
44
  total: 1212,
43
- currency: 'HUF', // optional, defaults to HUF
45
+ currency: 'HUF', // optional, HUF | EUR | USD, defaults to HUF
44
46
  customerEmail: 'rrd@webmania.cc',
45
- language: 'HU', // optional, defaults to HU
47
+ language: 'HU', // optional, AR | BG | CS | DE | EN | ES | FR | IT | HR | HU | PL | RO | RU | SK | TR | ZH, defaults to HU
46
48
  method: 'CARD', // optional, CARD | WIRE, defaults to CARD
47
49
  invoice: {
48
50
  name: 'Radharadhya Dasa',
@@ -80,7 +82,7 @@ const response = getPaymentResponse(r, s)
80
82
  - `transactionId`: the transaction id
81
83
  - `event`: the event type: `success` | `fail` | `timeout` | `cancel`
82
84
  - `merchantId`: the merchant id
83
- - `orderId`: the order id
85
+ - `orderRef`: the order id
84
86
 
85
87
  ### IPN Endpoint
86
88
 
package/dist/index.d.ts CHANGED
@@ -1,12 +1,19 @@
1
- import { PaymentData, SimplePayResponse } from './types';
1
+ import { PaymentData, SimplePayResponse, Currency } from './types';
2
2
  declare const generateSignature: (body: string, merchantKey: string) => string;
3
3
  declare const checkSignature: (responseText: string, signature: string, merchantKey: string) => boolean;
4
+ declare const getSimplePayConfig: (currency: Currency) => {
5
+ MERCHANT_KEY: string | undefined;
6
+ MERCHANT_ID: string | undefined;
7
+ API_URL: string;
8
+ SDK_VERSION: string;
9
+ };
4
10
  declare const startPayment: (paymentData: PaymentData) => Promise<SimplePayResponse>;
11
+ declare const getCurrencyFromMerchantId: (merchantId: string) => "HUF" | "EUR" | "USD";
5
12
  declare const getPaymentResponse: (r: string, signature: string) => {
6
13
  responseCode: number;
7
14
  transactionId: string;
8
15
  event: "success" | "fail" | "timeout" | "cancel";
9
16
  merchantId: string;
10
- orderId: string;
17
+ orderRef: string;
11
18
  };
12
- export { startPayment, generateSignature, checkSignature, getPaymentResponse };
19
+ export { startPayment, getPaymentResponse, getSimplePayConfig, generateSignature, checkSignature, getCurrencyFromMerchantId };
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import crypto from 'crypto';
2
+ import { CURRENCIES } from './types';
2
3
  // Existing interfaces remain the same
3
4
  const simplepayLogger = (...args) => {
4
5
  if (process.env.SIMPLEPAY_LOGGER !== 'true') {
@@ -14,12 +15,15 @@ const generateSignature = (body, merchantKey) => {
14
15
  const checkSignature = (responseText, signature, merchantKey) => signature === generateSignature(responseText, merchantKey);
15
16
  // escaping slashes for the request body to prevent strange SimplePay API errors (eg Missing Signature)
16
17
  const prepareRequestBody = (body) => JSON.stringify(body).replace(/\//g, '\\/');
17
- const getSimplePayConfig = () => {
18
+ const getSimplePayConfig = (currency) => {
19
+ if (!CURRENCIES.includes(currency)) {
20
+ throw new Error(`Unsupported currency: ${currency}`);
21
+ }
18
22
  const SIMPLEPAY_API_URL = 'https://secure.simplepay.hu/payment/v2';
19
23
  const SIMPLEPAY_SANDBOX_URL = 'https://sandbox.simplepay.hu/payment/v2/start';
20
- const SDK_VERSION = 'SimplePayV2.1_Rrd_0.3.6';
21
- const MERCHANT_KEY = process.env.SIMPLEPAY_MERCHANT_KEY_HUF;
22
- const MERCHANT_ID = process.env.SIMPLEPAY_MERCHANT_ID_HUF;
24
+ const SDK_VERSION = 'SimplePayV2.1_Rrd_0.5.0';
25
+ const MERCHANT_KEY = process.env[`SIMPLEPAY_MERCHANT_KEY_${currency}`];
26
+ const MERCHANT_ID = process.env[`SIMPLEPAY_MERCHANT_ID_${currency}`];
23
27
  const API_URL = process.env.SIMPLEPAY_PRODUCTION === 'true' ? SIMPLEPAY_API_URL : SIMPLEPAY_SANDBOX_URL;
24
28
  return {
25
29
  MERCHANT_KEY,
@@ -29,7 +33,8 @@ const getSimplePayConfig = () => {
29
33
  };
30
34
  };
31
35
  const startPayment = async (paymentData) => {
32
- const { MERCHANT_KEY, MERCHANT_ID, API_URL, SDK_VERSION } = getSimplePayConfig();
36
+ const currency = paymentData.currency || 'HUF';
37
+ const { MERCHANT_KEY, MERCHANT_ID, API_URL, SDK_VERSION } = getSimplePayConfig(currency);
33
38
  simplepayLogger({ MERCHANT_KEY, MERCHANT_ID, API_URL });
34
39
  if (!MERCHANT_KEY || !MERCHANT_ID) {
35
40
  throw new Error('Missing SimplePay configuration');
@@ -38,7 +43,7 @@ const startPayment = async (paymentData) => {
38
43
  salt: crypto.randomBytes(16).toString('hex'),
39
44
  merchant: MERCHANT_ID,
40
45
  orderRef: paymentData.orderRef,
41
- currency: paymentData.currency || 'HUF',
46
+ currency,
42
47
  customerEmail: paymentData.customerEmail,
43
48
  language: paymentData.language || 'HU',
44
49
  sdkVersion: SDK_VERSION,
@@ -87,10 +92,21 @@ const startPayment = async (paymentData) => {
87
92
  throw error;
88
93
  }
89
94
  };
95
+ const getCurrencyFromMerchantId = (merchantId) => {
96
+ const currency = Object.entries(process.env)
97
+ .find(([key, value]) => key.startsWith('SIMPLEPAY_MERCHANT_ID_') && value === merchantId)?.[0]?.replace('SIMPLEPAY_MERCHANT_ID_', '');
98
+ if (!currency) {
99
+ throw new Error(`Merchant id not found in the environment: ${merchantId}`);
100
+ }
101
+ return currency;
102
+ };
90
103
  const getPaymentResponse = (r, signature) => {
91
- const { MERCHANT_KEY } = getSimplePayConfig();
92
- // Note: Replaced atob with Buffer for ESM
104
+ signature = decodeURIComponent(signature);
105
+ signature = Buffer.from(signature, 'base64').toString('utf-8');
93
106
  const rDecoded = Buffer.from(r, 'base64').toString('utf-8');
107
+ const rDecodedJSON = JSON.parse(rDecoded);
108
+ const currency = getCurrencyFromMerchantId(rDecodedJSON.m);
109
+ const { MERCHANT_KEY } = getSimplePayConfig(currency);
94
110
  if (!checkSignature(rDecoded, signature, MERCHANT_KEY || '')) {
95
111
  simplepayLogger({ rDecoded, signature });
96
112
  throw new Error('Invalid response signature');
@@ -101,9 +117,9 @@ const getPaymentResponse = (r, signature) => {
101
117
  transactionId: responseJson.t,
102
118
  event: responseJson.e,
103
119
  merchantId: responseJson.m,
104
- orderId: responseJson.o,
120
+ orderRef: responseJson.o,
105
121
  };
106
122
  return response;
107
123
  };
108
- export { startPayment, generateSignature, checkSignature, getPaymentResponse };
124
+ export { startPayment, getPaymentResponse, getSimplePayConfig, generateSignature, checkSignature, getCurrencyFromMerchantId };
109
125
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -1,10 +1,14 @@
1
1
  type PaymentMethod = 'CARD' | 'WIRE';
2
+ declare const CURRENCIES: readonly ["HUF", "EUR", "USD"];
3
+ type Currency = typeof CURRENCIES[number];
4
+ declare const LANGUAGES: readonly ["AR", "BG", "CS", "DE", "EN", "ES", "FR", "IT", "HR", "HU", "PL", "RO", "RU", "SK", "TR", "ZH"];
5
+ type Language = typeof LANGUAGES[number];
2
6
  interface PaymentData {
3
7
  orderRef: string;
4
8
  total: number | string;
5
9
  customerEmail: string;
6
- currency?: string;
7
- language?: string;
10
+ currency?: Currency;
11
+ language?: Language;
8
12
  method?: PaymentMethod;
9
13
  invoice?: {
10
14
  name: string;
@@ -30,7 +34,7 @@ interface SimplePayResponse {
30
34
  salt: string;
31
35
  merchant: string;
32
36
  orderRef: string;
33
- currency: string;
37
+ currency: Currency;
34
38
  transactionId: string;
35
39
  timeout: string;
36
40
  total: string;
@@ -44,4 +48,4 @@ interface SimplepayResult {
44
48
  m: string;
45
49
  o: string;
46
50
  }
47
- export { PaymentData, SimplePayRequestBody, SimplePayResponse, SimplepayResult };
51
+ export { PaymentData, SimplePayRequestBody, SimplePayResponse, SimplepayResult, CURRENCIES, Currency, PaymentMethod, LANGUAGES, Language };
package/dist/types.js CHANGED
@@ -1 +1,21 @@
1
+ const CURRENCIES = ['HUF', 'EUR', 'USD'];
2
+ const LANGUAGES = [
3
+ 'AR', // Arabic
4
+ 'BG', // Bulgarian
5
+ 'CS', // Czech
6
+ 'DE', // German
7
+ 'EN', // English
8
+ 'ES', // Spanish
9
+ 'FR', // French
10
+ 'IT', // Italian
11
+ 'HR', // Croatian
12
+ 'HU', // Hungarian
13
+ 'PL', // Polish
14
+ 'RO', // Romanian
15
+ 'RU', // Russian
16
+ 'SK', // Slovak
17
+ 'TR', // Turkish
18
+ 'ZH', // Chinese
19
+ ];
20
+ export { CURRENCIES, LANGUAGES };
1
21
  //# sourceMappingURL=types.js.map
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,CAAU,CAAA;AAGjD,MAAM,SAAS,GAAG;IACd,IAAI,EAAE,SAAS;IACf,IAAI,EAAE,YAAY;IAClB,IAAI,EAAE,QAAQ;IACd,IAAI,EAAE,SAAS;IACf,IAAI,EAAE,UAAU;IAChB,IAAI,EAAE,UAAU;IAChB,IAAI,EAAE,SAAS;IACf,IAAI,EAAE,UAAU;IAChB,IAAI,EAAE,WAAW;IACjB,IAAI,EAAE,YAAY;IAClB,IAAI,EAAE,SAAS;IACf,IAAI,EAAE,WAAW;IACjB,IAAI,EAAE,UAAU;IAChB,IAAI,EAAE,SAAS;IACf,IAAI,EAAE,UAAU;IAChB,IAAI,EAAE,UAAU;CACV,CAAA;AAoDV,OAAO,EAAyE,UAAU,EAA2B,SAAS,EAAY,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "simplepay-js-sdk",
3
- "version": "0.3.6",
3
+ "version": "0.5.0",
4
4
  "description": "A Node.js utility for SimplePay payment integration",
5
5
  "repository": {
6
6
  "type": "git",
@@ -22,7 +22,8 @@
22
22
  "prepare": "npm run build",
23
23
  "test": "vitest --run",
24
24
  "test:watch": "vitest",
25
- "release": "bash ./release.sh"
25
+ "release": "bash ./release.sh",
26
+ "generate-signature": "node tools/generate-signature.js"
26
27
  },
27
28
  "keywords": [
28
29
  "simplepay",
package/src/index.spec.ts CHANGED
@@ -1,10 +1,12 @@
1
- import { describe, it, expect, vi } from 'vitest'
2
- import { checkSignature, generateSignature, getPaymentResponse, startPayment } from './index'
3
- import { PaymentData } from './types'
1
+ import { describe, it, expect, vi, beforeEach } from 'vitest'
2
+ import { checkSignature, generateSignature, getPaymentResponse, getSimplePayConfig, startPayment, getCurrencyFromMerchantId } from './index'
3
+ import { Currency } from './types'
4
4
 
5
5
  const setEnv = () => {
6
- process.env.SIMPLEPAY_MERCHANT_KEY_HUF = 'testKey'
7
6
  process.env.SIMPLEPAY_MERCHANT_ID_HUF = 'testId'
7
+ process.env.SIMPLEPAY_MERCHANT_KEY_HUF = 'testKey'
8
+ process.env.SIMPLEPAY_MERCHANT_ID_EUR = 'merchantEuroId'
9
+ process.env.SIMPLEPAY_MERCHANT_KEY_EUR = 'secretEuroKey'
8
10
  }
9
11
 
10
12
  const paymentData = {
@@ -12,140 +14,165 @@ const paymentData = {
12
14
  customerEmail: 'test@example.com',
13
15
  total: 1212
14
16
  }
15
-
16
- describe('generateSignature', () => {
17
- it('should generate correct signature for sample payload from documentation', () => {
18
- const merchantKey = 'FxDa5w314kLlNseq2sKuVwaqZshZT5d6'
19
- const body = {
20
- salt: 'c1ca1d0e9fc2323b3dda7cf145e36f5e',
21
- merchant: 'PUBLICTESTHUF',
22
- orderRef: '101010516348232058105',
23
- currency: 'HUF',
24
- customerEmail: 'sdk_test@otpmobil.com',
25
- language: 'HU',
26
- sdkVersion: 'SimplePayV2.1_Payment_PHP_SDK_2.0.7_190701:dd236896400d7463677a82a47f53e36e',
27
- methods: ['CARD'],
28
- total: '25',
29
- timeout: '2021-10-30T12:30:11+00:00',
30
- url: 'https://sdk.simplepay.hu/back.php',
31
- }
32
-
33
- let bodyString = JSON.stringify(body)
34
- // after stringify we should insert backslashes for the url
35
- bodyString = bodyString.replace(/\//g, '\\/')
36
-
37
- const result = generateSignature(bodyString, merchantKey)
38
-
39
- const expectedSignature = 'gcDJ8J7TyT1rC/Ygj/8CihXaLwniMWRav09QSEMQUnv5TbYaEDvQAuBE1mW3plvZ'
40
- expect(result).toBe(expectedSignature)
17
+ describe('SimplePay SDK Tests', () => {
18
+ beforeEach(() => {
19
+ // Clear all environment variables before each test
20
+ delete process.env.SIMPLEPAY_MERCHANT_KEY_HUF
21
+ delete process.env.SIMPLEPAY_MERCHANT_ID_HUF
22
+ })
23
+ describe('generateSignature', () => {
24
+ it('should generate correct signature for sample payload from documentation', () => {
25
+ const merchantKey = 'FxDa5w314kLlNseq2sKuVwaqZshZT5d6'
26
+ const body = {
27
+ salt: 'c1ca1d0e9fc2323b3dda7cf145e36f5e',
28
+ merchant: 'PUBLICTESTHUF',
29
+ orderRef: '101010516348232058105',
30
+ currency: 'HUF',
31
+ customerEmail: 'sdk_test@otpmobil.com',
32
+ language: 'HU',
33
+ sdkVersion: 'SimplePayV2.1_Payment_PHP_SDK_2.0.7_190701:dd236896400d7463677a82a47f53e36e',
34
+ methods: ['CARD'],
35
+ total: '25',
36
+ timeout: '2021-10-30T12:30:11+00:00',
37
+ url: 'https://sdk.simplepay.hu/back.php',
38
+ }
39
+
40
+ let bodyString = JSON.stringify(body)
41
+ // after stringify we should insert backslashes for the url
42
+ bodyString = bodyString.replace(/\//g, '\\/')
43
+
44
+ const result = generateSignature(bodyString, merchantKey)
45
+
46
+ const expectedSignature = 'gcDJ8J7TyT1rC/Ygj/8CihXaLwniMWRav09QSEMQUnv5TbYaEDvQAuBE1mW3plvZ'
47
+ expect(result).toBe(expectedSignature)
48
+ })
41
49
  })
42
- })
43
50
 
51
+ describe('checkSignature', () => {
52
+ it('should generate correct signature for the response', () => {
53
+ const merchantKey = 'P085602'
54
+ const response = {
55
+ transactionId: '504226393',
56
+ orderRef: 'ORDER124',
57
+ merchant: merchantKey,
58
+ timeout: '2024-11-29T13:29:17+01:00',
59
+ total: '1000',
60
+ paymentUrl: 'https://sb-checkout.simplepay.hu/trx/cJZs3UUc48FlGu7Mfa1M0tcTWO53oA5RxS0OUMPqA17Fe3HGBr',
61
+ currency: 'HUF',
62
+ salt: 'R0ZBm2gdCXuTmxpOkqB4s0aAhZxZwSWG'
63
+ }
64
+
65
+ const expectedSignature = 'W98O/EdHobsWJTw2U1xUuUWXtCaJnTnzq5Na8ddCKE4gm2IW7vro33tGAW55YPf6'
66
+ const result = checkSignature(JSON.stringify(response).replace(/\//g, '\\/'), expectedSignature, merchantKey)
67
+ expect(result).toBeTruthy()
68
+ })
44
69
 
45
- describe('checkSignature', () => {
46
- it('should generate correct signature for the response', () => {
47
- const merchantKey = 'P085602'
48
- const response = {
49
- transactionId: '504226393',
50
- orderRef: 'ORDER124',
51
- merchant: merchantKey,
52
- timeout: '2024-11-29T13:29:17+01:00',
53
- total: '1000',
54
- paymentUrl: 'https://sb-checkout.simplepay.hu/trx/cJZs3UUc48FlGu7Mfa1M0tcTWO53oA5RxS0OUMPqA17Fe3HGBr',
55
- currency: 'HUF',
56
- salt: 'R0ZBm2gdCXuTmxpOkqB4s0aAhZxZwSWG'
57
- }
58
-
59
- const expectedSignature = 'W98O/EdHobsWJTw2U1xUuUWXtCaJnTnzq5Na8ddCKE4gm2IW7vro33tGAW55YPf6'
60
- const result = checkSignature(JSON.stringify(response).replace(/\//g, '\\/'), expectedSignature, merchantKey)
61
- expect(result).toBeTruthy()
70
+ it('should return false for invalid signature', () => {
71
+ const merchantKey = 'testKey'
72
+ const response = { test: 'data' }
73
+ const invalidSignature = 'invalid-signature'
74
+
75
+ const result = checkSignature(
76
+ JSON.stringify(response),
77
+ invalidSignature,
78
+ merchantKey
79
+ )
80
+ expect(result).toBeFalsy()
81
+ })
62
82
  })
63
83
 
64
- it('should return false for invalid signature', () => {
65
- const merchantKey = 'testKey'
66
- const response = { test: 'data' }
67
- const invalidSignature = 'invalid-signature'
68
-
69
- const result = checkSignature(
70
- JSON.stringify(response),
71
- invalidSignature,
72
- merchantKey
73
- )
74
- expect(result).toBeFalsy()
84
+ describe('getSimplePayConfig', () => {
85
+ it('should return correct config for HUF currency', () => {
86
+ setEnv()
87
+ const config = getSimplePayConfig('HUF')
88
+ expect(config.MERCHANT_ID).toBe('testId')
89
+ expect(config.MERCHANT_KEY).toBe('testKey')
90
+ })
91
+
92
+ it('should throw error for unsupported currency', () => {
93
+ expect(() => getSimplePayConfig('GBP' as Currency)).toThrow('Unsupported currency: GBP')
94
+ })
75
95
  })
76
- })
77
96
 
78
- describe('getPaymentResponse', () => {
79
- it('should correctly decode and parse valid response', () => {
80
- // Create a base64 encoded response similar to what SimplePay returns
81
- const mockResponse = {
82
- r: 'SUCCESS',
83
- t: '123456789',
84
- e: 'PAYMENT',
85
- m: 'MERCHANT123',
86
- o: 'ORDER123'
87
- }
88
- const encodedResponse = Buffer.from(JSON.stringify(mockResponse)).toString('base64')
89
- const validSignature = generateSignature(JSON.stringify(mockResponse), process.env.SIMPLEPAY_MERCHANT_KEY_HUF || '')
90
-
91
- const result = getPaymentResponse(encodedResponse, validSignature)
92
-
93
- expect(result).toEqual({
94
- responseCode: 'SUCCESS',
95
- transactionId: '123456789',
96
- event: 'PAYMENT',
97
- merchantId: 'MERCHANT123',
98
- orderId: 'ORDER123'
97
+ const mockResponse = {
98
+ r: 'SUCCESS',
99
+ t: '123456789',
100
+ e: 'PAYMENT',
101
+ m: 'testId',
102
+ o: 'ORDER123'
103
+ }
104
+ const encodedResponse = Buffer.from(JSON.stringify(mockResponse)).toString('base64')
105
+
106
+ describe('getCurrencyFromMerchantId', () => {
107
+ it('should return correct currency for merchantId', () => {
108
+ setEnv()
109
+ const currency = getCurrencyFromMerchantId('testId')
110
+ expect(currency).toBe('HUF')
99
111
  })
100
112
  })
101
113
 
102
- it('should throw error for invalid signature', () => {
103
- const mockResponse = { test: 'data' }
104
- const encodedResponse = Buffer.from(JSON.stringify(mockResponse)).toString('base64')
114
+ describe('getPaymentResponse', () => {
115
+ it('should correctly decode and parse valid response', () => {
116
+ setEnv()
117
+ const r = 'eyJyIjowLCJ0Ijo1MDQyMzM4ODEsImUiOiJTVUNDRVNTIiwibSI6Im1lcmNoYW50RXVyb0lkIiwibyI6ImMtMS1ldXIifQ=='
118
+ // { r: 0, t: 504233881, e: 'SUCCESS', m: 'merchantEuroId', o: 'c-1-eur' }
119
+ const s = 'WWx4cnBEYThqRi94VkIvck5zRUpvRnhPb0hRK0NpemlCbVdTTUloWVdIU0NKbXZMb2M2a3pBaVpQbVlEVTh6Ng=='
120
+ const result = getPaymentResponse(r, s)
121
+ expect(result).toEqual({
122
+ responseCode: 0,
123
+ transactionId: 504233881,
124
+ event: 'SUCCESS',
125
+ merchantId: 'merchantEuroId',
126
+ orderRef: 'c-1-eur'
127
+ })
128
+ })
105
129
 
106
- expect(() =>
107
- getPaymentResponse(encodedResponse, 'invalid-signature')
108
- ).toThrow('Invalid response signature')
130
+ it('should throw error for invalid signature', () => {
131
+ setEnv()
132
+ expect(() =>
133
+ getPaymentResponse(encodedResponse, 'invalid-signature')
134
+ ).toThrow('Invalid response signature')
135
+ })
109
136
  })
110
- })
111
137
 
112
- describe('startPayment', () => {
113
- it('should throw error when merchant configuration is missing', async () => {
114
- await expect(startPayment(paymentData)).rejects.toThrow('Missing SimplePay configuration')
115
- })
138
+ describe('startPayment', () => {
139
+ it('should throw error when merchant configuration is missing', async () => {
140
+ await expect(startPayment(paymentData)).rejects.toThrow('Missing SimplePay configuration')
141
+ })
116
142
 
117
- it('should handle API errors correctly', async () => {
118
- setEnv()
119
-
120
- global.fetch = vi.fn().mockResolvedValue({
121
- ok: true,
122
- headers: {
123
- get: vi.fn().mockReturnValue('mockSignature')
124
- },
125
- text: vi.fn().mockResolvedValue(JSON.stringify({
126
- transactionId: '123456',
127
- total: '1212',
128
- merchant: 'testId'
129
- }))
130
- }) as unknown as typeof fetch
131
- await expect(startPayment(paymentData)).rejects.toThrow('Invalid response signature')
132
- })
143
+ it('should handle API errors correctly', async () => {
144
+ setEnv()
145
+
146
+ global.fetch = vi.fn().mockResolvedValue({
147
+ ok: true,
148
+ headers: {
149
+ get: vi.fn().mockReturnValue('mockSignature')
150
+ },
151
+ text: vi.fn().mockResolvedValue(JSON.stringify({
152
+ transactionId: '123456',
153
+ total: '1212',
154
+ merchant: 'testId'
155
+ }))
156
+ }) as unknown as typeof fetch
157
+ await expect(startPayment(paymentData)).rejects.toThrow('Invalid response signature')
158
+ })
133
159
 
134
- it('should successfully start CARD, HUF, HU payment when API returns valid response', async () => {
135
- setEnv()
136
- global.fetch = vi.fn().mockResolvedValue({
137
- ok: true,
138
- headers: {
139
- get: vi.fn().mockReturnValue('bxSwUc0qn0oABSRcq9uawF6zncFBhRk/AbO4HznYR9Pt5SjocyxAD+9Q4bE44h0J')
140
- },
141
- text: vi.fn().mockResolvedValue(JSON.stringify({
142
- transactionId: '123456',
143
- total: '1212',
144
- merchant: 'testId'
145
- }))
146
- }) as unknown as typeof fetch
147
-
148
- await expect(startPayment(paymentData)).resolves.toBeDefined()
160
+ it('should successfully start CARD, HUF, HU payment when API returns valid response', async () => {
161
+ setEnv()
162
+ global.fetch = vi.fn().mockResolvedValue({
163
+ ok: true,
164
+ headers: {
165
+ get: vi.fn().mockReturnValue('bxSwUc0qn0oABSRcq9uawF6zncFBhRk/AbO4HznYR9Pt5SjocyxAD+9Q4bE44h0J')
166
+ },
167
+ text: vi.fn().mockResolvedValue(JSON.stringify({
168
+ transactionId: '123456',
169
+ total: '1212',
170
+ merchant: 'testId'
171
+ }))
172
+ }) as unknown as typeof fetch
173
+
174
+ await expect(startPayment(paymentData)).resolves.toBeDefined()
175
+ })
149
176
  })
150
- })
151
177
 
178
+ })
package/src/index.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import crypto from 'crypto'
2
- import { PaymentData, SimplePayRequestBody, SimplePayResponse, SimplepayResult } from './types'
2
+ import { PaymentData, SimplePayRequestBody, SimplePayResponse, SimplepayResult, Currency, CURRENCIES } from './types'
3
3
 
4
4
  // Existing interfaces remain the same
5
5
 
@@ -24,12 +24,16 @@ const prepareRequestBody = (body: SimplePayRequestBody) =>
24
24
  JSON.stringify(body).replace(/\//g, '\\/')
25
25
 
26
26
 
27
- const getSimplePayConfig = () => {
27
+ const getSimplePayConfig = (currency: Currency) => {
28
+ if (!CURRENCIES.includes(currency)) {
29
+ throw new Error(`Unsupported currency: ${currency}`)
30
+ }
31
+
28
32
  const SIMPLEPAY_API_URL = 'https://secure.simplepay.hu/payment/v2'
29
33
  const SIMPLEPAY_SANDBOX_URL = 'https://sandbox.simplepay.hu/payment/v2/start'
30
- const SDK_VERSION = 'SimplePayV2.1_Rrd_0.3.6'
31
- const MERCHANT_KEY = process.env.SIMPLEPAY_MERCHANT_KEY_HUF
32
- const MERCHANT_ID = process.env.SIMPLEPAY_MERCHANT_ID_HUF
34
+ const SDK_VERSION = 'SimplePayV2.1_Rrd_0.5.0'
35
+ const MERCHANT_KEY = process.env[`SIMPLEPAY_MERCHANT_KEY_${currency}`]
36
+ const MERCHANT_ID = process.env[`SIMPLEPAY_MERCHANT_ID_${currency}`]
33
37
  const API_URL = process.env.SIMPLEPAY_PRODUCTION === 'true' ? SIMPLEPAY_API_URL : SIMPLEPAY_SANDBOX_URL
34
38
 
35
39
  return {
@@ -41,7 +45,8 @@ const getSimplePayConfig = () => {
41
45
  }
42
46
 
43
47
  const startPayment = async (paymentData: PaymentData) => {
44
- const { MERCHANT_KEY, MERCHANT_ID, API_URL, SDK_VERSION } = getSimplePayConfig()
48
+ const currency = paymentData.currency || 'HUF'
49
+ const { MERCHANT_KEY, MERCHANT_ID, API_URL, SDK_VERSION } = getSimplePayConfig(currency)
45
50
  simplepayLogger({ MERCHANT_KEY, MERCHANT_ID, API_URL })
46
51
 
47
52
  if (!MERCHANT_KEY || !MERCHANT_ID) {
@@ -52,7 +57,7 @@ const startPayment = async (paymentData: PaymentData) => {
52
57
  salt: crypto.randomBytes(16).toString('hex'),
53
58
  merchant: MERCHANT_ID,
54
59
  orderRef: paymentData.orderRef,
55
- currency: paymentData.currency || 'HUF',
60
+ currency,
56
61
  customerEmail: paymentData.customerEmail,
57
62
  language: paymentData.language || 'HU',
58
63
  sdkVersion: SDK_VERSION,
@@ -111,10 +116,24 @@ const startPayment = async (paymentData: PaymentData) => {
111
116
  }
112
117
  }
113
118
 
119
+ const getCurrencyFromMerchantId = (merchantId: string) => {
120
+ const currency = Object.entries(process.env)
121
+ .find(([key, value]) =>
122
+ key.startsWith('SIMPLEPAY_MERCHANT_ID_') && value === merchantId
123
+ )?.[0]?.replace('SIMPLEPAY_MERCHANT_ID_', '') as Currency
124
+ if (!currency) {
125
+ throw new Error(`Merchant id not found in the environment: ${merchantId}`)
126
+ }
127
+ return currency
128
+ }
129
+
114
130
  const getPaymentResponse = (r: string, signature: string) => {
115
- const { MERCHANT_KEY } = getSimplePayConfig()
116
- // Note: Replaced atob with Buffer for ESM
131
+ signature = decodeURIComponent(signature)
132
+ signature = Buffer.from(signature, 'base64').toString('utf-8')
117
133
  const rDecoded = Buffer.from(r, 'base64').toString('utf-8')
134
+ const rDecodedJSON = JSON.parse(rDecoded)
135
+ const currency = getCurrencyFromMerchantId(rDecodedJSON.m)
136
+ const { MERCHANT_KEY } = getSimplePayConfig(currency as Currency)
118
137
 
119
138
  if (!checkSignature(rDecoded, signature, MERCHANT_KEY || '')) {
120
139
  simplepayLogger({ rDecoded, signature })
@@ -127,10 +146,17 @@ const getPaymentResponse = (r: string, signature: string) => {
127
146
  transactionId: responseJson.t,
128
147
  event: responseJson.e,
129
148
  merchantId: responseJson.m,
130
- orderId: responseJson.o,
149
+ orderRef: responseJson.o,
131
150
  }
132
151
 
133
152
  return response
134
153
  }
135
154
 
136
- export { startPayment, generateSignature, checkSignature, getPaymentResponse }
155
+ export {
156
+ startPayment,
157
+ getPaymentResponse,
158
+ getSimplePayConfig,
159
+ generateSignature,
160
+ checkSignature,
161
+ getCurrencyFromMerchantId
162
+ }
package/src/types.ts CHANGED
@@ -1,11 +1,34 @@
1
1
  type PaymentMethod = 'CARD' | 'WIRE'
2
2
 
3
+ const CURRENCIES = ['HUF', 'EUR', 'USD'] as const
4
+ type Currency = typeof CURRENCIES[number]
5
+
6
+ const LANGUAGES = [
7
+ 'AR', // Arabic
8
+ 'BG', // Bulgarian
9
+ 'CS', // Czech
10
+ 'DE', // German
11
+ 'EN', // English
12
+ 'ES', // Spanish
13
+ 'FR', // French
14
+ 'IT', // Italian
15
+ 'HR', // Croatian
16
+ 'HU', // Hungarian
17
+ 'PL', // Polish
18
+ 'RO', // Romanian
19
+ 'RU', // Russian
20
+ 'SK', // Slovak
21
+ 'TR', // Turkish
22
+ 'ZH', // Chinese
23
+ ] as const
24
+ type Language = typeof LANGUAGES[number]
25
+
3
26
  interface PaymentData {
4
27
  orderRef: string
5
28
  total: number | string
6
29
  customerEmail: string
7
- currency?: string
8
- language?: string
30
+ currency?: Currency
31
+ language?: Language
9
32
  method?: PaymentMethod
10
33
  invoice?: {
11
34
  name: string
@@ -33,7 +56,7 @@ interface SimplePayResponse {
33
56
  salt: string
34
57
  merchant: string
35
58
  orderRef: string
36
- currency: string
59
+ currency: Currency
37
60
  transactionId: string
38
61
  timeout: string
39
62
  total: string
@@ -49,4 +72,4 @@ interface SimplepayResult {
49
72
  o: string // order id
50
73
  }
51
74
 
52
- export { PaymentData, SimplePayRequestBody, SimplePayResponse, SimplepayResult }
75
+ export { PaymentData, SimplePayRequestBody, SimplePayResponse, SimplepayResult, CURRENCIES, Currency, PaymentMethod, LANGUAGES, Language }