Skip to content

Commit 35d0b4e

Browse files
Merge pull request #1 from dev-aces/allow-number-outsum
v.1.1.0 Allow number type for outSum, fixed special symbols in userParams
2 parents da4a3f8 + b544f7c commit 35d0b4e

12 files changed

+97
-31
lines changed

.github/workflows/release_package.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ on:
33
workflow_dispatch:
44
inputs:
55
release-type:
6-
description: 'Release type (one of): patch, minor, major, prerelease'
6+
description: 'Release type (one of): major, minor, patch, prerelease'
77
required: true
88
jobs:
99
release:

.prettierignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
CHANGELOG.md

CHANGELOG.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,33 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## Unreleased
99

10+
### Added
11+
12+
- Allow outSum to be a number or a formatted string.
13+
14+
### Fixed
15+
16+
- Fixed calculating signature value with special symbols in userParams (@ in emails).
17+
- Renamed Email to EMail field in IRobokassaResponse.
18+
1019
## 1.0.1 - 2023-05-13
20+
1121
### Changed
22+
1223
- Translated README.md to Russian language.
1324

1425
## 1.0.0 - 2023-05-12
26+
1527
### Added
28+
1629
- Added `isTest` mode parameter.
1730
- Added `receipt` parameter to conform the fiscal policy.
1831
- Added unit tests.
1932

2033
### Changed
34+
2135
- Rewrote the forked code to use TypeScript.
2236

2337
### Fixed
38+
2439
- Semantic Version calculation errors in the old forked repositories.

README.md

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Robokassa Node.JS
22

