PluginProbe
Yatra – Travel Booking & Tour Operator Software / trunk
Yatra – Travel Booking & Tour Operator Software vtrunk
3.0.14 3.0.14.1 3.0.14.2 3.0.12 3.0.13 3.0.11 3.0.10 3.0.9 3.0.8 3.0.7 3.0.6 3.0.5 3.0.5.1 3.0.4 3.0.3 3.0.2.9 3.0.2.7 3.0.2.8 3.0.2.6 trunk 1.0.0 2.0.0 2.0.1 2.0.10 2.0.11 All 82 releases
yatra / app / Controllers / PaymentController.php

PaymentController.php in Yatra – Travel Booking & Tour Operator Software trunk, at app/Controllers/PaymentController.php

239 lines 7.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 declare(strict_types=1);
4
5 namespace Yatra\Controllers;
6
7 use WP_REST_Request;
8 use WP_REST_Response;
9 use WP_Error;
10 use Yatra\Services\PaymentService;
11
12 /**
13 * Payment REST API Controller
14 *
15 * Handles payment record operations (listing, viewing, managing payments)
16 */
17 class PaymentController extends BaseController
18 {
19 /**
20 * REST API namespace
21 */
22 protected string $namespace = 'yatra/v1';
23
24 /**
25 * Payment service instance
26 */
27 private PaymentService $paymentService;
28
29 /**
30 * Constructor - Initialize services
31 */
32 public function __construct()
33 {
34 $this->paymentService = new PaymentService();
35 }
36
37 /**
38 * Register REST API routes
39 */
40 public function register_routes(): void
41 {
42 // Payment stats — view cap (read-only aggregates).
43 register_rest_route($this->namespace, '/payments/stats', [
44 [
45 'methods' => 'GET',
46 'callback' => [$this, 'getPaymentStats'],
47 'permission_callback' => [$this, 'checkCanView'],
48 ],
49 ]);
50
51 // List + create payments. Create needs the edit-bookings cap
52 // because adding a payment mutates the booking's payment state.
53 register_rest_route($this->namespace, '/payments', [
54 [
55 'methods' => 'GET',
56 'callback' => [$this, 'getPayments'],
57 'permission_callback' => [$this, 'checkCanView'],
58 ],
59 [
60 'methods' => 'POST',
61 'callback' => [$this, 'createPayment'],
62 'permission_callback' => [$this, 'checkCanEdit'],
63 ]
64 ]);
65
66 // Single-payment read / update / delete. Update + delete are
67 // refund-equivalent operations from the customer's perspective
68 // (changing the amount or removing a recorded payment can
69 // affect what the customer owes), so we gate them on the
70 // dedicated refund cap. Accountant role holds refund without
71 // holding edit-bookings, so they can issue refunds without
72 // also being able to edit the underlying booking.
73 register_rest_route($this->namespace, '/payments/(?P<id>\d+)', [
74 [
75 'methods' => 'GET',
76 'callback' => [$this, 'getPayment'],
77 'permission_callback' => [$this, 'checkCanView'],
78 ],
79 [
80 'methods' => 'PUT',
81 'callback' => [$this, 'updatePayment'],
82 'permission_callback' => [$this, 'checkCanRefund'],
83 ],
84 [
85 'methods' => 'DELETE',
86 'callback' => [$this, 'deletePayment'],
87 'permission_callback' => [$this, 'checkCanRefund'],
88 ]
89 ]);
90 }
91
92 /**
93 * Granular permission checks. WP administrators pass every cap
94 * via the Team module's admin-fallback filter, so an explicit
95 * `manage_options` check isn't needed at this layer.
96 */
97 public function checkCanView(): bool
98 {
99 return current_user_can('yatra_view_bookings');
100 }
101
102 public function checkCanEdit(): bool
103 {
104 return current_user_can('yatra_edit_bookings');
105 }
106
107 public function checkCanRefund(): bool
108 {
109 // Refund cap is high-sensitivity. Held by Owner + Manager +
110 // Accountant by default. Sales Agent / Front Desk / Guide
111 // can record payments via the create endpoint above but
112 // cannot modify or delete existing ones.
113 return current_user_can('yatra_refund_bookings');
114 }
115
116 /**
117 * @deprecated Kept for any external code referencing the old
118 * method name. Routes to view — safer than the old "view OR
119 * manage_options" shorthand, and admin users still pass via
120 * the admin-fallback layer.
121 */
122 public function checkAdminPermission(): bool
123 {
124 return $this->checkCanView();
125 }
126
127 /**
128 * GET /payments/stats - Counts per status for admin toolbar
129 */
130 public function getPaymentStats(WP_REST_Request $request): WP_REST_Response
131 {
132 $counts = $this->paymentService->getAdminStatusCounts();
133
134 return new WP_REST_Response($counts, 200);
135 }
136
137 /**
138 * GET /payments - List all payments
139 */
140 public function getPayments(WP_REST_Request $request): WP_REST_Response
141 {
142 $filters = [
143 'page' => (int) ($request->get_param('page') ?: 1),
144 'per_page' => (int) ($request->get_param('per_page') ?: 20),
145 'booking_id' => (int) $request->get_param('booking_id'),
146 'status' => $request->get_param('status') ?: '',
147 'gateway' => $request->get_param('gateway') ?: '',
148 'search' => $request->get_param('search') ?: '',
149 'date_from' => $request->get_param('date_from') ?: '',
150 'date_to' => $request->get_param('date_to') ?: '',
151 // Column sorting from the table headers. Both are validated against a
152 // whitelist in the repository — never interpolated raw into SQL.
153 'orderby' => $request->get_param('orderby') ?: '',
154 'order' => $request->get_param('order') ?: '',
155 ];
156
157 $result = $this->paymentService->getPayments($filters);
158
159 return new WP_REST_Response([
160 'data' => $result['data'],
161 'total' => $result['total'],
162 'page' => $filters['page'],
163 'per_page' => $filters['per_page'],
164 'total_pages' => ceil($result['total'] / $filters['per_page']),
165 ], 200);
166 }
167
168 /**
169 * GET /payments/{id} - Get single payment
170 */
171 public function getPayment(WP_REST_Request $request)
172 {
173 $id = (int) $request->get_param('id');
174 $payment = $this->paymentService->getPayment($id);
175
176 if (!$payment) {
177 return new WP_Error('payment_not_found', 'Payment not found', ['status' => 404]);
178 }
179
180 return new WP_REST_Response($payment, 200);
181 }
182
183 /**
184 * POST /payments - Create payment
185 */
186 public function createPayment(WP_REST_Request $request)
187 {
188 $data = $request->get_json_params();
189
190 try {
191 $payment = $this->paymentService->createPayment($data);
192 return new WP_REST_Response($payment, 201);
193 } catch (\Exception $e) {
194 return new WP_Error('payment_creation_failed', $e->getMessage(), ['status' => 400]);
195 }
196 }
197
198 /**
199 * PUT /payments/{id} - Update payment
200 */
201 public function updatePayment(WP_REST_Request $request)
202 {
203 $id = (int) $request->get_param('id');
204 $data = $request->get_json_params();
205
206 try {
207 $payment = $this->paymentService->updatePayment($id, $data);
208
209 if (!$payment) {
210 return new WP_Error('payment_not_found', 'Payment not found', ['status' => 404]);
211 }
212
213 return new WP_REST_Response($payment, 200);
214 } catch (\Exception $e) {
215 return new WP_Error('payment_update_failed', $e->getMessage(), ['status' => 400]);
216 }
217 }
218
219 /**
220 * DELETE /payments/{id} - Delete payment
221 */
222 public function deletePayment(WP_REST_Request $request)
223 {
224 $id = (int) $request->get_param('id');
225
226 try {
227 $result = $this->paymentService->deletePayment($id);
228
229 if (!$result) {
230 return new WP_Error('payment_not_found', 'Payment not found', ['status' => 404]);
231 }
232
233 return new WP_REST_Response(['success' => true], 200);
234 } catch (\Exception $e) {
235 return new WP_Error('payment_deletion_failed', $e->getMessage(), ['status' => 400]);
236 }
237 }
238 }
239