pec-payment-sdk 1.1.1

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.
Files changed (47) hide show
  1. package/LICENSE +21 -0
  2. package/README.fa.md +212 -0
  3. package/README.md +212 -0
  4. package/dist/cjs/PecClient.d.ts +28 -0
  5. package/dist/cjs/PecClient.d.ts.map +1 -0
  6. package/dist/cjs/PecClient.js +218 -0
  7. package/dist/cjs/constants.d.ts +13 -0
  8. package/dist/cjs/constants.d.ts.map +1 -0
  9. package/dist/cjs/constants.js +15 -0
  10. package/dist/cjs/errors.d.ts +14 -0
  11. package/dist/cjs/errors.d.ts.map +1 -0
  12. package/dist/cjs/errors.js +28 -0
  13. package/dist/cjs/index.d.ts +6 -0
  14. package/dist/cjs/index.d.ts.map +1 -0
  15. package/dist/cjs/index.js +30 -0
  16. package/dist/cjs/soapClient.d.ts +6 -0
  17. package/dist/cjs/soapClient.d.ts.map +1 -0
  18. package/dist/cjs/soapClient.js +44 -0
  19. package/dist/cjs/types.d.ts +122 -0
  20. package/dist/cjs/types.d.ts.map +1 -0
  21. package/dist/cjs/types.js +2 -0
  22. package/dist/cjs/utils.d.ts +43 -0
  23. package/dist/cjs/utils.d.ts.map +1 -0
  24. package/dist/cjs/utils.js +162 -0
  25. package/dist/esm/PecClient.d.ts +28 -0
  26. package/dist/esm/PecClient.d.ts.map +1 -0
  27. package/dist/esm/PecClient.js +211 -0
  28. package/dist/esm/constants.d.ts +13 -0
  29. package/dist/esm/constants.d.ts.map +1 -0
  30. package/dist/esm/constants.js +12 -0
  31. package/dist/esm/errors.d.ts +14 -0
  32. package/dist/esm/errors.d.ts.map +1 -0
  33. package/dist/esm/errors.js +22 -0
  34. package/dist/esm/index.d.ts +6 -0
  35. package/dist/esm/index.d.ts.map +1 -0
  36. package/dist/esm/index.js +4 -0
  37. package/dist/esm/package.json +3 -0
  38. package/dist/esm/soapClient.d.ts +6 -0
  39. package/dist/esm/soapClient.d.ts.map +1 -0
  40. package/dist/esm/soapClient.js +36 -0
  41. package/dist/esm/types.d.ts +122 -0
  42. package/dist/esm/types.d.ts.map +1 -0
  43. package/dist/esm/types.js +1 -0
  44. package/dist/esm/utils.d.ts +43 -0
  45. package/dist/esm/utils.d.ts.map +1 -0
  46. package/dist/esm/utils.js +144 -0
  47. package/package.json +62 -0
