node-behind-api-client 2.0.48
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/.gitlab-ci.yml +20 -0
- package/README.md +65 -0
- package/docs/behind-api-client/easyjob/JobDescriptions/README.md +654 -0
- package/docs/behind-api-client/easyjob/README.md +647 -0
- package/docs/behind-api-client/easyjob/applicants/README.md +494 -0
- package/docs/behind-api-client/easyjob/applications/README.md +754 -0
- package/docs/behind-api-client/easyjob/candidateProfiles/README.md +940 -0
- package/docs/behind-api-client/easyjob/jd-candidate-questions/README.md +372 -0
- package/docs/behind-api-client/payments/payture/README.21.md +901 -0
- package/docs/behind-api-client/payments/payture/README.cards.md +1497 -0
- package/docs/behind-api-client/payments/payture/README.md +1497 -0
- package/docs/behind-api-client/payments/payture/README.rukitchen.md +396 -0
- package/docs/behind-api-client/payments/payture/README.subscriptions.md +1266 -0
- package/docs/behind-api-client/payments/stripe/README.flow.md +254 -0
- package/docs/behind-api-client/rag/storage/README.md +519 -0
- package/example.js +35 -0
- package/index.cjs +14 -0
- package/index.js +15 -0
- package/lib/behind-api-auth-client/BehindApiAuthClient.js +91 -0
- package/lib/behind-api-auth-client/authorisation/AuthorisationApp.js +9 -0
- package/lib/behind-api-auth-client/authorisation/AuthorisationV10.js +9 -0
- package/lib/behind-api-auth-client/authorisation/AuthorisationV10Code.js +30 -0
- package/lib/behind-api-auth-client/example.js +47 -0
- package/lib/behind-api-auth-client/package.json +9 -0
- package/lib/behind-api-client/BehindApiClient.js +137 -0
- package/lib/behind-api-client/chat/ChatApp.js +11 -0
- package/lib/behind-api-client/chat/ChatV10.js +13 -0
- package/lib/behind-api-client/chat/ChatV10Chat.js +87 -0
- package/lib/behind-api-client/chat/ChatV10Chats.js +14 -0
- package/lib/behind-api-client/chat/ChatV10Message.js +57 -0
- package/lib/behind-api-client/chat/ChatV20.js +11 -0
- package/lib/behind-api-client/chat/ChatV20Chat.js +14 -0
- package/lib/behind-api-client/chat/ChatV20Message.js +27 -0
- package/lib/behind-api-client/easyjob/EasyjobApp.js +9 -0
- package/lib/behind-api-client/easyjob/EasyjobV10.js +31 -0
- package/lib/behind-api-client/easyjob/EasyjobV10Answers.js +16 -0
- package/lib/behind-api-client/easyjob/EasyjobV10Applicants.js +29 -0
- package/lib/behind-api-client/easyjob/EasyjobV10Applications.js +39 -0
- package/lib/behind-api-client/easyjob/EasyjobV10CandidateProfileArtifacts.js +31 -0
- package/lib/behind-api-client/easyjob/EasyjobV10CandidateProfiles.js +99 -0
- package/lib/behind-api-client/easyjob/EasyjobV10Companies.js +36 -0
- package/lib/behind-api-client/easyjob/EasyjobV10Cv.js +15 -0
- package/lib/behind-api-client/easyjob/EasyjobV10Departments.js +37 -0
- package/lib/behind-api-client/easyjob/EasyjobV10JobDescriptionArtifacts.js +29 -0
- package/lib/behind-api-client/easyjob/EasyjobV10JobDescriptionCandidateQuestions.js +63 -0
- package/lib/behind-api-client/easyjob/EasyjobV10JobDescriptions.js +93 -0
- package/lib/behind-api-client/easyjob/EasyjobV10Reports.js +35 -0
- package/lib/behind-api-client/example.js +47 -0
- package/lib/behind-api-client/global/GlobalApp.js +9 -0
- package/lib/behind-api-client/global/GlobalV10.js +11 -0
- package/lib/behind-api-client/global/GlobalV10Sockets.js +16 -0
- package/lib/behind-api-client/global/GlobalV10Storage.js +29 -0
- package/lib/behind-api-client/gpt/GptApp.js +15 -0
- package/lib/behind-api-client/gpt/GptV10.js +15 -0
- package/lib/behind-api-client/gpt/GptV10Prompt.js +17 -0
- package/lib/behind-api-client/gpt/GptV10Request.js +16 -0
- package/lib/behind-api-client/gpt/GptV10Storedprompts.js +14 -0
- package/lib/behind-api-client/gpt/GptV10Whisper.js +23 -0
- package/lib/behind-api-client/gpt/GptV20.js +9 -0
- package/lib/behind-api-client/gpt/GptV20Prompt.js +15 -0
- package/lib/behind-api-client/gpt/GptV30.js +13 -0
- package/lib/behind-api-client/gpt/GptV30Chat.js +19 -0
- package/lib/behind-api-client/gpt/GptV30Prompt.js +41 -0
- package/lib/behind-api-client/gpt/GptV30Prompts.js +32 -0
- package/lib/behind-api-client/gpt/GptV40.js +11 -0
- package/lib/behind-api-client/gpt/GptV40Prompt.js +24 -0
- package/lib/behind-api-client/gpt/GptV40Prompts.js +30 -0
- package/lib/behind-api-client/mailer/MailerApp.js +11 -0
- package/lib/behind-api-client/mailer/MailerV10.js +15 -0
- package/lib/behind-api-client/mailer/MailerV10Bulk.js +21 -0
- package/lib/behind-api-client/mailer/MailerV10Message.js +83 -0
- package/lib/behind-api-client/mailer/MailerV10Settings.js +44 -0
- package/lib/behind-api-client/mailer/MailerV10Template.js +23 -0
- package/lib/behind-api-client/mailer/MailerV20.js +9 -0
- package/lib/behind-api-client/mailer/MailerV20Message.js +21 -0
- package/lib/behind-api-client/mastogram/MastogramApp.js +9 -0
- package/lib/behind-api-client/mastogram/MastogramV10.js +13 -0
- package/lib/behind-api-client/mastogram/MastogramV10Bluesky.js +42 -0
- package/lib/behind-api-client/mastogram/MastogramV10Mastodon.js +45 -0
- package/lib/behind-api-client/mastogram/MastogramV10Telegram.js +39 -0
- package/lib/behind-api-client/monitor/MonitorApp.js +9 -0
- package/lib/behind-api-client/monitor/MonitorV10.js +13 -0
- package/lib/behind-api-client/monitor/MonitorV10Finances.js +39 -0
- package/lib/behind-api-client/monitor/MonitorV10Record.js +15 -0
- package/lib/behind-api-client/monitor/MonitorV10Records.js +22 -0
- package/lib/behind-api-client/oauth/OauthApp.js +9 -0
- package/lib/behind-api-client/oauth/OauthV10.js +9 -0
- package/lib/behind-api-client/oauth/OauthV10Authorisation.js +15 -0
- package/lib/behind-api-client/package.json +9 -0
- package/lib/behind-api-client/payments/PaymentsApp.js +13 -0
- package/lib/behind-api-client/payments/PaymentsV10.js +15 -0
- package/lib/behind-api-client/payments/PaymentsV10Gift.js +32 -0
- package/lib/behind-api-client/payments/PaymentsV10Payture.js +30 -0
- package/lib/behind-api-client/payments/PaymentsV10Product.js +15 -0
- package/lib/behind-api-client/payments/PaymentsV10Telegram.js +44 -0
- package/lib/behind-api-client/payments/PaymentsV20.js +9 -0
- package/lib/behind-api-client/payments/PaymentsV20Payture.js +32 -0
- package/lib/behind-api-client/payments/PaymentsV21.js +15 -0
- package/lib/behind-api-client/payments/PaymentsV21Cards.js +14 -0
- package/lib/behind-api-client/payments/PaymentsV21Payture.js +29 -0
- package/lib/behind-api-client/payments/PaymentsV21Stripe.js +28 -0
- package/lib/behind-api-client/payments/PaymentsV21Subscriptions.js +21 -0
- package/lib/behind-api-client/questionnaire/QuestionnaireApp.js +9 -0
- package/lib/behind-api-client/questionnaire/QuestionnaireV10.js +9 -0
- package/lib/behind-api-client/questionnaire/QuestionnaireV10Form.js +22 -0
- package/lib/behind-api-client/raet/RaetApp.js +11 -0
- package/lib/behind-api-client/raet/RaetV10.js +21 -0
- package/lib/behind-api-client/raet/RaetV10Cv.js +87 -0
- package/lib/behind-api-client/raet/RaetV10Individual.js +43 -0
- package/lib/behind-api-client/raet/RaetV10Individuals.js +38 -0
- package/lib/behind-api-client/raet/RaetV10Jd.js +47 -0
- package/lib/behind-api-client/raet/RaetV10Project.js +61 -0
- package/lib/behind-api-client/raet/RaetV10Projects.js +14 -0
- package/lib/behind-api-client/raet/RaetV10Report.js +39 -0
- package/lib/behind-api-client/raet/RaetV20.js +11 -0
- package/lib/behind-api-client/raet/RaetV20Cv.js +31 -0
- package/lib/behind-api-client/raet/RaetV20Individuals.js +25 -0
- package/lib/behind-api-client/rag/RagApp.js +9 -0
- package/lib/behind-api-client/rag/RagV10.js +9 -0
- package/lib/behind-api-client/rag/RagV10Storage.js +27 -0
- package/lib/behind-api-client/ruKitchen/RuKitchenApp.js +9 -0
- package/lib/behind-api-client/ruKitchen/RuKitchenV10.js +11 -0
- package/lib/behind-api-client/ruKitchen/RuKitchenV10Importer.js +29 -0
- package/lib/behind-api-client/ruKitchen/RuKitchenV10SeoArticle.js +14 -0
- package/lib/behind-api-client/sales/SalesApp.js +11 -0
- package/lib/behind-api-client/sales/SalesV10.js +23 -0
- package/lib/behind-api-client/sales/SalesV10Catalogue.js +58 -0
- package/lib/behind-api-client/sales/SalesV10Categories.js +15 -0
- package/lib/behind-api-client/sales/SalesV10Companies.js +55 -0
- package/lib/behind-api-client/sales/SalesV10Company.js +120 -0
- package/lib/behind-api-client/sales/SalesV10Group.js +70 -0
- package/lib/behind-api-client/sales/SalesV10Groups.js +21 -0
- package/lib/behind-api-client/sales/SalesV10Logs.js +14 -0
- package/lib/behind-api-client/sales/SalesV10Notes.js +38 -0
- package/lib/behind-api-client/sales/SalesV20.js +11 -0
- package/lib/behind-api-client/sales/SalesV20Companies.js +26 -0
- package/lib/behind-api-client/sales/SalesV20Notes.js +17 -0
- package/lib/behind-api-client/sip/SipApp.js +9 -0
- package/lib/behind-api-client/sip/SipV10.js +15 -0
- package/lib/behind-api-client/sip/SipV10Call.js +83 -0
- package/lib/behind-api-client/sip/SipV10Phone.js +44 -0
- package/lib/behind-api-client/sip/SipV10Transcript.js +21 -0
- package/lib/behind-api-client/sip/SipV10Transcripts.js +21 -0
- package/lib/behind-api-client/storage/StorageApp.js +9 -0
- package/lib/behind-api-client/storage/StorageV10.js +11 -0
- package/lib/behind-api-client/storage/StorageV10File.js +35 -0
- package/lib/behind-api-client/storage/StorageV10Upload.js +21 -0
- package/lib/behind-api-client/tests/TestsApp.js +9 -0
- package/lib/behind-api-client/tests/TestsV10.js +15 -0
- package/lib/behind-api-client/tests/TestsV10Cases.js +29 -0
- package/lib/behind-api-client/tests/TestsV10CasesExtended.js +14 -0
- package/lib/behind-api-client/tests/TestsV10Core.js +14 -0
- package/lib/behind-api-client/tests/TestsV10Mail.js +14 -0
- package/lib/behind-api-client/tools/ToolsApp.js +9 -0
- package/lib/behind-api-client/tools/ToolsV10.js +9 -0
- package/lib/behind-api-client/tools/ToolsV10Pdf.js +30 -0
- package/package.json +25 -0
|
@@ -0,0 +1,901 @@
|
|
|
1
|
+
# Payments API V21 - Payture Endpoint
|
|
2
|
+
|
|
3
|
+
This document provides detailed information about the Payture payment gateway integration methods for the V21 Payments API.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The Payture Payments API V21 provides methods for initializing payment sessions through the Payture EWallet gateway. This includes creating payment sessions for both authorized and unauthorized users, managing customer accounts, and handling subscription payment flows with card registration.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Payments API V21 - Payture Methods
|
|
12
|
+
|
|
13
|
+
### behindAPI.V21.payments.payture.init()
|
|
14
|
+
Initializes a payment session for an authorized user.
|
|
15
|
+
|
|
16
|
+
**Parameters:**
|
|
17
|
+
- None (uses authenticated user session)
|
|
18
|
+
|
|
19
|
+
**Authorization:**
|
|
20
|
+
- Required: No (but uses session if available)
|
|
21
|
+
|
|
22
|
+
**Usage:**
|
|
23
|
+
```javascript
|
|
24
|
+
const result = await behindAPI.V21.payments.payture.init();
|
|
25
|
+
|
|
26
|
+
// Response:
|
|
27
|
+
{
|
|
28
|
+
success: true,
|
|
29
|
+
data: {
|
|
30
|
+
Success: "True",
|
|
31
|
+
Amount: "10.00",
|
|
32
|
+
SessionLifeTime: "60",
|
|
33
|
+
AttemptsCount: "5",
|
|
34
|
+
SessionId: "38ff74a9-c37c-42ba-a38a-bca05afecfc9",
|
|
35
|
+
SessionType: "Add",
|
|
36
|
+
RedirectUrl: "https://sandbox3.payture.com/vwapi/Add?SessionId=38ff74a9-c37c-42ba-a38a-bca05afecfc9",
|
|
37
|
+
Cmd: "Init"
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Error Response:
|
|
42
|
+
{
|
|
43
|
+
success: false,
|
|
44
|
+
message: "Can't finish request",
|
|
45
|
+
e: { /* error details */ }
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### behindAPI.V21.payments.payture.initUnauthorised(userId)
|
|
50
|
+
Authorizes payment for a user subscription through Payture EWallet. Creates or verifies user wallet, registers customer in Payture, and initializes payment session for card registration.
|
|
51
|
+
|
|
52
|
+
**Parameters:**
|
|
53
|
+
- `userId` (string, required) - User ID for payment authorization
|
|
54
|
+
|
|
55
|
+
**Authorization:**
|
|
56
|
+
- Required: No
|
|
57
|
+
|
|
58
|
+
**Usage:**
|
|
59
|
+
```javascript
|
|
60
|
+
const result = await behindAPI.V21.payments.payture.initUnauthorised(
|
|
61
|
+
"550e8400-e29b-41d4-a716-446655440001"
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
// Response:
|
|
65
|
+
{
|
|
66
|
+
success: true,
|
|
67
|
+
data: {
|
|
68
|
+
Success: "True",
|
|
69
|
+
Amount: "10.00",
|
|
70
|
+
SessionLifeTime: "60",
|
|
71
|
+
AttemptsCount: "5",
|
|
72
|
+
SessionId: "38ff74a9-c37c-42ba-a38a-bca05afecfc9",
|
|
73
|
+
SessionType: "Add",
|
|
74
|
+
RedirectUrl: "https://sandbox3.payture.com/vwapi/Add?SessionId=38ff74a9-c37c-42ba-a38a-bca05afecfc9",
|
|
75
|
+
Cmd: "Init"
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Error Response:
|
|
80
|
+
{
|
|
81
|
+
success: false,
|
|
82
|
+
message: "Can't finish request",
|
|
83
|
+
e: { /* error details */ }
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### behindAPI.V21.payments.payture.finalise()
|
|
88
|
+
Finalizes the payment process after card registration. Retrieves user's card list from Payture, selects the first active card that doesn't require CVV and isn't expired, and saves it to the database.
|
|
89
|
+
|
|
90
|
+
**Parameters:**
|
|
91
|
+
- None (uses authenticated user session)
|
|
92
|
+
|
|
93
|
+
**Authorization:**
|
|
94
|
+
- Required: No (but uses session)
|
|
95
|
+
|
|
96
|
+
**Usage:**
|
|
97
|
+
```javascript
|
|
98
|
+
const result = await behindAPI.V21.payments.payture.finalise();
|
|
99
|
+
|
|
100
|
+
// Success Response (with active card):
|
|
101
|
+
{
|
|
102
|
+
success: true,
|
|
103
|
+
data: {
|
|
104
|
+
card: {
|
|
105
|
+
CardName: "411111******1111",
|
|
106
|
+
CardHolder: "JOHN DOE",
|
|
107
|
+
Status: "IsActive",
|
|
108
|
+
NoCVV: "false",
|
|
109
|
+
Expired: "false"
|
|
110
|
+
// Note: CardId is removed for security
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Error Response (no active card):
|
|
116
|
+
{
|
|
117
|
+
success: false,
|
|
118
|
+
message: "No active card found"
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Error Response (can't get cards):
|
|
122
|
+
{
|
|
123
|
+
success: false,
|
|
124
|
+
message: "Can't get card list",
|
|
125
|
+
e: { /* error details */ }
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## Data Structure Reference
|
|
132
|
+
|
|
133
|
+
### Payment Initialization Response
|
|
134
|
+
The `init()` and `initUnauthorised()` methods return:
|
|
135
|
+
|
|
136
|
+
**Success Response:**
|
|
137
|
+
- `success` (boolean) - Always `true` for successful requests
|
|
138
|
+
- `data` (object) - Payture response data
|
|
139
|
+
- `Success` (string) - Payture success indicator ("True"/"False")
|
|
140
|
+
- `Amount` (string) - Payment amount in rubles (e.g., "10.00")
|
|
141
|
+
- `SessionLifeTime` (string) - Session lifetime in minutes (e.g., "60")
|
|
142
|
+
- `AttemptsCount` (string) - Number of payment attempts allowed (e.g., "5")
|
|
143
|
+
- `SessionId` (UUID string) - Unique payment session ID
|
|
144
|
+
- `SessionType` (string) - Session type ("Add" for card registration)
|
|
145
|
+
- `RedirectUrl` (string) - URL to redirect user for payment/card registration
|
|
146
|
+
- `Cmd` (string) - Command type ("Init")
|
|
147
|
+
|
|
148
|
+
**Error Response:**
|
|
149
|
+
- `success` (boolean) - Always `false` for failed requests
|
|
150
|
+
- `message` (string) - Error description
|
|
151
|
+
- `e` (object) - Error details
|
|
152
|
+
|
|
153
|
+
### Subscription Creation Response
|
|
154
|
+
The `finalise()` method returns:
|
|
155
|
+
|
|
156
|
+
**Success Response:**
|
|
157
|
+
- `success` (boolean) - Always `true` for successful requests
|
|
158
|
+
- `data` (object) - Container for response data
|
|
159
|
+
- `card` (object) - Selected active card information
|
|
160
|
+
- `CardName` (string) - Masked card number (e.g., "411111******1111")
|
|
161
|
+
- `CardHolder` (string) - Cardholder name
|
|
162
|
+
- `Status` (string) - Card status ("IsActive")
|
|
163
|
+
- `NoCVV` (string) - Whether CVV is required ("true"/"false")
|
|
164
|
+
- `Expired` (string) - Whether card is expired ("true"/"false")
|
|
165
|
+
|
|
166
|
+
**Error Response:**
|
|
167
|
+
- `success` (boolean) - Always `false` for failed requests
|
|
168
|
+
- `message` (string) - Error description ("No active card found", "Can't get card list")
|
|
169
|
+
- `e` (object, optional) - Error details
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## Complete Usage Examples
|
|
174
|
+
|
|
175
|
+
### Basic Payment Initialization for Guest Users
|
|
176
|
+
|
|
177
|
+
```javascript
|
|
178
|
+
// Example: Initialize payment for guest user
|
|
179
|
+
async function initializeGuestPayment(userId) {
|
|
180
|
+
try {
|
|
181
|
+
console.log("Initializing payment session...");
|
|
182
|
+
|
|
183
|
+
const result = await behindAPI.V21.payments.payture.initUnauthorised(userId);
|
|
184
|
+
|
|
185
|
+
if (result.success) {
|
|
186
|
+
console.log("✓ Payment session initialized!");
|
|
187
|
+
console.log(`Session ID: ${result.data.SessionId}`);
|
|
188
|
+
console.log(`Payment URL: ${result.data.RedirectUrl}`);
|
|
189
|
+
console.log(`Session lifetime: ${result.data.SessionLifeTime} minutes`);
|
|
190
|
+
|
|
191
|
+
// Redirect user to Payture for card registration
|
|
192
|
+
window.location.href = result.data.RedirectUrl;
|
|
193
|
+
|
|
194
|
+
return result.data;
|
|
195
|
+
} else {
|
|
196
|
+
console.log(`✗ Failed to initialize payment: ${result.message}`);
|
|
197
|
+
return null;
|
|
198
|
+
}
|
|
199
|
+
} catch (error) {
|
|
200
|
+
console.error("Error initializing payment:", error);
|
|
201
|
+
return null;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Usage
|
|
206
|
+
const sessionData = await initializeGuestPayment(
|
|
207
|
+
"aa0e8400-e29b-41d4-a716-446655440005"
|
|
208
|
+
);
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### Payment Initialization for Authorized Users
|
|
212
|
+
|
|
213
|
+
```javascript
|
|
214
|
+
// Example: Initialize payment for logged-in user
|
|
215
|
+
async function initializeUserPayment() {
|
|
216
|
+
try {
|
|
217
|
+
console.log("Initializing payment for authorized user...");
|
|
218
|
+
|
|
219
|
+
const result = await behindAPI.V21.payments.payture.init();
|
|
220
|
+
|
|
221
|
+
if (result.success) {
|
|
222
|
+
console.log("✓ Payment session ready!");
|
|
223
|
+
console.log(`Redirect URL: ${result.data.RedirectUrl}`);
|
|
224
|
+
|
|
225
|
+
// Store session ID for later reference
|
|
226
|
+
sessionStorage.setItem('payture_session_id', result.data.SessionId);
|
|
227
|
+
|
|
228
|
+
// Open in new window or redirect
|
|
229
|
+
const paymentWindow = window.open(result.data.RedirectUrl, '_blank');
|
|
230
|
+
|
|
231
|
+
if (!paymentWindow || paymentWindow.closed) {
|
|
232
|
+
// Fallback to same-window redirect
|
|
233
|
+
window.location.href = result.data.RedirectUrl;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
return result.data;
|
|
237
|
+
} else {
|
|
238
|
+
console.error(`✗ Initialization failed: ${result.message}`);
|
|
239
|
+
return null;
|
|
240
|
+
}
|
|
241
|
+
} catch (error) {
|
|
242
|
+
console.error("Error:", error);
|
|
243
|
+
return null;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Usage
|
|
248
|
+
const paymentData = await initializeUserPayment();
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
### Complete Card Registration and Finalization Flow
|
|
252
|
+
|
|
253
|
+
```javascript
|
|
254
|
+
// Example: Register card and finalize after callback
|
|
255
|
+
async function registerAndFinalizeCard() {
|
|
256
|
+
try {
|
|
257
|
+
console.log("Step 1: Initializing card registration...");
|
|
258
|
+
|
|
259
|
+
const initResult = await behindAPI.V21.payments.payture.init();
|
|
260
|
+
|
|
261
|
+
if (!initResult.success) {
|
|
262
|
+
console.error(`✗ Initialization failed: ${initResult.message}`);
|
|
263
|
+
return null;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
console.log("✓ Card registration session initialized!");
|
|
267
|
+
console.log(`Redirect URL: ${initResult.data.RedirectUrl}`);
|
|
268
|
+
|
|
269
|
+
// Store session data
|
|
270
|
+
sessionStorage.setItem('payture_session_id', initResult.data.SessionId);
|
|
271
|
+
sessionStorage.setItem('card_registration_pending', 'true');
|
|
272
|
+
|
|
273
|
+
// Redirect user to Payture
|
|
274
|
+
window.location.href = initResult.data.RedirectUrl;
|
|
275
|
+
|
|
276
|
+
return initResult.data;
|
|
277
|
+
|
|
278
|
+
} catch (error) {
|
|
279
|
+
console.error("Error:", error);
|
|
280
|
+
return null;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// After user returns from Payture (in callback page)
|
|
285
|
+
async function finalizeCardRegistration() {
|
|
286
|
+
try {
|
|
287
|
+
console.log("Step 2: Finalizing card registration...");
|
|
288
|
+
|
|
289
|
+
// Check if there's a pending registration
|
|
290
|
+
const isPending = sessionStorage.getItem('card_registration_pending');
|
|
291
|
+
|
|
292
|
+
if (!isPending) {
|
|
293
|
+
console.log("No pending card registration");
|
|
294
|
+
return null;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// Parse callback parameters
|
|
298
|
+
const params = new URLSearchParams(window.location.search);
|
|
299
|
+
const success = params.get('result');
|
|
300
|
+
|
|
301
|
+
if (success !== 'True') {
|
|
302
|
+
console.error("Card registration was not successful");
|
|
303
|
+
sessionStorage.removeItem('card_registration_pending');
|
|
304
|
+
return null;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// Finalize the registration
|
|
308
|
+
const finalizeResult = await behindAPI.V21.payments.payture.finalise();
|
|
309
|
+
|
|
310
|
+
if (finalizeResult.success) {
|
|
311
|
+
console.log("✓ Card registered successfully!");
|
|
312
|
+
console.log(`Card: ${finalizeResult.data.card.CardName}`);
|
|
313
|
+
console.log(`Holder: ${finalizeResult.data.card.CardHolder}`);
|
|
314
|
+
|
|
315
|
+
// Clear pending flag
|
|
316
|
+
sessionStorage.removeItem('card_registration_pending');
|
|
317
|
+
|
|
318
|
+
return {
|
|
319
|
+
cardInfo: {
|
|
320
|
+
maskedNumber: finalizeResult.data.card.CardName,
|
|
321
|
+
holder: finalizeResult.data.card.CardHolder
|
|
322
|
+
}
|
|
323
|
+
};
|
|
324
|
+
} else {
|
|
325
|
+
console.log(`✗ Failed to finalize: ${finalizeResult.message}`);
|
|
326
|
+
|
|
327
|
+
if (finalizeResult.message === "No active card found") {
|
|
328
|
+
console.log("No valid card was registered. Please try again.");
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
return null;
|
|
332
|
+
}
|
|
333
|
+
} catch (error) {
|
|
334
|
+
console.error("Error finalizing card registration:", error);
|
|
335
|
+
return null;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// Usage on main page - Start registration
|
|
340
|
+
await registerAndFinalizeCard();
|
|
341
|
+
|
|
342
|
+
// Usage on callback page - Complete registration
|
|
343
|
+
const cardData = await finalizeCardRegistration();
|
|
344
|
+
if (cardData) {
|
|
345
|
+
// Proceed with subscription creation
|
|
346
|
+
window.location.href = '/create-subscription';
|
|
347
|
+
}
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
### Complete Payment Flow with Two-Step Process
|
|
351
|
+
|
|
352
|
+
```javascript
|
|
353
|
+
// Example: Full payment flow - card registration, finalization, and subscription creation
|
|
354
|
+
async function completePaymentFlow(userId, subscriptionId) {
|
|
355
|
+
const flow = {
|
|
356
|
+
step: 1,
|
|
357
|
+
status: "starting",
|
|
358
|
+
data: {}
|
|
359
|
+
};
|
|
360
|
+
|
|
361
|
+
try {
|
|
362
|
+
// Step 1: Initialize payment session
|
|
363
|
+
console.log("Step 1: Initializing card registration...");
|
|
364
|
+
flow.step = 1;
|
|
365
|
+
|
|
366
|
+
const initResult = await behindAPI.V21.payments.payture.initUnauthorised(userId);
|
|
367
|
+
|
|
368
|
+
if (!initResult.success) {
|
|
369
|
+
flow.status = "failed_init";
|
|
370
|
+
flow.error = initResult.message;
|
|
371
|
+
return flow;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
flow.data.sessionId = initResult.data.SessionId;
|
|
375
|
+
flow.data.redirectUrl = initResult.data.RedirectUrl;
|
|
376
|
+
console.log("✓ Session initialized");
|
|
377
|
+
|
|
378
|
+
// Step 2: Redirect user for card registration
|
|
379
|
+
console.log("Step 2: Redirecting to Payture...");
|
|
380
|
+
flow.step = 2;
|
|
381
|
+
|
|
382
|
+
// Store flow data before redirect
|
|
383
|
+
sessionStorage.setItem('payment_flow', JSON.stringify(flow));
|
|
384
|
+
sessionStorage.setItem('pending_subscription', subscriptionId);
|
|
385
|
+
sessionStorage.setItem('card_registration_pending', 'true');
|
|
386
|
+
|
|
387
|
+
// Redirect user
|
|
388
|
+
window.location.href = initResult.data.RedirectUrl;
|
|
389
|
+
|
|
390
|
+
// AFTER USER RETURNS FROM PAYTURE (in callback handler):
|
|
391
|
+
|
|
392
|
+
// Step 3: Finalize card registration
|
|
393
|
+
console.log("Step 3: Finalizing card registration...");
|
|
394
|
+
flow.step = 3;
|
|
395
|
+
|
|
396
|
+
const finalizeResult = await behindAPI.V21.payments.payture.finalise();
|
|
397
|
+
|
|
398
|
+
if (!finalizeResult.success) {
|
|
399
|
+
flow.status = "failed_finalize";
|
|
400
|
+
flow.error = finalizeResult.message;
|
|
401
|
+
return flow;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
flow.data.cardInfo = finalizeResult.data.card;
|
|
405
|
+
console.log("✓ Card registered and saved");
|
|
406
|
+
|
|
407
|
+
// Step 4: Create subscription instance
|
|
408
|
+
console.log("Step 4: Creating subscription...");
|
|
409
|
+
flow.step = 4;
|
|
410
|
+
|
|
411
|
+
const subscriptionResult = await behindAPI.V21.payments.subscriptions.create(
|
|
412
|
+
subscriptionId
|
|
413
|
+
);
|
|
414
|
+
|
|
415
|
+
if (!subscriptionResult.success) {
|
|
416
|
+
flow.status = "failed_subscription";
|
|
417
|
+
flow.error = subscriptionResult.message;
|
|
418
|
+
return flow;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
flow.data.subscriptionId = subscriptionResult.data.subscription_instance_id;
|
|
422
|
+
flow.status = "completed";
|
|
423
|
+
console.log("✓ Payment flow completed successfully");
|
|
424
|
+
|
|
425
|
+
return flow;
|
|
426
|
+
|
|
427
|
+
} catch (error) {
|
|
428
|
+
console.error(`Error at step ${flow.step}:`, error);
|
|
429
|
+
flow.status = "error";
|
|
430
|
+
flow.error = error.message;
|
|
431
|
+
return flow;
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
// Usage on main page
|
|
436
|
+
const result = await completePaymentFlow(
|
|
437
|
+
"aa0e8400-e29b-41d4-a716-446655440005",
|
|
438
|
+
"premium-monthly"
|
|
439
|
+
);
|
|
440
|
+
|
|
441
|
+
// Usage on callback page (after Payture redirect)
|
|
442
|
+
async function handlePaymentCallback() {
|
|
443
|
+
const urlParams = new URLSearchParams(window.location.search);
|
|
444
|
+
const orderid = urlParams.get('orderid');
|
|
445
|
+
const success = urlParams.get('result');
|
|
446
|
+
|
|
447
|
+
if (success === 'True') {
|
|
448
|
+
console.log("Card registration successful, finalizing...");
|
|
449
|
+
|
|
450
|
+
// Step 1: Finalize card registration
|
|
451
|
+
const finalizeResult = await behindAPI.V21.payments.payture.finalise();
|
|
452
|
+
|
|
453
|
+
if (!finalizeResult.success) {
|
|
454
|
+
console.error("Failed to finalize card:", finalizeResult.message);
|
|
455
|
+
window.location.href = '/error?reason=card_finalization_failed';
|
|
456
|
+
return;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
console.log("Card finalized successfully!");
|
|
460
|
+
|
|
461
|
+
// Step 2: Create subscription if there's a pending one
|
|
462
|
+
const subscriptionId = sessionStorage.getItem('pending_subscription');
|
|
463
|
+
|
|
464
|
+
if (subscriptionId) {
|
|
465
|
+
console.log("Creating subscription...");
|
|
466
|
+
|
|
467
|
+
const subscriptionResult = await behindAPI.V21.payments.subscriptions.create(
|
|
468
|
+
subscriptionId
|
|
469
|
+
);
|
|
470
|
+
|
|
471
|
+
if (subscriptionResult.success) {
|
|
472
|
+
console.log("Subscription created!");
|
|
473
|
+
sessionStorage.removeItem('pending_subscription');
|
|
474
|
+
sessionStorage.removeItem('card_registration_pending');
|
|
475
|
+
// Redirect to success page
|
|
476
|
+
window.location.href = '/subscription-success';
|
|
477
|
+
} else {
|
|
478
|
+
console.error("Failed to create subscription:", subscriptionResult.message);
|
|
479
|
+
window.location.href = '/error?reason=subscription_creation_failed';
|
|
480
|
+
}
|
|
481
|
+
} else {
|
|
482
|
+
// No subscription to create, just card registration
|
|
483
|
+
sessionStorage.removeItem('card_registration_pending');
|
|
484
|
+
window.location.href = '/cards-success';
|
|
485
|
+
}
|
|
486
|
+
} else {
|
|
487
|
+
console.log("Card registration was not successful");
|
|
488
|
+
sessionStorage.removeItem('card_registration_pending');
|
|
489
|
+
window.location.href = '/error?reason=card_registration_failed';
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
### Handling Card Registration Callbacks
|
|
495
|
+
|
|
496
|
+
```javascript
|
|
497
|
+
// Example: Process callback after card registration using finalise
|
|
498
|
+
class PaytureCallbackHandler {
|
|
499
|
+
constructor() {
|
|
500
|
+
this.processCallback();
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
async processCallback() {
|
|
504
|
+
try {
|
|
505
|
+
// Parse URL parameters
|
|
506
|
+
const params = new URLSearchParams(window.location.search);
|
|
507
|
+
const orderId = params.get('orderid');
|
|
508
|
+
const success = params.get('result');
|
|
509
|
+
|
|
510
|
+
console.log(`Order ID: ${orderId}`);
|
|
511
|
+
console.log(`Success: ${success}`);
|
|
512
|
+
|
|
513
|
+
if (success !== 'True') {
|
|
514
|
+
this.handleFailure("Card registration was cancelled or failed");
|
|
515
|
+
return;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
// Wait a bit for Payture to process
|
|
519
|
+
await this.sleep(2000);
|
|
520
|
+
|
|
521
|
+
// Step 1: Finalize card registration
|
|
522
|
+
console.log("Finalizing card registration...");
|
|
523
|
+
const finalizeResult = await behindAPI.V21.payments.payture.finalise();
|
|
524
|
+
|
|
525
|
+
if (!finalizeResult.success) {
|
|
526
|
+
this.handleFailure(finalizeResult.message);
|
|
527
|
+
return;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
console.log("Card registered successfully!");
|
|
531
|
+
|
|
532
|
+
// Step 2: Check if there's a pending subscription to create
|
|
533
|
+
const subscriptionId = sessionStorage.getItem('pending_subscription');
|
|
534
|
+
|
|
535
|
+
if (subscriptionId) {
|
|
536
|
+
console.log("Creating subscription...");
|
|
537
|
+
|
|
538
|
+
const subscriptionResult = await behindAPI.V21.payments.subscriptions.create(
|
|
539
|
+
subscriptionId
|
|
540
|
+
);
|
|
541
|
+
|
|
542
|
+
if (subscriptionResult.success) {
|
|
543
|
+
this.handleSuccess(finalizeResult.data, subscriptionResult.data);
|
|
544
|
+
} else {
|
|
545
|
+
this.handleFailure(subscriptionResult.message);
|
|
546
|
+
}
|
|
547
|
+
} else {
|
|
548
|
+
// No subscription, just card registration
|
|
549
|
+
this.handleCardOnlySuccess(finalizeResult.data);
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
} catch (error) {
|
|
553
|
+
console.error("Callback processing error:", error);
|
|
554
|
+
this.handleFailure(error.message);
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
handleSuccess(cardData, subscriptionData) {
|
|
559
|
+
console.log("✓ Subscription activated!");
|
|
560
|
+
console.log(`Subscription ID: ${subscriptionData.subscription_instance_id}`);
|
|
561
|
+
console.log(`Card: ${cardData.card.CardName}`);
|
|
562
|
+
|
|
563
|
+
// Clear session data
|
|
564
|
+
sessionStorage.removeItem('pending_subscription');
|
|
565
|
+
sessionStorage.removeItem('payment_flow');
|
|
566
|
+
sessionStorage.removeItem('card_registration_pending');
|
|
567
|
+
|
|
568
|
+
// Show success message
|
|
569
|
+
this.showMessage(
|
|
570
|
+
`Your subscription has been activated! Card: ${cardData.card.CardName}`,
|
|
571
|
+
'success'
|
|
572
|
+
);
|
|
573
|
+
|
|
574
|
+
// Redirect after delay
|
|
575
|
+
setTimeout(() => {
|
|
576
|
+
window.location.href = '/dashboard';
|
|
577
|
+
}, 3000);
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
handleCardOnlySuccess(cardData) {
|
|
581
|
+
console.log("✓ Card registered successfully!");
|
|
582
|
+
console.log(`Card: ${cardData.card.CardName}`);
|
|
583
|
+
|
|
584
|
+
// Clear session data
|
|
585
|
+
sessionStorage.removeItem('card_registration_pending');
|
|
586
|
+
|
|
587
|
+
// Show success message
|
|
588
|
+
this.showMessage(
|
|
589
|
+
`Card registered successfully: ${cardData.card.CardName}`,
|
|
590
|
+
'success'
|
|
591
|
+
);
|
|
592
|
+
|
|
593
|
+
// Redirect after delay
|
|
594
|
+
setTimeout(() => {
|
|
595
|
+
window.location.href = '/cards';
|
|
596
|
+
}, 3000);
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
handleFailure(message = "Payment failed") {
|
|
600
|
+
console.error("✗ Process failed:", message);
|
|
601
|
+
|
|
602
|
+
// Clear pending flags
|
|
603
|
+
sessionStorage.removeItem('card_registration_pending');
|
|
604
|
+
|
|
605
|
+
this.showMessage(
|
|
606
|
+
`Failed: ${message}. Please try again.`,
|
|
607
|
+
'error'
|
|
608
|
+
);
|
|
609
|
+
|
|
610
|
+
// Redirect after delay
|
|
611
|
+
setTimeout(() => {
|
|
612
|
+
window.location.href = '/subscribe';
|
|
613
|
+
}, 3000);
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
showMessage(text, type = 'info') {
|
|
617
|
+
// Implement your UI message display
|
|
618
|
+
console.log(`[${type.toUpperCase()}] ${text}`);
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
sleep(ms) {
|
|
622
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
// Initialize on callback page
|
|
627
|
+
if (window.location.pathname === '/payment/callback') {
|
|
628
|
+
new PaytureCallbackHandler();
|
|
629
|
+
}
|
|
630
|
+
```
|
|
631
|
+
|
|
632
|
+
---
|
|
633
|
+
|
|
634
|
+
## Internal Process Flow
|
|
635
|
+
|
|
636
|
+
### Customer Registration Process
|
|
637
|
+
1. **Check Wallet**: System verifies user has RUB wallet
|
|
638
|
+
2. **Create Wallet**: Creates RUB wallet if needed
|
|
639
|
+
3. **Register Customer**: Registers customer in Payture with credentials
|
|
640
|
+
- Username: `customer-{user_id}`
|
|
641
|
+
- Password: MD5 hash of `{user_id}{salt}`
|
|
642
|
+
4. **Initialize Session**: Creates payment session for card registration
|
|
643
|
+
|
|
644
|
+
### Card Selection Logic
|
|
645
|
+
The `createSubscription()` method selects cards based on:
|
|
646
|
+
- `Status`: Must be "IsActive"
|
|
647
|
+
- `NoCVV`: Must be "false" (CVV not required for recurring)
|
|
648
|
+
- `Expired`: Must be "false"
|
|
649
|
+
- Selection: First matching card is used
|
|
650
|
+
|
|
651
|
+
### Session Parameters
|
|
652
|
+
Payment sessions are initialized with:
|
|
653
|
+
- **Amount**: 1000 kopecks (10.00 RUB) - test amount for card verification
|
|
654
|
+
- **SessionType**: "Add" - for card registration
|
|
655
|
+
- **Product**: "Ru-kitchen.ru"
|
|
656
|
+
- **Description**: "Monthly subscription for premium content"
|
|
657
|
+
|
|
658
|
+
---
|
|
659
|
+
|
|
660
|
+
## Testing
|
|
661
|
+
|
|
662
|
+
### Test Environment Setup
|
|
663
|
+
```javascript
|
|
664
|
+
// Configure test environment
|
|
665
|
+
const TEST_CONFIG = {
|
|
666
|
+
testUserId: "test-user-000000000000000000000001",
|
|
667
|
+
testSubscriptionId: "test-premium-monthly",
|
|
668
|
+
callbackUrl: "http://localhost:3000/payment/callback"
|
|
669
|
+
};
|
|
670
|
+
|
|
671
|
+
// Test payment initialization
|
|
672
|
+
async function testPaymentInit() {
|
|
673
|
+
console.log("=== TESTING PAYMENT INITIALIZATION ===\n");
|
|
674
|
+
|
|
675
|
+
// Test 1: Unauthorized init
|
|
676
|
+
console.log("Test 1: Initialize payment for guest...");
|
|
677
|
+
const initResult = await behindAPI.V21.payments.payture.initUnauthorised(
|
|
678
|
+
TEST_CONFIG.testUserId
|
|
679
|
+
);
|
|
680
|
+
|
|
681
|
+
console.log(initResult.success ? "✓ PASS" : "✗ FAIL");
|
|
682
|
+
if (initResult.success) {
|
|
683
|
+
console.log(`Session ID: ${initResult.data.SessionId}`);
|
|
684
|
+
console.log(`Redirect URL: ${initResult.data.RedirectUrl}\n`);
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
// Test 2: Authorized init
|
|
688
|
+
console.log("Test 2: Initialize payment for authorized user...");
|
|
689
|
+
const authInitResult = await behindAPI.V21.payments.payture.init();
|
|
690
|
+
|
|
691
|
+
console.log(authInitResult.success ? "✓ PASS" : "✗ FAIL\n");
|
|
692
|
+
|
|
693
|
+
console.log("=== TESTS COMPLETE ===");
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
// Test subscription creation
|
|
697
|
+
async function testSubscriptionCreation() {
|
|
698
|
+
console.log("=== TESTING SUBSCRIPTION CREATION ===\n");
|
|
699
|
+
|
|
700
|
+
console.log("Test: Create subscription with card...");
|
|
701
|
+
const result = await behindAPI.V21.payments.payture.createSubscription(
|
|
702
|
+
TEST_CONFIG.testSubscriptionId
|
|
703
|
+
);
|
|
704
|
+
|
|
705
|
+
if (result.success) {
|
|
706
|
+
console.log("✓ PASS");
|
|
707
|
+
console.log(`Subscription ID: ${result.data.subscription_instance_id}`);
|
|
708
|
+
console.log(`Card: ${result.data.card.CardName}`);
|
|
709
|
+
} else {
|
|
710
|
+
console.log("✗ FAIL");
|
|
711
|
+
console.log(`Error: ${result.message}`);
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
console.log("\n=== TEST COMPLETE ===");
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
// Run tests
|
|
718
|
+
testPaymentInit();
|
|
719
|
+
```
|
|
720
|
+
|
|
721
|
+
---
|
|
722
|
+
|
|
723
|
+
## Troubleshooting
|
|
724
|
+
|
|
725
|
+
### Common Issues and Solutions
|
|
726
|
+
|
|
727
|
+
**Issue: Payment session expired before user completed registration**
|
|
728
|
+
```javascript
|
|
729
|
+
// Solution: Check session lifetime and warn user
|
|
730
|
+
async function initWithExpiryWarning(userId) {
|
|
731
|
+
const result = await behindAPI.V21.payments.payture.initUnauthorised(userId);
|
|
732
|
+
|
|
733
|
+
if (result.success) {
|
|
734
|
+
const sessionMinutes = parseInt(result.data.SessionLifeTime);
|
|
735
|
+
|
|
736
|
+
alert(`Please complete payment within ${sessionMinutes} minutes`);
|
|
737
|
+
|
|
738
|
+
// Set warning timer
|
|
739
|
+
setTimeout(() => {
|
|
740
|
+
alert("Payment session will expire soon!");
|
|
741
|
+
}, (sessionMinutes - 5) * 60 * 1000); // Warn 5 minutes before expiry
|
|
742
|
+
|
|
743
|
+
window.location.href = result.data.RedirectUrl;
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
```
|
|
747
|
+
|
|
748
|
+
**Issue: No active cards found when finalizing**
|
|
749
|
+
```javascript
|
|
750
|
+
// Solution: Guide user to register a new card
|
|
751
|
+
async function finalizeWithFallback() {
|
|
752
|
+
const result = await behindAPI.V21.payments.payture.finalise();
|
|
753
|
+
|
|
754
|
+
if (!result.success && result.message === "No active card found") {
|
|
755
|
+
console.log("No card was registered. Redirecting to card registration...");
|
|
756
|
+
|
|
757
|
+
// Initialize new card registration session
|
|
758
|
+
const initResult = await behindAPI.V21.payments.payture.init();
|
|
759
|
+
|
|
760
|
+
if (initResult.success) {
|
|
761
|
+
window.location.href = initResult.data.RedirectUrl;
|
|
762
|
+
}
|
|
763
|
+
} else if (result.success) {
|
|
764
|
+
console.log("Card finalized successfully!");
|
|
765
|
+
return result.data;
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
```
|
|
769
|
+
|
|
770
|
+
**Issue: Wallet not created for user**
|
|
771
|
+
```javascript
|
|
772
|
+
// Solution: Ensure wallet creation is successful
|
|
773
|
+
async function verifyWalletBeforePayment(userId) {
|
|
774
|
+
try {
|
|
775
|
+
// The initUnauthorised method handles wallet creation automatically,
|
|
776
|
+
// but you can verify by checking the response
|
|
777
|
+
const result = await behindAPI.V21.payments.payture.initUnauthorised(userId);
|
|
778
|
+
|
|
779
|
+
if (!result.success) {
|
|
780
|
+
console.error("Failed to initialize payment. Wallet may not exist.");
|
|
781
|
+
// Attempt manual wallet creation through separate API if available
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
return result;
|
|
785
|
+
} catch (error) {
|
|
786
|
+
console.error("Wallet verification error:", error);
|
|
787
|
+
return { success: false, message: error.message };
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
```
|
|
791
|
+
|
|
792
|
+
**Issue: Callback URL parameters not being processed**
|
|
793
|
+
```javascript
|
|
794
|
+
// Solution: Robust parameter parsing
|
|
795
|
+
function parseCallbackParams() {
|
|
796
|
+
const params = new URLSearchParams(window.location.search);
|
|
797
|
+
|
|
798
|
+
const data = {
|
|
799
|
+
orderId: params.get('orderid'),
|
|
800
|
+
success: params.get('result'),
|
|
801
|
+
timestamp: Date.now()
|
|
802
|
+
};
|
|
803
|
+
|
|
804
|
+
// Validate parameters
|
|
805
|
+
if (!data.orderId) {
|
|
806
|
+
console.error("Missing order ID in callback");
|
|
807
|
+
return null;
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
// Normalize success value
|
|
811
|
+
data.success = data.success === 'True' || data.success === 'true' || data.success === '1';
|
|
812
|
+
|
|
813
|
+
console.log("Callback parameters:", data);
|
|
814
|
+
return data;
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
// Usage in callback handler
|
|
818
|
+
const callbackData = parseCallbackParams();
|
|
819
|
+
if (callbackData && callbackData.success) {
|
|
820
|
+
// Process successful payment
|
|
821
|
+
}
|
|
822
|
+
```
|
|
823
|
+
|
|
824
|
+
---
|
|
825
|
+
|
|
826
|
+
## Security Considerations
|
|
827
|
+
|
|
828
|
+
1. **Customer Credentials**: User passwords are hashed with MD5 and salt
|
|
829
|
+
2. **Session Security**: Payment sessions have limited lifetime (typically 60 minutes)
|
|
830
|
+
3. **Card Storage**: Card IDs are removed from responses for security
|
|
831
|
+
4. **HTTPS Required**: All redirect URLs must use HTTPS in production
|
|
832
|
+
5. **Rate Limiting**: Implement rate limiting on payment initialization
|
|
833
|
+
6. **Input Validation**: Always validate UUIDs and user IDs
|
|
834
|
+
7. **Error Handling**: Don't expose sensitive error details to users
|
|
835
|
+
8. **Audit Logging**: Log all payment operations
|
|
836
|
+
|
|
837
|
+
```javascript
|
|
838
|
+
// Example: Secure payment initialization with validation
|
|
839
|
+
async function securePaymentInit(userId) {
|
|
840
|
+
// Validate UUID format
|
|
841
|
+
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
842
|
+
|
|
843
|
+
if (!uuidRegex.test(userId)) {
|
|
844
|
+
return {
|
|
845
|
+
success: false,
|
|
846
|
+
message: "Invalid user ID format"
|
|
847
|
+
};
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
// Check rate limit
|
|
851
|
+
const rateLimitKey = `payment_init_${userId}`;
|
|
852
|
+
const attempts = parseInt(sessionStorage.getItem(rateLimitKey) || '0');
|
|
853
|
+
|
|
854
|
+
if (attempts >= 5) {
|
|
855
|
+
return {
|
|
856
|
+
success: false,
|
|
857
|
+
message: "Too many attempts. Please try again later."
|
|
858
|
+
};
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
// Increment attempt counter
|
|
862
|
+
sessionStorage.setItem(rateLimitKey, (attempts + 1).toString());
|
|
863
|
+
|
|
864
|
+
// Initialize payment
|
|
865
|
+
const result = await behindAPI.V21.payments.payture.initUnauthorised(userId);
|
|
866
|
+
|
|
867
|
+
// Log the operation (send to your logging service)
|
|
868
|
+
logPaymentOperation({
|
|
869
|
+
action: 'payment_init',
|
|
870
|
+
userId: userId,
|
|
871
|
+
success: result.success,
|
|
872
|
+
timestamp: new Date().toISOString()
|
|
873
|
+
});
|
|
874
|
+
|
|
875
|
+
return result;
|
|
876
|
+
}
|
|
877
|
+
```
|
|
878
|
+
|
|
879
|
+
---
|
|
880
|
+
|
|
881
|
+
## API Reference Summary
|
|
882
|
+
|
|
883
|
+
| Method | Authorization Required | Parameters | Returns |
|
|
884
|
+
|--------|----------------------|------------|---------|
|
|
885
|
+
| `init` | No | None | SessionId, RedirectUrl, SessionLifeTime |
|
|
886
|
+
| `initUnauthorised` | No | userId | SessionId, RedirectUrl, SessionLifeTime |
|
|
887
|
+
| `finalise` | No (uses session) | None | card |
|
|
888
|
+
|
|
889
|
+
---
|
|
890
|
+
|
|
891
|
+
## Support and Resources
|
|
892
|
+
|
|
893
|
+
For additional help:
|
|
894
|
+
- **API Documentation**: Refer to the main Payments API V21 documentation
|
|
895
|
+
- **Payture Documentation**: Check Payture's official EWallet API documentation
|
|
896
|
+
- **Database Procedures**:
|
|
897
|
+
- `escrow.tr_account_get_default` - Get user wallet
|
|
898
|
+
- `public.create_simple_wallet` - Create wallet
|
|
899
|
+
- `escrow.payment_method_create` - Save payment method
|
|
900
|
+
- **Support**: Contact your technical support team for integration assistance
|
|
901
|
+
- **Testing**: Always use sandbox environment before production deployment
|