@ayushsolanki29/payment-gateway 0.0.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.
@@ -0,0 +1,160 @@
1
+ <?php
2
+ header('Content-Type: application/json');
3
+ session_start();
4
+
5
+ // Handle different API actions
6
+ $action = $_GET['action'] ?? '';
7
+ $input = json_decode(file_get_contents('php://input'), true) ?? [];
8
+ $response = ['success' => false, 'message' => 'Invalid action'];
9
+
10
+ // Merchant configuration
11
+ const MERCHANT_UPI_ID = 'merchant@upi';
12
+ const MERCHANT_NAME = 'Example Merchant';
13
+ const MIN_AMOUNT = 100; // ₹1.00 (100 paise)
14
+
15
+ try {
16
+ switch ($action) {
17
+ case 'init_transaction':
18
+ $response = handleInitTransaction($input);
19
+ break;
20
+
21
+ case 'verify_contact':
22
+ $response = handleVerifyContact($input);
23
+ break;
24
+
25
+ case 'process_payment':
26
+ $response = handleProcessPayment($input);
27
+ break;
28
+
29
+ case 'check_status':
30
+ $response = handleCheckStatus($input);
31
+ break;
32
+
33
+ default:
34
+ $response = ['success' => false, 'message' => 'Invalid action specified'];
35
+ }
36
+ } catch (Exception $e) {
37
+ $response = ['success' => false, 'message' => $e->getMessage()];
38
+ }
39
+
40
+ echo json_encode($response);
41
+ exit;
42
+
43
+ // API Handlers
44
+ function handleInitTransaction($data) {
45
+ $amount = intval($data['amount'] ?? 0);
46
+
47
+ // Validate amount (must be at least ₹1)
48
+ if ($amount < MIN_AMOUNT) {
49
+ return [
50
+ 'success' => false,
51
+ 'message' => 'Amount must be at least ₹1.00 (100 paise)'
52
+ ];
53
+ }
54
+
55
+ // Generate transaction ID
56
+ $transactionId = 'TXN' . uniqid() . strtoupper(substr(md5(microtime()), 0, 6));
57
+
58
+ // Store transaction in session (replace with database in production)
59
+ $_SESSION['transactions'][$transactionId] = [
60
+ 'amount' => $amount,
61
+ 'status' => 'initiated',
62
+ 'created_at' => time()
63
+ ];
64
+
65
+ return ['success' => true, 'transactionId' => $transactionId];
66
+ }
67
+
68
+ function handleVerifyContact($data) {
69
+ $upiId = trim($data['upiId'] ?? '');
70
+ $phone = trim($data['phone'] ?? '');
71
+ $transactionId = $data['transactionId'] ?? '';
72
+
73
+ // Validate required fields
74
+ if (empty($upiId) || empty($phone) || empty($transactionId)) {
75
+ return ['success' => false, 'message' => 'Missing required fields'];
76
+ }
77
+
78
+ // Validate UPI ID format
79
+ if (!preg_match('/^[\w.-]+@[\w.-]+$/', $upiId)) {
80
+ return ['success' => false, 'message' => 'Invalid UPI ID format'];
81
+ }
82
+
83
+ // Validate phone number
84
+ if (!preg_match('/^[0-9]{10}$/', $phone)) {
85
+ return ['success' => false, 'message' => 'Phone number must be 10 digits'];
86
+ }
87
+
88
+ // Update transaction in session
89
+ if (isset($_SESSION['transactions'][$transactionId])) {
90
+ $_SESSION['transactions'][$transactionId]['upiId'] = $upiId;
91
+ $_SESSION['transactions'][$transactionId]['phone'] = $phone;
92
+ $_SESSION['transactions'][$transactionId]['status'] = 'verified';
93
+ }
94
+
95
+ // Set cookies for future use
96
+ setcookie('upi_id', $upiId, time() + (86400 * 30), "/");
97
+ setcookie('phone_number', $phone, time() + (86400 * 30), "/");
98
+
99
+ return ['success' => true, 'upiId' => $upiId, 'phone' => $phone];
100
+ }
101
+
102
+ function handleProcessPayment($data) {
103
+ $transactionId = $data['transactionId'] ?? '';
104
+ $amount = intval($data['amount'] ?? 0);
105
+ $upiId = $data['upiId'] ?? '';
106
+ $phone = $data['phone'] ?? '';
107
+
108
+ if (empty($transactionId) || !isset($_SESSION['transactions'][$transactionId])) {
109
+ return ['success' => false, 'message' => 'Invalid transaction'];
110
+ }
111
+
112
+ // Generate UPI payment URL
113
+ $paymentUrl = "upi://pay?pa=" . urlencode(MERCHANT_UPI_ID) .
114
+ "&pn=" . urlencode(MERCHANT_NAME) .
115
+ "&am=" . $amount .
116
+ "&tn=" . $transactionId .
117
+ "&cu=INR";
118
+
119
+ // Update transaction status
120
+ $_SESSION['transactions'][$transactionId]['status'] = 'processing';
121
+ $_SESSION['transactions'][$transactionId]['payment_url'] = $paymentUrl;
122
+
123
+ return [
124
+ 'success' => true,
125
+ 'upiUrl' => $paymentUrl,
126
+ 'merchantUpiId' => MERCHANT_UPI_ID,
127
+ 'redirectUrl' => 'thank-you.html'
128
+ ];
129
+ }
130
+
131
+ function handleCheckStatus($data) {
132
+ $transactionId = $data['transactionId'] ?? '';
133
+
134
+ if (empty($transactionId) || !isset($_SESSION['transactions'][$transactionId])) {
135
+ return ['success' => false, 'message' => 'Invalid transaction'];
136
+ }
137
+
138
+ // Simulate payment processing (2-5 seconds)
139
+ $txn = $_SESSION['transactions'][$transactionId];
140
+ $elapsed = time() - $txn['created_at'];
141
+
142
+ if ($elapsed < 2) {
143
+ return ['success' => true, 'paymentSuccess' => false];
144
+ }
145
+
146
+ // Simulate 70% success rate
147
+ $paymentSuccess = (rand(1, 10) <= 7);
148
+
149
+ if ($paymentSuccess) {
150
+ $_SESSION['transactions'][$transactionId]['status'] = 'completed';
151
+ return [
152
+ 'success' => true,
153
+ 'paymentSuccess' => true,
154
+ 'redirectUrl' => 'thank-you.html'
155
+ ];
156
+ } else {
157
+ $_SESSION['transactions'][$transactionId]['status'] = 'failed';
158
+ return ['success' => true, 'paymentSuccess' => false];
159
+ }
160
+ }
@@ -0,0 +1,257 @@
1
+ class UPIPaymentGateway {
2
+ constructor(options = {}) {
3
+ this.config = {
4
+ paymentTimeout: 180,
5
+ apiBase: "payment-api.php",
6
+ defaults: {
7
+ amount: 1000, // ₹10.00 (1000 paise)
8
+ currency: "INR",
9
+ merchantName: "Example Merchant",
10
+ merchantUpiId: "merchant@upi",
11
+ themeColor: "#005bf2",
12
+ },
13
+ };
14
+
15
+ this.options = $.extend({}, this.config.defaults, options);
16
+ this.transactionId = null;
17
+ this.timer = null;
18
+
19
+ this.cacheElements();
20
+ this.bindEvents();
21
+ }
22
+ cacheElements() {
23
+ this.$els = {
24
+ modal: $("#paymentModal"),
25
+ trigger: $("#paymentTrigger"),
26
+ closeBtn: $(".close-modal"),
27
+ amount: $("#paymentAmount"),
28
+ upiInput: $("#upiId"),
29
+ phoneInput: $("#phoneNumber"),
30
+ proceedBtn: $("#proceedToPay"),
31
+ qrCode: $("#upiQrCode"),
32
+ merchantUpi: $("#merchantUpiId"),
33
+ amountFinal: $("#displayAmount"),
34
+ timer: $("#paymentTimer"),
35
+ upiBtn: $("#openUpiApp"),
36
+ messageBox: $("#messageBox"),
37
+ messageText: $("#messageText"),
38
+ contactStep: $("#contactStep"),
39
+ paymentStep: $("#paymentStep"),
40
+ };
41
+ }
42
+
43
+ bindEvents() {
44
+ this.$els.trigger.on("click", () => this.openModal());
45
+ this.$els.closeBtn.on("click", () => this.closeModal());
46
+ this.$els.proceedBtn.on("click", () => this.verifyAndProceed());
47
+ this.$els.upiBtn.on("click", () => this.openUpiApp());
48
+
49
+ // Tab switching
50
+ $(".option-tab").on("click", (e) => {
51
+ const tab = $(e.currentTarget);
52
+ $(".option-tab, .option-content").removeClass("active");
53
+ tab.addClass("active");
54
+ $(`#${tab.data("tab")}`).addClass("active");
55
+ });
56
+
57
+ // Copy UPI ID
58
+ $(".copy-btn").on("click", (e) => {
59
+ const target = $(e.currentTarget).data("target");
60
+ const text = $(`#${target}`).text();
61
+ navigator.clipboard.writeText(text);
62
+ this.showMessage("UPI ID copied to clipboard!", "success");
63
+ });
64
+ }
65
+
66
+ openModal() {
67
+ this.$els.amount.text(`₹${this.options.amount}`);
68
+ this.$els.modal.css("display", "flex");
69
+ $("body").css("overflow", "hidden");
70
+ }
71
+
72
+ closeModal() {
73
+ this.$els.modal.hide();
74
+ $("body").css("overflow", "");
75
+ this.resetFlow();
76
+ clearInterval(this.timer);
77
+ }
78
+
79
+ resetFlow() {
80
+ this.$els.contactStep.addClass("active");
81
+ this.$els.paymentStep.removeClass("active");
82
+ this.$els.proceedBtn
83
+ .prop("disabled", false)
84
+ .html(
85
+ '<span>Proceed to Payment</span><i class="fas fa-arrow-right"></i>'
86
+ );
87
+ }
88
+
89
+ async verifyAndProceed() {
90
+ const upiId = this.$els.upiInput.val().trim();
91
+ const phone = this.$els.phoneInput.val().trim();
92
+
93
+ if (!this.validateInputs(upiId, phone)) return;
94
+
95
+ this.loading(true);
96
+
97
+ try {
98
+ // 1. Initialize transaction
99
+ const init = await this.apiCall("init_transaction", {
100
+ amount: this.options.amount,
101
+ });
102
+
103
+ if (!init.success) throw new Error(init.message || "Transaction failed");
104
+ this.transactionId = init.transactionId;
105
+
106
+ // 2. Verify contact details
107
+ const verify = await this.apiCall("verify_contact", {
108
+ upiId,
109
+ phone,
110
+ transactionId: this.transactionId,
111
+ });
112
+
113
+ if (!verify.success)
114
+ throw new Error(verify.message || "Verification failed");
115
+
116
+ // 3. Process payment
117
+ const payment = await this.apiCall("process_payment", {
118
+ transactionId: this.transactionId,
119
+ amount: this.options.amount,
120
+ upiId,
121
+ phone,
122
+ });
123
+
124
+ if (!payment.success)
125
+ throw new Error(payment.message || "Payment failed");
126
+
127
+ this.showPaymentStep(payment.upiUrl, payment.merchantUpiId);
128
+ } catch (err) {
129
+ this.showMessage(err.message, "error");
130
+ this.loading(false);
131
+ }
132
+ }
133
+
134
+ validateInputs(upiId, phone) {
135
+ if (!upiId || !phone) {
136
+ this.showMessage("Please enter both UPI ID and Phone Number", "error");
137
+ return false;
138
+ }
139
+ if (!/^[\w.-]+@[\w.-]+$/.test(upiId)) {
140
+ this.showMessage("Invalid UPI ID format", "error");
141
+ return false;
142
+ }
143
+ if (!/^[0-9]{10}$/.test(phone)) {
144
+ this.showMessage("Phone number must be 10 digits", "error");
145
+ return false;
146
+ }
147
+ return true;
148
+ }
149
+
150
+ showPaymentStep(upiUrl, merchantUpiId) {
151
+ this.$els.contactStep.removeClass("active");
152
+ this.$els.paymentStep.addClass("active");
153
+
154
+ this.$els.qrCode.attr(
155
+ "src",
156
+ `https://api.qrserver.com/v1/create-qr-code/?size=150x150&data=${encodeURIComponent(
157
+ upiUrl
158
+ )}`
159
+ );
160
+ this.$els.merchantUpi.text(merchantUpiId || this.options.merchantUpiId);
161
+ this.$els.amountFinal.text(`₹${this.options.amount}`);
162
+
163
+ this.startTimer();
164
+ }
165
+
166
+ startTimer() {
167
+ let seconds = this.config.paymentTimeout;
168
+ this.$els.timer.text(seconds);
169
+
170
+ this.timer = setInterval(() => {
171
+ seconds--;
172
+ this.$els.timer.text(seconds);
173
+ if (seconds <= 0) {
174
+ clearInterval(this.timer);
175
+ this.checkStatus();
176
+ }
177
+ }, 1000);
178
+ }
179
+
180
+ async checkStatus() {
181
+ try {
182
+ const res = await this.apiCall("check_status", {
183
+ transactionId: this.transactionId,
184
+ });
185
+
186
+ if (res.paymentSuccess) {
187
+ this.showMessage("Payment successful!", "success");
188
+ setTimeout(() => {
189
+ window.location.href = res.redirectUrl || "thank-you.html";
190
+ }, 2000);
191
+ } else {
192
+ this.showMessage("Payment not completed. Please try again.", "error");
193
+ this.resetFlow();
194
+ }
195
+ } catch (err) {
196
+ this.showMessage("Error verifying payment", "error");
197
+ this.resetFlow();
198
+ }
199
+ }
200
+
201
+ openUpiApp() {
202
+ const url = `upi://pay?pa=${this.options.merchantUpiId}&pn=${this.options.merchantName}&am=${this.options.amount}&tn=${this.transactionId}&cu=INR`;
203
+ window.location.href = url;
204
+ setTimeout(() => {
205
+ this.showMessage(
206
+ "If UPI app didn't open, please copy the UPI ID",
207
+ "warning"
208
+ );
209
+ }, 1000);
210
+ }
211
+
212
+ loading(show) {
213
+ this.$els.proceedBtn
214
+ .prop("disabled", show)
215
+ .html(
216
+ show
217
+ ? '<i class="fas fa-spinner fa-spin"></i> Processing...'
218
+ : '<span>Proceed to Payment</span><i class="fas fa-arrow-right"></i>'
219
+ );
220
+ }
221
+
222
+ showMessage(msg, type) {
223
+ this.$els.messageText.text(msg);
224
+ this.$els.messageBox
225
+ .removeClass("error success show")
226
+ .addClass(`${type} show`);
227
+
228
+ setTimeout(() => {
229
+ this.$els.messageBox.removeClass("show");
230
+ }, 5000);
231
+ }
232
+
233
+ async apiCall(action, data) {
234
+ try {
235
+ const res = await $.ajax({
236
+ url: `${this.config.apiBase}?action=${action}`,
237
+ method: "POST",
238
+ dataType: "json",
239
+ data: JSON.stringify(data),
240
+ contentType: "application/json",
241
+ });
242
+ return res;
243
+ } catch (err) {
244
+ console.error("API Error:", err);
245
+ throw new Error("Network error. Please try again.");
246
+ }
247
+ }
248
+ }
249
+
250
+ // Initialize when DOM is ready
251
+ $(document).ready(() => {
252
+ const paymentGateway = new UPIPaymentGateway({
253
+ amount: 1000, // ₹10.00 (1000 paise)
254
+ merchantName: "Example Merchant",
255
+ merchantUpiId: "merchant@upi",
256
+ });
257
+ });