@@ -0,0 +1,162 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.toRials = toRials;
4
+ exports.validateAmount = validateAmount;
5
+ exports.getPaymentPageUrl = getPaymentPageUrl;
6
+ exports.isSuccessStatus = isSuccessStatus;
7
+ exports.shouldConfirmPayment = shouldConfirmPayment;
8
+ exports.generateOrderId = generateOrderId;
9
+ exports.isValidUrl = isValidUrl;
10
+ exports.isValidHttpsUrl = isValidHttpsUrl;
11
+ exports.parseCallback = parseCallback;
12
+ exports.normalizeSoapField = normalizeSoapField;
13
+ exports.normalizeSoapNumber = normalizeSoapNumber;
14
+ exports.buildPaymentTokenResult = buildPaymentTokenResult;
15
+ exports.mapMultiplexedAccounts = mapMultiplexedAccounts;
16
+ exports.validateMultiplexedAccounts = validateMultiplexedAccounts;
17
+ exports.validateSaleReportDateRange = validateSaleReportDateRange;
18
+ exports.normalizeBillInfoResult = normalizeBillInfoResult;
19
+ const crypto_1 = require("crypto");
20
+ const constants_js_1 = require("./constants.js");
21
+ const errors_js_1 = require("./errors.js");
22
+ const MAX_SALE_REPORT_RANGE_MS = 30 * 24 * 60 * 60 * 1000;
23
+ /** Converts an amount to Rials for PEC API requests. */
24
+ function toRials(amount, currency = 'toman') {
25
+ validateAmount(amount);
26
+ return currency === 'toman' ? amount * 10 : amount;
27
+ }
28
+ /** Ensures amount is a positive finite number. */
29
+ function validateAmount(amount) {
30
+ if (!Number.isFinite(amount) || amount <= 0) {
31
+ throw new errors_js_1.PecValidationError('amount must be a positive number');
32
+ }
33
+ }
34
+ function getPaymentPageUrl(token) {
35
+ return `${constants_js_1.PAYMENT_PAGE_BASE}${token}`;
36
+ }
37
+ function isSuccessStatus(status) {
38
+ return Number(status) === constants_js_1.PEC_SUCCESS_STATUS;
39
+ }
40
+ /** Returns true when the bank callback indicates a successful payment worth confirming. */
41
+ function shouldConfirmPayment(callback) {
42
+ return callback.status === constants_js_1.PEC_SUCCESS_STATUS && Number(callback.rrn) > 0;
43
+ }
44
+ function generateOrderId() {
45
+ return (0, crypto_1.randomBytes)(20).toString('hex');
46
+ }
47
+ /** Validates callback URLs (HTTP for local dev, HTTPS for production). */
48
+ function isValidUrl(url) {
49
+ try {
50
+ const parsed = new URL(url);
51
+ return ((parsed.protocol === 'https:' || parsed.protocol === 'http:') &&
52
+ parsed.hostname.length > 0);
53
+ }
54
+ catch {
55
+ return false;
56
+ }
57
+ }
58
+ /** @deprecated Use {@link isValidUrl} instead. */
59
+ function isValidHttpsUrl(url) {
60
+ return isValidUrl(url) && url.startsWith('https:');
61
+ }
62
+ function readField(body, keys) {
63
+ for (const key of keys) {
64
+ const value = body[key];
65
+ if (value !== undefined && value !== null && value !== '') {
66
+ return String(value);
67
+ }
68
+ }
69
+ return '';
70
+ }
71
+ function parseCallbackStatus(body) {
72
+ const raw = readField(body, ['status', 'Status']);
73
+ if (raw === '') {
74
+ return NaN;
75
+ }
76
+ return Number(raw);
77
+ }
78
+ /**
79
+ * Parses the bank callback payload (PEC POSTs to your callback URL).
80
+ * Pass `req.body` for POST callbacks; merge `req.query` if your route uses GET.
81
+ */
82
+ function parseCallback(body) {
83
+ return {
84
+ token: readField(body, ['Token', 'token']),
85
+ status: parseCallbackStatus(body),
86
+ orderId: readField(body, ['OrderId', 'orderId']),
87
+ terminalNo: readField(body, ['TerminalNo', 'terminalNo']),
88
+ amount: readField(body, ['Amount', 'amount']),
89
+ rrn: readField(body, ['RRN', 'rrn']),
90
+ };
91
+ }
92
+ function normalizeSoapField(value) {
93
+ if (value === undefined || value === null) {
94
+ return '';
95
+ }
96
+ if (Array.isArray(value)) {
97
+ return normalizeSoapField(value[0]);
98
+ }
99
+ return String(value);
100
+ }
101
+ function normalizeSoapNumber(value) {
102
+ return Number(normalizeSoapField(value));
103
+ }
104
+ function buildPaymentTokenResult(status, token, message) {
105
+ const normalizedStatus = normalizeSoapNumber(status);
106
+ const normalizedToken = normalizeSoapField(token);
107
+ const normalizedMessage = normalizeSoapField(message);
108
+ const result = {
109
+ status: normalizedStatus,
110
+ token: normalizedToken,
111
+ message: normalizedMessage,
112
+ };
113
+ if (isSuccessStatus(normalizedStatus) && normalizedToken.length > 0) {
114
+ return { ...result, paymentUrl: getPaymentPageUrl(normalizedToken) };
115
+ }
116
+ return result;
117
+ }
118
+ function mapMultiplexedAccounts(accounts, currency = 'toman') {
119
+ validateMultiplexedAccounts(accounts);
120
+ return accounts.map((account) => ({
121
+ Amount: toRials(account.amount, currency),
122
+ IBAN: account.iban,
123
+ PayId: account.payId,
124
+ }));
125
+ }
126
+ function validateMultiplexedAccounts(accounts) {
127
+ if (!Array.isArray(accounts) || accounts.length === 0) {
128
+ throw new errors_js_1.PecValidationError('accounts must be a non-empty array');
129
+ }
130
+ for (const account of accounts) {
131
+ validateAmount(account.amount);
132
+ if (!account.iban?.trim()) {
133
+ throw new errors_js_1.PecValidationError('each account must include a valid iban');
134
+ }
135
+ if (!account.payId?.trim()) {
136
+ throw new errors_js_1.PecValidationError('each account must include a valid payId');
137
+ }
138
+ }
139
+ }
140
+ /** Validates sale report date range (max 30 days, end after start). */
141
+ function validateSaleReportDateRange(fromDate, toDate) {
142
+ const from = new Date(fromDate);
143
+ const to = new Date(toDate);
144
+ if (Number.isNaN(from.getTime()) || Number.isNaN(to.getTime())) {
145
+ throw new errors_js_1.PecValidationError('fromDate and toDate must be valid date strings');
146
+ }
147
+ if (to.getTime() < from.getTime()) {
148
+ throw new errors_js_1.PecValidationError('toDate must be on or after fromDate');
149
+ }
150
+ if (to.getTime() - from.getTime() > MAX_SALE_REPORT_RANGE_MS) {
151
+ throw new errors_js_1.PecValidationError('date range must not exceed 30 days');
152
+ }
153
+ }
154
+ function normalizeBillInfoResult(payload) {
155
+ return {
156
+ status: normalizeSoapNumber(payload.Status),
157
+ message: normalizeSoapField(payload.Message),
158
+ amount: normalizeSoapField(payload.Amount),
159
+ billId: normalizeSoapField(payload.BillId),
160
+ payId: normalizeSoapField(payload.PayId),
161
+ };
162
+ }
@@ -0,0 +1,28 @@
1
+ import type { BillInfoResult, ConfirmPaymentInput, ConfirmPaymentResult, GetBillInfoInput, GetSaleReportInput, GetSaleReportResult, PaymentTokenResult, PecClientOptions, RequestBillPaymentInput, RequestGovernmentMultiplexedPaymentInput, RequestGovernmentPaymentInput, RequestMobileTopupInput, RequestMultiplexedPaymentInput, RequestPaymentInput, ReversePaymentInput, ReversePaymentResult } from './types.js';
2
+ export declare class PecClient {
3
+ private readonly loginAccount;
4
+ private readonly defaultCallbackUrl?;
5
+ constructor(options: PecClientOptions);
6
+ /** Starts a standard sale payment and returns a token plus redirect URL. */
7
+ requestPayment(input: RequestPaymentInput): Promise<PaymentTokenResult>;
8
+ /** Starts an online multiplexed sale (تسهیم آنلاین). */
9
+ requestMultiplexedPayment(input: RequestMultiplexedPaymentInput): Promise<PaymentTokenResult>;
10
+ /** Starts a government-ID sale (شناسه حساب دولتی). */
11
+ requestGovernmentPayment(input: RequestGovernmentPaymentInput): Promise<PaymentTokenResult>;
12
+ /** Starts a government sale with multiplexed IBAN accounts. */
13
+ requestGovernmentMultiplexedPayment(input: RequestGovernmentMultiplexedPaymentInput): Promise<PaymentTokenResult>;
14
+ /** Starts a bill payment request. */
15
+ requestBillPayment(input: RequestBillPaymentInput): Promise<PaymentTokenResult>;
16
+ /** Retrieves bill details before payment. */
17
+ getBillInfo(input: GetBillInfoInput): Promise<BillInfoResult>;
18
+ /** Starts a mobile top-up/charge request. */
19
+ requestMobileTopup(input: RequestMobileTopupInput): Promise<PaymentTokenResult>;
20
+ /** Confirms/settles a successful payment using its token. */
21
+ confirmPayment(input: ConfirmPaymentInput): Promise<ConfirmPaymentResult>;
22
+ /** Reverses a payment. Works only within the bank's allowed time window. */
23
+ reversePayment(input: ReversePaymentInput): Promise<ReversePaymentResult>;
24
+ /** Fetches sale transactions from PEC reporting REST API. */
25
+ getSaleReport(input: GetSaleReportInput): Promise<GetSaleReportResult>;
26
+ private resolveCallbackUrl;
27
+ }
28
+ //# sourceMappingURL=PecClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PecClient.d.ts","sourceRoot":"","sources":["../../src/PecClient.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,cAAc,EACd,mBAAmB,EACnB,oBAAoB,EACpB,gBAAgB,EAChB,kBAAkB,EAClB,mBAAmB,EACnB,kBAAkB,EAClB,gBAAgB,EAChB,uBAAuB,EACvB,wCAAwC,EACxC,6BAA6B,EAC7B,uBAAuB,EACvB,8BAA8B,EAC9B,mBAAmB,EACnB,mBAAmB,EACnB,oBAAoB,EACrB,MAAM,YAAY,CAAC;AAapB,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAS;gBAEjC,OAAO,EAAE,gBAAgB;IASrC,4EAA4E;IACtE,cAAc,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAqB7E,wDAAwD;IAClD,yBAAyB,CAC7B,KAAK,EAAE,8BAA8B,GACpC,OAAO,CAAC,kBAAkB,CAAC;IAwB9B,sDAAsD;IAChD,wBAAwB,CAC5B,KAAK,EAAE,6BAA6B,GACnC,OAAO,CAAC,kBAAkB,CAAC;IAqB9B,+DAA+D;IACzD,mCAAmC,CACvC,KAAK,EAAE,wCAAwC,GAC9C,OAAO,CAAC,kBAAkB,CAAC;IAwB9B,qCAAqC;IAC/B,kBAAkB,CAAC,KAAK,EAAE,uBAAuB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAsBrF,6CAA6C;IACvC,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,cAAc,CAAC;IAgBnE,6CAA6C;IACvC,kBAAkB,CAAC,KAAK,EAAE,uBAAuB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAwBrF,6DAA6D;IACvD,cAAc,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAuB/E,4EAA4E;IACtE,cAAc,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAsB/E,6DAA6D;IACvD,aAAa,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAiC5E,OAAO,CAAC,kBAAkB;CAa3B"}
@@ -0,0 +1,211 @@
1
+ import axios from 'axios';
2
+ import { REPORT_API_URL, WSDL } from './constants.js';
3
+ import { PecTransportError, PecValidationError } from './errors.js';
4
+ import { callSoapMethod } from './soapClient.js';
5
+ import { buildPaymentTokenResult, isValidUrl, mapMultiplexedAccounts, normalizeBillInfoResult, normalizeSoapField, normalizeSoapNumber, toRials, validateSaleReportDateRange, } from './utils.js';
6
+ export class PecClient {
7
+ constructor(options) {
8
+ if (!options?.loginAccount?.trim()) {
9
+ throw new PecValidationError('loginAccount is required');
10
+ }
11
+ this.loginAccount = options.loginAccount;
12
+ this.defaultCallbackUrl = options.callbackUrl;
13
+ }
14
+ /** Starts a standard sale payment and returns a token plus redirect URL. */
15
+ async requestPayment(input) {
16
+ const callbackUrl = this.resolveCallbackUrl(input.callbackUrl);
17
+ const currency = input.currency ?? 'toman';
18
+ const result = await callSoapMethod(WSDL.SALE, 'SalePaymentRequestAsync', {
19
+ requestData: {
20
+ LoginAccount: this.loginAccount,
21
+ Amount: toRials(input.amount, currency),
22
+ OrderId: input.orderId,
23
+ CallBackUrl: callbackUrl,
24
+ AdditionalData: input.additionalData ?? '',
25
+ Originator: input.originator ?? '',
26
+ },
27
+ });
28
+ const payload = result?.SalePaymentRequestResult ?? {};
29
+ return buildPaymentTokenResult(payload.Status, payload.Token, payload.Message);
30
+ }
31
+ /** Starts an online multiplexed sale (تسهیم آنلاین). */
32
+ async requestMultiplexedPayment(input) {
33
+ const callbackUrl = this.resolveCallbackUrl(input.callbackUrl);
34
+ const currency = input.currency ?? 'toman';
35
+ const result = await callSoapMethod(WSDL.MULTIPLEXED_SALE, 'MultiplexedSaleWithIBANPaymentRequestAsync', {
36
+ requestData: {
37
+ LoginAccount: this.loginAccount,
38
+ Amount: toRials(input.amount, currency),
39
+ OrderId: input.orderId,
40
+ CallBackUrl: callbackUrl,
41
+ AdditionalData: '',
42
+ Originator: input.originator ?? '',
43
+ MultiplexedAccounts: {
44
+ MultiplexedAccount: mapMultiplexedAccounts(input.accounts, currency),
45
+ },
46
+ },
47
+ });
48
+ const payload = result?.MultiplexedSaleWithIBANPaymentRequestResult ?? {};
49
+ return buildPaymentTokenResult(payload.Status, payload.Token, payload.Message);
50
+ }
51
+ /** Starts a government-ID sale (شناسه حساب دولتی). */
52
+ async requestGovernmentPayment(input) {
53
+ const callbackUrl = this.resolveCallbackUrl(input.callbackUrl);
54
+ const currency = input.currency ?? 'toman';
55
+ const result = await callSoapMethod(WSDL.GOVERNMENT_SALE, 'SalePaymentRequestAsync', {
56
+ requestData: {
57
+ LoginAccount: this.loginAccount,
58
+ Amount: toRials(input.amount, currency),
59
+ OrderId: input.orderId,
60
+ CallBackUrl: callbackUrl,
61
+ AdditionalData: `GOVId=${input.govId}`,
62
+ Originator: input.originator ?? '',
63
+ },
64
+ });
65
+ const payload = result?.SalePaymentRequestResult ?? {};
66
+ return buildPaymentTokenResult(payload.Status, payload.Token, payload.Message);
67
+ }
68
+ /** Starts a government sale with multiplexed IBAN accounts. */
69
+ async requestGovernmentMultiplexedPayment(input) {
70
+ const callbackUrl = this.resolveCallbackUrl(input.callbackUrl);
71
+ const currency = input.currency ?? 'toman';
72
+ const result = await callSoapMethod(WSDL.GOVERNMENT_SALE, 'GovSaleWithMultiIbanPaymentRequestSW2Async', {
73
+ requestData: {
74
+ LoginAccount: this.loginAccount,
75
+ Amount: toRials(input.amount, currency),
76
+ OrderId: input.orderId,
77
+ CallBackUrl: callbackUrl,
78
+ AdditionalData: `GOVId=${input.govId}`,
79
+ Originator: input.originator ?? '',
80
+ MultiplexedAccounts: {
81
+ MultiplexedAccount: mapMultiplexedAccounts(input.accounts, currency),
82
+ },
83
+ },
84
+ });
85
+ const payload = result?.GovSaleWithMultiIbanPaymentRequestSW2Result ?? {};
86
+ return buildPaymentTokenResult(payload.Status, payload.Token, payload.Message);
87
+ }
88
+ /** Starts a bill payment request. */
89
+ async requestBillPayment(input) {
90
+ const callbackUrl = this.resolveCallbackUrl(input.callbackUrl);
91
+ const result = await callSoapMethod(WSDL.BILL, 'BillPaymentRequestAsync', {
92
+ requestData: {
93
+ LoginAccount: this.loginAccount,
94
+ BillId: input.billId,
95
+ PayId: input.payId,
96
+ OrderId: input.orderId,
97
+ Amount: '',
98
+ CallBackUrl: callbackUrl,
99
+ AdditionalData: input.additionalData ?? '',
100
+ Originator: input.originator ?? '',
101
+ },
102
+ });
103
+ const payload = result?.BillPaymentRequestResult ?? {};
104
+ return buildPaymentTokenResult(payload.Status, payload.Token, payload.Message);
105
+ }
106
+ /** Retrieves bill details before payment. */
107
+ async getBillInfo(input) {
108
+ if (!input.billId?.trim() || !input.payId?.trim()) {
109
+ throw new PecValidationError('billId and payId are required');
110
+ }
111
+ const result = await callSoapMethod(WSDL.BILL, 'GetBillInfoAsync', {
112
+ billId: input.billId,
113
+ payId: input.payId,
114
+ });
115
+ const payload = result?.GetBillInfoResult ?? {};
116
+ return normalizeBillInfoResult(payload);
117
+ }
118
+ /** Starts a mobile top-up/charge request. */
119
+ async requestMobileTopup(input) {
120
+ const callbackUrl = this.resolveCallbackUrl(input.callbackUrl);
121
+ const currency = input.currency ?? 'toman';
122
+ const result = await callSoapMethod(WSDL.MOBILE_TOPUP, 'TopupChargeRequestAsync', {
123
+ requestData: {
124
+ LoginAccount: this.loginAccount,
125
+ OrderId: input.orderId,
126
+ ChargeMobileNumber: input.chargeMobileNumber,
127
+ RequesterMobileNumber: input.requesterMobileNumber,
128
+ TopupType: input.topupType,
129
+ Amount: toRials(input.amount, currency),
130
+ CallBackUrl: callbackUrl,
131
+ AdditionalData: input.additionalData ?? '',
132
+ Originator: input.originator ?? '',
133
+ },
134
+ });
135
+ const payload = result?.TopupChargeRequestResult ?? {};
136
+ return buildPaymentTokenResult(payload.Status, payload.Token, payload.Message);
137
+ }
138
+ /** Confirms/settles a successful payment using its token. */
139
+ async confirmPayment(input) {
140
+ if (input.token === undefined || input.token === null || input.token === '') {
141
+ throw new PecValidationError('token is required');
142
+ }
143
+ const result = await callSoapMethod(WSDL.CONFIRM, 'ConfirmPaymentAsync', {
144
+ requestData: {
145
+ LoginAccount: this.loginAccount,
146
+ Token: input.token,
147
+ },
148
+ });
149
+ const payload = result?.ConfirmPaymentResult ?? {};
150
+ return {
151
+ status: normalizeSoapNumber(payload.Status),
152
+ token: normalizeSoapField(payload.Token),
153
+ cardNumberMasked: normalizeSoapField(payload.CardNumberMasked),
154
+ rrn: normalizeSoapField(payload.RRN),
155
+ };
156
+ }
157
+ /** Reverses a payment. Works only within the bank's allowed time window. */
158
+ async reversePayment(input) {
159
+ if (input.token === undefined || input.token === null || input.token === '') {
160
+ throw new PecValidationError('token is required');
161
+ }
162
+ const result = await callSoapMethod(WSDL.REVERSAL, 'ReversalRequestAsync', {
163
+ requestData: {
164
+ LoginAccount: this.loginAccount,
165
+ Token: input.token,
166
+ },
167
+ });
168
+ const payload = result?.ReversalRequestResult ?? {};
169
+ return {
170
+ status: normalizeSoapNumber(payload.Status),
171
+ token: normalizeSoapField(payload.Token),
172
+ message: normalizeSoapField(payload.Message),
173
+ };
174
+ }
175
+ /** Fetches sale transactions from PEC reporting REST API. */
176
+ async getSaleReport(input) {
177
+ if (!input.username?.trim() || !input.password?.trim()) {
178
+ throw new PecValidationError('username and password are required');
179
+ }
180
+ validateSaleReportDateRange(input.fromDate, input.toDate);
181
+ const authToken = Buffer.from(`${input.username}|${input.password}`).toString('base64');
182
+ try {
183
+ const response = await axios.post(REPORT_API_URL, {
184
+ FromDate: input.fromDate,
185
+ ToDate: input.toDate,
186
+ RRN: input.rrn ?? '',
187
+ OrderId: input.orderId ?? '',
188
+ Token: input.token ?? '',
189
+ }, {
190
+ headers: {
191
+ 'Content-Type': 'application/json',
192
+ Authorization: `Basic ${authToken}`,
193
+ },
194
+ });
195
+ return response.data;
196
+ }
197
+ catch (error) {
198
+ throw new PecTransportError('Failed to fetch sale report', error);
199
+ }
200
+ }
201
+ resolveCallbackUrl(callbackUrl) {
202
+ const resolved = callbackUrl ?? this.defaultCallbackUrl;
203
+ if (!resolved) {
204
+ throw new PecValidationError('callbackUrl is required');
205
+ }
206
+ if (!isValidUrl(resolved)) {
207
+ throw new PecValidationError('callbackUrl must be a valid HTTP or HTTPS URL');
208
+ }
209
+ return resolved;
210
+ }
211
+ }
@@ -0,0 +1,13 @@
1
+ export declare const WSDL: {
2
+ readonly SALE: "https://pec.shaparak.ir/NewIPGServices/Sale/SaleService.asmx?WSDL";
3
+ readonly CONFIRM: "https://pec.shaparak.ir/NewIPGServices/Confirm/ConfirmService.asmx?WSDL";
4
+ readonly REVERSAL: "https://pec.shaparak.ir/NewIPGServices/Reverse/ReversalService.asmx?WSDL";
5
+ readonly MULTIPLEXED_SALE: "https://pec.shaparak.ir/NewIPGServices/MultiplexedSale/OnlineMultiplexedSalePaymentService.asmx?WSDL";
6
+ readonly GOVERNMENT_SALE: "https://pec.shaparak.ir/NewIPGServices/Sale/GovermentIdSaleServiceSW2.asmx?WSDL";
7
+ readonly BILL: "https://pec.shaparak.ir/NewIPGServices/Bill/BillService.asmx?WSDL";
8
+ readonly MOBILE_TOPUP: "https://pec.shaparak.ir/NewIPGServices/SimCharge/TopupChargeService.asmx?WSDL";
9
+ };
10
+ export declare const PAYMENT_PAGE_BASE = "https://pec.shaparak.ir/NewIPG/?Token=";
11
+ export declare const REPORT_API_URL = "https://pgwservices.pec.ir/api/PGWReport/GetSaleReport";
12
+ export declare const PEC_SUCCESS_STATUS = 0;
13
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,IAAI;;;;;;;;CAUP,CAAC;AAEX,eAAO,MAAM,iBAAiB,2CAA2C,CAAC;AAE1E,eAAO,MAAM,cAAc,2DAA2D,CAAC;AAEvF,eAAO,MAAM,kBAAkB,IAAI,CAAC"}
@@ -0,0 +1,12 @@
1
+ export const WSDL = {
2
+ SALE: 'https://pec.shaparak.ir/NewIPGServices/Sale/SaleService.asmx?WSDL',
3
+ CONFIRM: 'https://pec.shaparak.ir/NewIPGServices/Confirm/ConfirmService.asmx?WSDL',
4
+ REVERSAL: 'https://pec.shaparak.ir/NewIPGServices/Reverse/ReversalService.asmx?WSDL',
5
+ MULTIPLEXED_SALE: 'https://pec.shaparak.ir/NewIPGServices/MultiplexedSale/OnlineMultiplexedSalePaymentService.asmx?WSDL',
6
+ GOVERNMENT_SALE: 'https://pec.shaparak.ir/NewIPGServices/Sale/GovermentIdSaleServiceSW2.asmx?WSDL',
7
+ BILL: 'https://pec.shaparak.ir/NewIPGServices/Bill/BillService.asmx?WSDL',
8
+ MOBILE_TOPUP: 'https://pec.shaparak.ir/NewIPGServices/SimCharge/TopupChargeService.asmx?WSDL',
9
+ };
10
+ export const PAYMENT_PAGE_BASE = 'https://pec.shaparak.ir/NewIPG/?Token=';
11
+ export const REPORT_API_URL = 'https://pgwservices.pec.ir/api/PGWReport/GetSaleReport';
12
+ export const PEC_SUCCESS_STATUS = 0;
@@ -0,0 +1,14 @@
1
+ export declare class PecError extends Error {
2
+ readonly status: number;
3
+ readonly pecMessage?: string;
4
+ readonly cause?: unknown;
5
+ constructor(message: string, status: number, pecMessage?: string, cause?: unknown);
6
+ }
7
+ export declare class PecValidationError extends Error {
8
+ constructor(message: string);
9
+ }
10
+ export declare class PecTransportError extends Error {
11
+ readonly cause?: unknown;
12
+ constructor(message: string, cause?: unknown);
13
+ }
14
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,QAAS,SAAQ,KAAK;IACjC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;gBAEb,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO;CAOlF;AAED,qBAAa,kBAAmB,SAAQ,KAAK;gBAC/B,OAAO,EAAE,MAAM;CAI5B;AAED,qBAAa,iBAAkB,SAAQ,KAAK;IAC1C,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;gBAEb,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO;CAK7C"}
@@ -0,0 +1,22 @@
1
+ export class PecError extends Error {
2
+ constructor(message, status, pecMessage, cause) {
3
+ super(message);
4
+ this.name = 'PecError';
5
+ this.status = status;
6
+ this.pecMessage = pecMessage;
7
+ this.cause = cause;
8
+ }
9
+ }
10
+ export class PecValidationError extends Error {
11
+ constructor(message) {
12
+ super(message);
13
+ this.name = 'PecValidationError';
14
+ }
15
+ }
16
+ export class PecTransportError extends Error {
17
+ constructor(message, cause) {
18
+ super(message);
19
+ this.name = 'PecTransportError';
20
+ this.cause = cause;
21
+ }
22
+ }
@@ -0,0 +1,6 @@
1
+ export { PecClient } from './PecClient.js';
2
+ export { PecError, PecTransportError, PecValidationError } from './errors.js';
3
+ export { PAYMENT_PAGE_BASE, PEC_SUCCESS_STATUS, REPORT_API_URL, WSDL } from './constants.js';
4
+ export { generateOrderId, getPaymentPageUrl, isSuccessStatus, isValidHttpsUrl, isValidUrl, mapMultiplexedAccounts, normalizeBillInfoResult, normalizeSoapField, normalizeSoapNumber, parseCallback, shouldConfirmPayment, toRials, validateAmount, validateMultiplexedAccounts, validateSaleReportDateRange, } from './utils.js';
5
+ export type { BillInfoResult, CallbackPayload, ConfirmPaymentInput, ConfirmPaymentResult, Currency, GetBillInfoInput, GetSaleReportInput, GetSaleReportResult, MultiplexedAccount, OrderId, PaymentTokenResult, PecClientOptions, RequestBillPaymentInput, RequestGovernmentMultiplexedPaymentInput, RequestGovernmentPaymentInput, RequestMobileTopupInput, RequestMultiplexedPaymentInput, RequestPaymentInput, ReversePaymentInput, ReversePaymentResult, } from './types.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAC9E,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAC7F,OAAO,EACL,eAAe,EACf,iBAAiB,EACjB,eAAe,EACf,eAAe,EACf,UAAU,EACV,sBAAsB,EACtB,uBAAuB,EACvB,kBAAkB,EAClB,mBAAmB,EACnB,aAAa,EACb,oBAAoB,EACpB,OAAO,EACP,cAAc,EACd,2BAA2B,EAC3B,2BAA2B,GAC5B,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,cAAc,EACd,eAAe,EACf,mBAAmB,EACnB,oBAAoB,EACpB,QAAQ,EACR,gBAAgB,EAChB,kBAAkB,EAClB,mBAAmB,EACnB,kBAAkB,EAClB,OAAO,EACP,kBAAkB,EAClB,gBAAgB,EAChB,uBAAuB,EACvB,wCAAwC,EACxC,6BAA6B,EAC7B,uBAAuB,EACvB,8BAA8B,EAC9B,mBAAmB,EACnB,mBAAmB,EACnB,oBAAoB,GACrB,MAAM,YAAY,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { PecClient } from './PecClient.js';
2
+ export { PecError, PecTransportError, PecValidationError } from './errors.js';
3
+ export { PAYMENT_PAGE_BASE, PEC_SUCCESS_STATUS, REPORT_API_URL, WSDL } from './constants.js';
4
+ export { generateOrderId, getPaymentPageUrl, isSuccessStatus, isValidHttpsUrl, isValidUrl, mapMultiplexedAccounts, normalizeBillInfoResult, normalizeSoapField, normalizeSoapNumber, parseCallback, shouldConfirmPayment, toRials, validateAmount, validateMultiplexedAccounts, validateSaleReportDateRange, } from './utils.js';
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "module"
3
+ }
@@ -0,0 +1,6 @@
1
+ import soap from 'soap';
2
+ export declare function getSoapClient(wsdlUrl: string): Promise<soap.Client>;
3
+ export declare function callSoapMethod<T>(wsdlUrl: string, methodName: string, args: Record<string, unknown>): Promise<T>;
4
+ /** Clears cached SOAP clients (useful in tests). */
5
+ export declare function clearSoapClientCache(): void;
6
+ //# sourceMappingURL=soapClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"soapClient.d.ts","sourceRoot":"","sources":["../../src/soapClient.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AAKxB,wBAAsB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAWzE;AAED,wBAAsB,cAAc,CAAC,CAAC,EACpC,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,OAAO,CAAC,CAAC,CAAC,CAqBZ;AAED,oDAAoD;AACpD,wBAAgB,oBAAoB,IAAI,IAAI,CAE3C"}
@@ -0,0 +1,36 @@
1
+ import soap from 'soap';
2
+ import { PecTransportError } from './errors.js';
3
+ const clientCache = new Map();
4
+ export async function getSoapClient(wsdlUrl) {
5
+ let cached = clientCache.get(wsdlUrl);
6
+ if (!cached) {
7
+ cached = soap.createClientAsync(wsdlUrl).catch((error) => {
8
+ clientCache.delete(wsdlUrl);
9
+ throw new PecTransportError(`Failed to create SOAP client for ${wsdlUrl}`, error);
10
+ });
11
+ clientCache.set(wsdlUrl, cached);
12
+ }
13
+ return cached;
14
+ }
15
+ export async function callSoapMethod(wsdlUrl, methodName, args) {
16
+ try {
17
+ const client = await getSoapClient(wsdlUrl);
18
+ const method = client[methodName];
19
+ if (typeof method !== 'function') {
20
+ throw new PecTransportError(`SOAP method "${methodName}" was not found in ${wsdlUrl}`);
21
+ }
22
+ const asyncMethod = method;
23
+ const [result] = await asyncMethod.call(client, args);
24
+ return result;
25
+ }
26
+ catch (error) {
27
+ if (error instanceof PecTransportError) {
28
+ throw error;
29
+ }
30
+ throw new PecTransportError(`SOAP call "${methodName}" failed`, error);
31
+ }
32
+ }
33
+ /** Clears cached SOAP clients (useful in tests). */
34
+ export function clearSoapClientCache() {
35
+ clientCache.clear();
36
+ }