@yosle/tropipayjs 0.2.1 → 0.2.2
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 +27 -0
- package/api/TropipayAPI.d.ts +31 -4
- package/index.d.ts +41 -104
- package/index.js +99 -81
- package/interfaces/index.d.ts +10 -35
- package/interfaces/paymentlink/index.d.ts +3 -1
- package/package.json +5 -2
- package/paymentcard/paymentcard.spec.d.ts +1 -0
- package/src/api/TropipayAPI.ts +129 -30
- package/src/depositAccount/depositAccounts.ts +5 -5
- package/src/index.ts +1 -0
- package/src/interfaces/index.ts +212 -264
- package/src/interfaces/paymentlink/index.d.ts +32 -33
- package/src/interfaces/paymentlink/index.ts +3 -1
- package/src/paymentcard/PaymentCard.ts +4 -4
- package/src/utils/TropipayUtils.ts +1 -40
- package/utils/TropipayUtils.d.ts +1 -14
- package/accounts/accounts.d.ts +0 -52
- package/src/accounts/accounts.ts +0 -86
package/interfaces/index.d.ts
CHANGED
|
@@ -35,71 +35,36 @@ export interface UserHookSubscribed extends UserHook {
|
|
|
35
35
|
createdAt: string;
|
|
36
36
|
updatedAt: string;
|
|
37
37
|
}
|
|
38
|
-
/**
|
|
39
|
-
* Interface for creating payment links/cards
|
|
40
|
-
* @see https://tpp.stoplight.io/docs/tropipay-api-doc/b3A6ODgyNTM3OQ-create-a-new-pay-link-charge
|
|
41
|
-
*/
|
|
42
38
|
export interface PaymentLinkPayload {
|
|
43
|
-
/** Account ID where the funds will be received if compatible */
|
|
44
|
-
accountId?: number;
|
|
45
|
-
/** Reference code for the payment, preferred to be unique */
|
|
46
39
|
reference: string;
|
|
47
|
-
/** Short description of the payment */
|
|
48
40
|
concept: string;
|
|
49
|
-
/** Whether to mark this payment link as favorite */
|
|
50
41
|
favorite: boolean;
|
|
51
|
-
/** Amount to charge in the specified currency */
|
|
52
42
|
amount: number;
|
|
53
|
-
/** Currency code (EUR, USD, etc.) */
|
|
54
43
|
currency: string;
|
|
55
|
-
/** Detailed description of the payment */
|
|
56
44
|
description: string;
|
|
57
|
-
/** If true, the payment link can only be used once */
|
|
58
45
|
singleUse: boolean;
|
|
59
|
-
/** Reason ID for the payment */
|
|
60
46
|
reasonId: number;
|
|
61
|
-
/** Number of days until the payment link expires */
|
|
62
47
|
expirationDays: number;
|
|
63
|
-
/** Language code for the payment page (en, es, etc.) */
|
|
64
48
|
lang: string;
|
|
65
|
-
/** URL to redirect after successful payment */
|
|
66
49
|
urlSuccess: string;
|
|
67
|
-
/** URL to redirect after failed payment */
|
|
68
50
|
urlFailed: string;
|
|
69
|
-
/** Webhook URL for payment notifications */
|
|
70
51
|
urlNotification: string;
|
|
71
|
-
/** Date when the service will be provided (ISO format) */
|
|
72
52
|
serviceDate: string;
|
|
73
|
-
/** Client information for the payment */
|
|
74
53
|
client?: {
|
|
75
|
-
/** Client's first name */
|
|
76
54
|
name?: string;
|
|
77
|
-
/** Client's last name */
|
|
78
55
|
lastName?: string;
|
|
79
|
-
/** Client's address */
|
|
80
56
|
address?: string;
|
|
81
|
-
/** Client's phone number */
|
|
82
57
|
phone?: string;
|
|
83
|
-
/** Client's email address */
|
|
84
58
|
email?: string;
|
|
85
|
-
/** Client's country ID */
|
|
86
59
|
countryId?: number;
|
|
87
|
-
/** Client's country ISO code */
|
|
88
60
|
countryIso?: string;
|
|
89
|
-
/** Client's city */
|
|
90
61
|
city: string;
|
|
91
|
-
/** Client's postal code */
|
|
92
62
|
postCode: string;
|
|
93
|
-
/** Whether client accepted terms and conditions */
|
|
94
63
|
termsAndConditions: boolean;
|
|
95
64
|
} | null;
|
|
96
|
-
/** @deprecated If true, redirects directly to payment page */
|
|
97
65
|
directPayment: boolean;
|
|
98
|
-
/** List of allowed payment methods */
|
|
99
66
|
paymentMethods?: string[];
|
|
100
|
-
/** Base64 encoded image for the payment page */
|
|
101
67
|
imageBase?: string;
|
|
102
|
-
/** Whether to save the payment token for future use */
|
|
103
68
|
saveToken?: boolean;
|
|
104
69
|
}
|
|
105
70
|
export interface PaymentLink extends PaymentLinkPayload {
|
|
@@ -199,3 +164,13 @@ export type AccountDeposits = {
|
|
|
199
164
|
count: number;
|
|
200
165
|
rows: Deposit[];
|
|
201
166
|
};
|
|
167
|
+
export type RefundResponse = {
|
|
168
|
+
id: number;
|
|
169
|
+
orderCode: string;
|
|
170
|
+
amount: number;
|
|
171
|
+
currency: string;
|
|
172
|
+
state: string;
|
|
173
|
+
type: string;
|
|
174
|
+
createdAt: string;
|
|
175
|
+
completedAt: string;
|
|
176
|
+
};
|
|
@@ -46,7 +46,6 @@ declare enum Reasons {
|
|
|
46
46
|
SENDING_YOU_A_KISS = 80
|
|
47
47
|
}
|
|
48
48
|
export interface PaymentLinkPayload {
|
|
49
|
-
accountId: number;
|
|
50
49
|
reference: string;
|
|
51
50
|
concept: string;
|
|
52
51
|
favorite: boolean;
|
|
@@ -61,6 +60,9 @@ export interface PaymentLinkPayload {
|
|
|
61
60
|
urlFailed: string;
|
|
62
61
|
urlNotification: string;
|
|
63
62
|
serviceDate: string;
|
|
63
|
+
/**
|
|
64
|
+
* fgfsgdfgdfgd
|
|
65
|
+
*/
|
|
64
66
|
client?: {
|
|
65
67
|
name: string;
|
|
66
68
|
lastName: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yosle/tropipayjs",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "Javascript / Typescript SDK for the Tropipay API",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -12,7 +12,10 @@
|
|
|
12
12
|
},
|
|
13
13
|
"repository": {
|
|
14
14
|
"type": "git",
|
|
15
|
-
"url": "https://github.com/yosle/tropipayjs"
|
|
15
|
+
"url": "git+https://github.com/yosle/tropipayjs.git"
|
|
16
|
+
},
|
|
17
|
+
"publishConfig": {
|
|
18
|
+
"access": "public"
|
|
16
19
|
},
|
|
17
20
|
"keywords": [
|
|
18
21
|
"Javascript",
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
declare function sum(a: number, b: number): number;
|
package/src/api/TropipayAPI.ts
CHANGED
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
MediationPaymentCardConfig,
|
|
16
16
|
LoginResponse,
|
|
17
17
|
AccountDeposits,
|
|
18
|
+
RefundResponse,
|
|
18
19
|
} from "../interfaces";
|
|
19
20
|
type ServerMode = "Development" | "Production";
|
|
20
21
|
import TropipayHooks from "../hooks/TropipayHooks";
|
|
@@ -22,13 +23,11 @@ import PaymentCard from "../paymentcard/PaymentCard";
|
|
|
22
23
|
import MediationPaymentCard from "../mediationPaymentCard/MediationPaymentCard";
|
|
23
24
|
import DepositAccounts from "../depositAccount/depositAccounts";
|
|
24
25
|
import { TropipayJSException, handleExceptions } from "../utils/errors";
|
|
25
|
-
import Accounts from "../accounts/accounts";
|
|
26
26
|
export class Tropipay {
|
|
27
27
|
readonly clientId: string;
|
|
28
28
|
readonly clientSecret: string;
|
|
29
29
|
readonly scopes: String[];
|
|
30
30
|
public request: Axios;
|
|
31
|
-
public loginRequest: Axios;
|
|
32
31
|
public static accessToken: string | null;
|
|
33
32
|
public static refreshToken: string | null;
|
|
34
33
|
public static expiresIn: number | null;
|
|
@@ -37,7 +36,6 @@ export class Tropipay {
|
|
|
37
36
|
public paymentCards: PaymentCard;
|
|
38
37
|
public depositAccounts: DepositAccounts;
|
|
39
38
|
public mediationPaymentCard: MediationPaymentCard;
|
|
40
|
-
public accounts: Accounts;
|
|
41
39
|
|
|
42
40
|
/**
|
|
43
41
|
* Initializes a new instance of the Tropipay class.
|
|
@@ -58,6 +56,7 @@ export class Tropipay {
|
|
|
58
56
|
"ALLOW_GET_BALANCE",
|
|
59
57
|
"ALLOW_GET_MOVEMENT_LIST",
|
|
60
58
|
"ALLOW_GET_CREDENTIAL",
|
|
59
|
+
"ALLOW_REFUND",
|
|
61
60
|
];
|
|
62
61
|
} else {
|
|
63
62
|
this.scopes = config.scopes;
|
|
@@ -75,12 +74,11 @@ export class Tropipay {
|
|
|
75
74
|
this.clientSecret = config.clientSecret;
|
|
76
75
|
this.serverMode = config.serverMode || "Development";
|
|
77
76
|
|
|
78
|
-
const tpp_env =
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
: "https://sandbox.tropipay.me";
|
|
77
|
+
const tpp_env = this.serverMode === "Production"
|
|
78
|
+
? "https://www.tropipay.com"
|
|
79
|
+
: "https://tropipay-dev.herokuapp.com";
|
|
82
80
|
this.request = axios.create({
|
|
83
|
-
baseURL: config.customTropipayUrl || tpp_env,
|
|
81
|
+
baseURL: config.customTropipayUrl || tpp_env,
|
|
84
82
|
headers: {
|
|
85
83
|
"Content-Type": "application/json",
|
|
86
84
|
Accept: "application/json",
|
|
@@ -88,33 +86,27 @@ export class Tropipay {
|
|
|
88
86
|
},
|
|
89
87
|
});
|
|
90
88
|
|
|
91
|
-
// Create a separate instance for login requests
|
|
92
|
-
this.loginRequest = axios.create({
|
|
93
|
-
baseURL: config.customTropipayUrl || tpp_env,
|
|
94
|
-
headers: {
|
|
95
|
-
"Content-Type": "application/json",
|
|
96
|
-
Accept: "application/json",
|
|
97
|
-
},
|
|
98
|
-
});
|
|
99
89
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
async (config) => {
|
|
103
|
-
const currentTimestamp = Math.floor(Date.now() / 1000);
|
|
90
|
+
// Add request interceptor for Token expired
|
|
91
|
+
this.request.interceptors.request.use(
|
|
92
|
+
async (config: any) => {
|
|
93
|
+
const currentTimestamp = Math.floor(Date.now() / 1000); // Current time in seconds
|
|
104
94
|
|
|
105
95
|
if (Tropipay.expiresIn && Tropipay.expiresIn < currentTimestamp) {
|
|
106
|
-
|
|
96
|
+
// Token has expired, attempt to refresh it
|
|
107
97
|
try {
|
|
108
|
-
|
|
98
|
+
await this.login();
|
|
109
99
|
} catch (error) {
|
|
110
|
-
|
|
100
|
+
// Handle token refresh error
|
|
101
|
+
Tropipay.accessToken = null;
|
|
102
|
+
Tropipay.refreshToken = null;
|
|
103
|
+
throw handleExceptions(error as any);
|
|
111
104
|
}
|
|
112
105
|
}
|
|
113
|
-
|
|
114
|
-
config.headers.Authorization = `Bearer ${Tropipay.accessToken}`;
|
|
106
|
+
|
|
115
107
|
return config;
|
|
116
108
|
},
|
|
117
|
-
(error) => {
|
|
109
|
+
(error: AxiosError) => {
|
|
118
110
|
return Promise.reject(error);
|
|
119
111
|
}
|
|
120
112
|
);
|
|
@@ -124,14 +116,34 @@ export class Tropipay {
|
|
|
124
116
|
this.mediationPaymentCard = new MediationPaymentCard(this);
|
|
125
117
|
|
|
126
118
|
this.depositAccounts = new DepositAccounts(this);
|
|
127
|
-
|
|
119
|
+
|
|
120
|
+
|
|
128
121
|
}
|
|
129
122
|
|
|
130
123
|
public async login() {
|
|
131
124
|
try {
|
|
125
|
+
if (Tropipay.refreshToken) {
|
|
126
|
+
const { data } = await this.request.post<LoginResponse>(
|
|
127
|
+
"/api/v2/access/token",
|
|
128
|
+
{
|
|
129
|
+
client_id: this.clientId,
|
|
130
|
+
client_secret: this.clientSecret,
|
|
131
|
+
grant_type: "refresh_token",
|
|
132
|
+
refresh_token: Tropipay.refreshToken,
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
headers: {
|
|
136
|
+
"Content-Type": "application/json",
|
|
137
|
+
Accept: "application/json",
|
|
138
|
+
},
|
|
139
|
+
}
|
|
140
|
+
);
|
|
141
|
+
return data;
|
|
142
|
+
}
|
|
143
|
+
|
|
132
144
|
// normal credetials login
|
|
133
|
-
const { data } = await this.
|
|
134
|
-
"/api/
|
|
145
|
+
const { data } = await this.request.post<LoginResponse>(
|
|
146
|
+
"/api/v2/access/token",
|
|
135
147
|
{
|
|
136
148
|
client_id: this.clientId,
|
|
137
149
|
client_secret: this.clientSecret,
|
|
@@ -147,13 +159,13 @@ export class Tropipay {
|
|
|
147
159
|
);
|
|
148
160
|
|
|
149
161
|
Tropipay.accessToken = data.access_token;
|
|
162
|
+
Tropipay.refreshToken = data.refresh_token;
|
|
150
163
|
Tropipay.expiresIn = data.expires_in;
|
|
151
164
|
return data;
|
|
152
165
|
} catch (error) {
|
|
153
166
|
Tropipay.accessToken = null;
|
|
154
167
|
Tropipay.refreshToken = null;
|
|
155
168
|
Tropipay.expiresIn = null;
|
|
156
|
-
Tropipay.expiresIn = null;
|
|
157
169
|
throw handleExceptions(error as any);
|
|
158
170
|
}
|
|
159
171
|
}
|
|
@@ -316,6 +328,7 @@ export class Tropipay {
|
|
|
316
328
|
* belonging or not to the TropiPay platform with the particularity
|
|
317
329
|
* that the payment will be held in custody or retained until it is
|
|
318
330
|
* released with the approval of the payer.
|
|
331
|
+
* @deprecated This method is no longer supported and may be removed in a future release.
|
|
319
332
|
* @see https://tpp.stoplight.io/docs/tropipay-api-doc/12a128ff971e4-creating-a-mediation-payment-card
|
|
320
333
|
* @param config Payload with the payment details
|
|
321
334
|
*/
|
|
@@ -340,6 +353,91 @@ export class Tropipay {
|
|
|
340
353
|
throw handleExceptions(error as any);
|
|
341
354
|
}
|
|
342
355
|
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* Refund a completed transaction.
|
|
359
|
+
* Requires 2FA enabled and ALLOW_REFUND permission on the Tropipay account.
|
|
360
|
+
*
|
|
361
|
+
* In Development mode, `securityCode` defaults to `"123456"` when omitted.
|
|
362
|
+
* In Production mode, you must first call `requestSecurityCode()` to receive
|
|
363
|
+
* the 2FA code via SMS, then pass it as the `securityCode` parameter.
|
|
364
|
+
*
|
|
365
|
+
* @see https://doc.tropipay.com/docs/api-reference/movements#refund-a-transaction
|
|
366
|
+
* @param orderCode Code of the order/transaction to refund (e.g. "ORD-123456")
|
|
367
|
+
* @param amount Amount to refund in cents (e.g. 5000 = 50.00 USD/EUR)
|
|
368
|
+
* @param securityCode 2FA confirmation code. Use "123456" in Development or
|
|
369
|
+
* the code received via SMS in Production (obtained via requestSecurityCode()).
|
|
370
|
+
*/
|
|
371
|
+
async refundMovement(
|
|
372
|
+
orderCode: string,
|
|
373
|
+
amount: number,
|
|
374
|
+
securityCode: string
|
|
375
|
+
): Promise<RefundResponse> {
|
|
376
|
+
if (!Tropipay.accessToken) {
|
|
377
|
+
await this.login();
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
if (!this.scopes.includes("ALLOW_REFUND")) {
|
|
381
|
+
throw new TropipayJSException(
|
|
382
|
+
"The credential does not have the ALLOW_REFUND scope required to perform refunds. If you believe your account should have this permission, please contact Tropipay support.",
|
|
383
|
+
403,
|
|
384
|
+
null
|
|
385
|
+
);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
try {
|
|
389
|
+
const response = await this.request.post(
|
|
390
|
+
"/api/v3/movements/in/refund",
|
|
391
|
+
{ orderCode, amount, securityCode },
|
|
392
|
+
{
|
|
393
|
+
headers: {
|
|
394
|
+
"Content-Type": "application/json",
|
|
395
|
+
Accept: "application/json",
|
|
396
|
+
Authorization: `Bearer ${Tropipay.accessToken}`,
|
|
397
|
+
},
|
|
398
|
+
}
|
|
399
|
+
);
|
|
400
|
+
return response.data as RefundResponse;
|
|
401
|
+
} catch (error) {
|
|
402
|
+
throw handleExceptions(error as any);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* Request a 2FA security code to be sent via SMS for confirming sensitive
|
|
408
|
+
* operations like refunds.
|
|
409
|
+
*
|
|
410
|
+
* In Production mode, you must call this method first to trigger an SMS with
|
|
411
|
+
* the code, then use the received code when calling `refundMovement()`.
|
|
412
|
+
* In Development mode this is not required as the default code "123456"
|
|
413
|
+
* is used automatically.
|
|
414
|
+
*
|
|
415
|
+
* @see https://doc.tropipay.com/docs/api-reference/movements#refund-a-transaction
|
|
416
|
+
* @returns The API response confirming the code was sent
|
|
417
|
+
*/
|
|
418
|
+
async requestSecurityCode(type: "sms" | "email" = "sms"): Promise<any> {
|
|
419
|
+
if (!Tropipay.accessToken) {
|
|
420
|
+
await this.login();
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
try {
|
|
424
|
+
const response = await this.request.post(
|
|
425
|
+
"/api/v3/users/sendSecurityCode",
|
|
426
|
+
{ type },
|
|
427
|
+
{
|
|
428
|
+
headers: {
|
|
429
|
+
"Content-Type": "application/json",
|
|
430
|
+
Accept: "application/json",
|
|
431
|
+
Authorization: `Bearer ${Tropipay.accessToken}`,
|
|
432
|
+
},
|
|
433
|
+
}
|
|
434
|
+
);
|
|
435
|
+
return response.data;
|
|
436
|
+
} catch (error) {
|
|
437
|
+
throw handleExceptions(error as any);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
|
|
343
441
|
}
|
|
344
442
|
|
|
345
443
|
export class ClientSideUtils {
|
|
@@ -357,4 +455,5 @@ export const Scopes = {
|
|
|
357
455
|
ALLOW_GET_BALANCE: "ALLOW_GET_BALANCE",
|
|
358
456
|
ALLOW_GET_MOVEMENT_LIST: "ALLOW_GET_MOVEMENT_LIST",
|
|
359
457
|
ALLOW_GET_CREDENTIAL: "ALLOW_GET_CREDENTIAL",
|
|
458
|
+
ALLOW_REFUND: "ALLOW_REFUND",
|
|
360
459
|
};
|
|
@@ -18,7 +18,7 @@ export default class DepositAccounts {
|
|
|
18
18
|
}
|
|
19
19
|
try {
|
|
20
20
|
const deposit = await this.tropipay.request.get(
|
|
21
|
-
`/api/
|
|
21
|
+
`/api/v2/deposit_accounts`,
|
|
22
22
|
{
|
|
23
23
|
headers: {
|
|
24
24
|
"Content-Type": "application/json",
|
|
@@ -43,7 +43,7 @@ export default class DepositAccounts {
|
|
|
43
43
|
}
|
|
44
44
|
try {
|
|
45
45
|
const deposit = await this.tropipay.request.post(
|
|
46
|
-
"/api/
|
|
46
|
+
"/api/v2/deposit_accounts",
|
|
47
47
|
depositAccountObj,
|
|
48
48
|
{
|
|
49
49
|
headers: {
|
|
@@ -70,7 +70,7 @@ export default class DepositAccounts {
|
|
|
70
70
|
}
|
|
71
71
|
try {
|
|
72
72
|
const deposit = await this.tropipay.request.get(
|
|
73
|
-
`/api/
|
|
73
|
+
`/api/v2/deposit_accounts/${id}`,
|
|
74
74
|
{
|
|
75
75
|
headers: {
|
|
76
76
|
"Content-Type": "application/json",
|
|
@@ -96,7 +96,7 @@ export default class DepositAccounts {
|
|
|
96
96
|
}
|
|
97
97
|
try {
|
|
98
98
|
const deposit = await this.tropipay.request.put(
|
|
99
|
-
`/api/
|
|
99
|
+
`/api/v2/deposit_accounts/`,
|
|
100
100
|
{
|
|
101
101
|
headers: {
|
|
102
102
|
"Content-Type": "application/json",
|
|
@@ -122,7 +122,7 @@ export default class DepositAccounts {
|
|
|
122
122
|
}
|
|
123
123
|
try {
|
|
124
124
|
const deposit = await this.tropipay.request.delete(
|
|
125
|
-
`/api/
|
|
125
|
+
`/api/v2/deposit_accounts/${id}`,
|
|
126
126
|
{
|
|
127
127
|
headers: {
|
|
128
128
|
"Content-Type": "application/json",
|
package/src/index.ts
CHANGED