PluginProbe
Yatra – Travel Booking & Tour Operator Software / 3.0.15
Yatra – Travel Booking & Tour Operator Software v3.0.15
3.0.15 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 All 83 releases
yatra / app / Controllers / PaymentController.php

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

251 lines 8.1 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
193 // The service reports validation failures (unknown booking, invalid
194 // status) as ['success' => false]; answering 201 made the admin form
195 // redirect as if the payment had been saved.
196 if (is_array($payment) && isset($payment['success']) && !$payment['success']) {
197 return new WP_REST_Response($payment, 400);
198 }
199
200 return new WP_REST_Response($payment, 201);
201 } catch (\Exception $e) {
202 return new WP_Error('payment_creation_failed', $e->getMessage(), ['status' => 400]);
203 }
204 }
205
206 /**
207 * PUT /payments/{id} - Update payment
208 */
209 public function updatePayment(WP_REST_Request $request)
210 {
211 $id = (int) $request->get_param('id');
212 $data = $request->get_json_params();
213
214 try {
215 $payment = $this->paymentService->updatePayment($id, $data);
216
217 if (!$payment) {
218 return new WP_Error('payment_not_found', 'Payment not found', ['status' => 404]);
219 }
220
221 if (is_array($payment) && isset($payment['success']) && !$payment['success']) {
222 return new WP_REST_Response($payment, 400);
223 }
224
225 return new WP_REST_Response($payment, 200);
226 } catch (\Exception $e) {
227 return new WP_Error('payment_update_failed', $e->getMessage(), ['status' => 400]);
228 }
229 }
230
231 /**
232 * DELETE /payments/{id} - Delete payment
233 */
234 public function deletePayment(WP_REST_Request $request)
235 {
236 $id = (int) $request->get_param('id');
237
238 try {
239 $result = $this->paymentService->deletePayment($id);
240
241 if (!$result) {
242 return new WP_Error('payment_not_found', 'Payment not found', ['status' => 404]);
243 }
244
245 return new WP_REST_Response(['success' => true], 200);
246 } catch (\Exception $e) {
247 return new WP_Error('payment_deletion_failed', $e->getMessage(), ['status' => 400]);
248 }
249 }
250 }
251