3-
Пакет Node.JS для [Robokassa](https://docs.robokassa.ru).
3+
Пакет [Robokassa](https://docs.robokassa.ru) для Node.JS.
44

55
Поддерживает JavaScript и TypeScript.
66

@@ -29,13 +29,16 @@ const robokassa = new Robokassa({
2929
merchantLogin: 'my_merchant_login',
3030
password1: 'my_password_1',
3131
password2: 'my_password_2',
32+
// hashAlgorithm: 'md5' (default)
33+
// isTest: false (default)
34+
// url: 'https://auth.robokassa.ru/Merchant/Index.aspx' (default)
3235
});
3336

3437
const url = robokassa.generatePaymentUrl({
35-
outSum: '10.00',
38+
outSum: '10.00', // или outSum: 10 (type number)
3639
description: 'Тестовый продукт',
37-
// Пользовательские параметры должны начинаться с "shp_" | "Shp_" | "SHP_".
38-
// Они будут переданы на ваш сервер вызовом Робокассы после оплаты.
40+
// Пользовательские параметры должны начинаться с "shp_" или "Shp_" или "SHP_".
41+
// Они будут переданы на ваш сервер вызовом Робокассы после оплаты в том же виде.
3942
userParameters: {
4043
shp_interface: 'link',
4144
shp_user_id: 'user_id',
@@ -68,7 +71,11 @@ const { Robokassa } = require('@dev-aces/robokassa');
6871

6972
## Webhooks
7073

71-
Если в настройках Робокассы исользуется метод `POST` для отправки рузультатов (рекомендуется), то можно использовать Express.JS для обработки запросов:
74+
Result URL для подтверждения и обработки успешной оплаты.
75+
76+
Для перенаправления браузера пользователя после оплаты Робокасса использует параметры Success URL и Failure URL. Не перепутайте.
77+
78+
Если в настройках Робокассы исользуется метод `POST` для отправки Result URL (рекомендуется), то можно использовать следующий код Express.JS для обработки запросов:
7279

7380
TypeScript:
7481

@@ -84,12 +91,12 @@ const robokassa = new Robokassa({
8491

8592
const app = express();
8693

87-
// Указать данный URL для отправки результатов в настройках Робокассы
94+
// Указать данный URL для отправки успешного результаты оплаты в настройках Робокассы (Method of sending data to Result Url)
8895
app.post('/payment/result', function (req: Request, res: Response) {
8996
const robokassaResponse = req.body as IRobokassaResponse;
9097

9198
if (robokassa.checkPayment(robokassaResponse)) {
92-
console.log('PAYMENT SUCCESS!');
99+
console.log('Successful payment!');
93100

94101
const { InvId, /* OutSum, shp_interface, ...etc */ } = robokassaResponse;
95102

@@ -102,18 +109,6 @@ app.post('/payment/result', function (req: Request, res: Response) {
102109
});
103110
```
104111

105-
Опционально можно добавить webhook APIs для оповещения об успешной и неуспешной оплате.
106-
107-
```typescript
108-
app.get('/payment/true', function (req: Request, res: Response) {
109-
res.render('payment_true');
110-
});
111-
112-
app.get('/payment/false', function (req: Request, res: Response) {
113-
res.render('payment_false');
114-
});
115-
```
116-
117112
## Внесение изменений
118113

119114
Сделайте fork репозитория, изменения, убедитесь что успешно пройдены тесты и форматирование:

src/Robokassa.spec.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,54 @@ describe('#Robokassa', () => {
7676
);
7777
});
7878

79+
it('should generate url without IsTest', () => {
80+
const testRobokassa = new Robokassa({
81+
merchantLogin: 'my_merchant_login',
82+
password1: 'my_password1',
83+
password2: 'my_password2',
84+
isTest: false,
85+
});
86+
const result = testRobokassa.generatePaymentUrl({
87+
description: 'Товар 1',
88+
invId: 42,
89+
outSum: '100.00',
90+
});
91+
expect(result).toEqual(
92+
'https://auth.robokassa.ru/Merchant/Index.aspx?MerchantLogin=my_merchant_login&Description=%D0%A2%D0%BE%D0%B2%D0%B0%D1%80%201&InvId=42&OutSum=100.00&SignatureValue=7642fdc174d0aabe022d992afd59f276',
93+
);
94+
});
95+
96+
it('should format outSum to fixed string when number type is passed', () => {
97+
const testRobokassa = new Robokassa({
98+
merchantLogin: 'my_merchant_login',
99+
password1: 'my_password1',
100+
password2: 'my_password2',
101+
});
102+
const result = testRobokassa.generatePaymentUrl({
103+
description: 'Товар 1',
104+
invId: 42,
105+
outSum: 100,
106+
});
107+
expect(result).toEqual(
108+
'https://auth.robokassa.ru/Merchant/Index.aspx?MerchantLogin=my_merchant_login&Description=%D0%A2%D0%BE%D0%B2%D0%B0%D1%80%201&InvId=42&OutSum=100.00&SignatureValue=7642fdc174d0aabe022d992afd59f276',
109+
);
110+
});
111+
112+
it('should pass InvId=0 when invId is not specified', () => {
113+
const testRobokassa = new Robokassa({
114+
merchantLogin: 'my_merchant_login',
115+
password1: 'my_password1',
116+
password2: 'my_password2',
117+
});
118+
const result = testRobokassa.generatePaymentUrl({
119+
description: 'Товар 1',
120+
outSum: '100.00',
121+
});
122+
expect(result).toEqual(
123+
'https://auth.robokassa.ru/Merchant/Index.aspx?MerchantLogin=my_merchant_login&Description=%D0%A2%D0%BE%D0%B2%D0%B0%D1%80%201&OutSum=100.00&InvId=0&SignatureValue=cd9e54da801539e5bb4d6d371f6fef3f',
124+
);
125+
});
126+
79127
it('should generate url with maximum parameters', () => {
80128
const result = robokassa.generatePaymentUrl({
81129
description: 'Услуги по разработке',

src/Robokassa.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ export class Robokassa {
2222
order.invId = 0;
2323
}
2424

25+
if (typeof order.outSum === 'number') {
26+
order.outSum = order.outSum.toFixed(2);
27+
}
28+
2529
const { userParameters, receipt, ...usualOrderParameters } = order;
2630

2731
const orderWithCapitalizedKeys = Object.fromEntries(

src/internal/calculateReceivingSignatureValue.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ describe('#calculateReceivingSignatureValue', () => {
2828
});
2929

3030
expect(result).toEqual(
31-
'200.00:84:my_password2:Shp_email=test%40test.com:Shp_user_id=123',
31+
'200.00:84:my_password2:Shp_email=test@test.com:Shp_user_id=123',
3232
);
3333
});
3434
});

src/internal/calculateReceivingSignatureValue.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,8 @@ export const buildExpectedReceivingSignatureString = ({
1616
);
1717

1818
const signatureUserParams =
19-
userParameters.map(
20-
([key, value]) => `${key}=${encodeURIComponent(value?.toString() ?? '')}`,
21-
) ?? [];
19+
userParameters.map(([key, value]) => `${key}=${value?.toString() ?? ''}`) ??
20+
[];
2221
// Порядок параметров важен, сортируем по алфавиту
2322
signatureUserParams.sort((a, b) => a.localeCompare(b));
2423

src/internal/calculateSendingSignatureValue.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ describe('#calculateSendingSignatureValue', () => {
3434
});
3535

3636
expect(result).toEqual(
37-
'my_merchant_login:200.00:84:my_password1:Shp_email=test%40test.com:Shp_user_id=123',
37+
'my_merchant_login:200.00:84:my_password1:Shp_email=test@test.com:Shp_user_id=123',
3838
);
3939
});
4040

src/internal/calculateSendingSignatureValue.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export const buildSendingSignatureString = ({
1212
}) => {
1313
const signatureUserParams =
1414
Object.entries(order.userParameters ?? {}).map(
15-
([key, value]) => `${key}=${encodeURIComponent(value?.toString() ?? '')}`,
15+
([key, value]) => `${key}=${value?.toString() ?? ''}`,
1616
) ?? [];
1717
// Порядок параметров важен, сортируем по алфавиту
1818
signatureUserParams.sort((a, b) => a.localeCompare(b));

0 commit comments

Comments
 (0)