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 / RecurringAvailabilityController.php

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

365 lines 11.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Recurring Availability REST API Controller
4 * API endpoints for recurring availability rules management
5 *
6 * This is a FREE feature - no Pro plugin required
7 *
8 * @package Yatra\Controllers
9 * @since 3.0.0
10 */
11
12 declare(strict_types=1);
13
14 namespace Yatra\Controllers;
15
16 use WP_REST_Request;
17 use WP_REST_Response;
18 use WP_Error;
19 use Yatra\Services\RecurringAvailabilityService;
20 use Yatra\Repositories\RecurringAvailabilityRepository;
21
22 class RecurringAvailabilityController extends BaseController
23 {
24 private RecurringAvailabilityService $service;
25
26 public function __construct()
27 {
28 $this->service = new RecurringAvailabilityService(new RecurringAvailabilityRepository());
29 }
30
31 /**
32 * Register routes
33 */
34 public function register_routes(): void
35 {
36 $namespace = 'yatra/v1';
37 $base = 'recurring-availability';
38
39 // Collection routes
40 register_rest_route($namespace, '/' . $base, [
41 [
42 'methods' => \WP_REST_Server::READABLE,
43 'callback' => [$this, 'get_items'],
44 'permission_callback' => [$this, 'check_permission'],
45 'args' => [
46 'trip_id' => [
47 'required' => true,
48 'type' => 'integer',
49 'validate_callback' => function ($param) {
50 return is_numeric($param) && $param > 0;
51 },
52 ],
53 'status' => [
54 'type' => 'string',
55 'default' => 'all',
56 ],
57 'rule_type' => [
58 'type' => 'string',
59 'default' => 'all',
60 ],
61 'page' => [
62 'type' => 'integer',
63 'default' => 1,
64 'minimum' => 1,
65 ],
66 'per_page' => [
67 'type' => 'integer',
68 'default' => 50,
69 'minimum' => 1,
70 'maximum' => 100,
71 ],
72 ],
73 ],
74 [
75 'methods' => \WP_REST_Server::CREATABLE,
76 'callback' => [$this, 'create_item'],
77 'permission_callback' => [$this, 'check_permission'],
78 ],
79 ]);
80
81 // Single item routes
82 register_rest_route($namespace, '/' . $base . '/(?P<id>[\d]+)', [
83 [
84 'methods' => \WP_REST_Server::READABLE,
85 'callback' => [$this, 'get_item'],
86 'permission_callback' => [$this, 'check_permission'],
87 ],
88 [
89 'methods' => \WP_REST_Server::EDITABLE,
90 'callback' => [$this, 'update_item'],
91 'permission_callback' => [$this, 'check_permission'],
92 ],
93 [
94 'methods' => \WP_REST_Server::DELETABLE,
95 'callback' => [$this, 'delete_item'],
96 'permission_callback' => [$this, 'check_permission'],
97 ],
98 ]);
99
100 // Status counts endpoint
101 register_rest_route($namespace, '/' . $base . '/counts', [
102 [
103 'methods' => \WP_REST_Server::READABLE,
104 'callback' => [$this, 'get_counts'],
105 'permission_callback' => [$this, 'check_permission'],
106 'args' => [
107 'trip_id' => [
108 'required' => true,
109 'type' => 'integer',
110 'validate_callback' => function ($param) {
111 return is_numeric($param) && $param > 0;
112 },
113 ],
114 ],
115 ],
116 ]);
117
118 // Preview generated dates
119 register_rest_route($namespace, '/' . $base . '/preview', [
120 'methods' => \WP_REST_Server::CREATABLE,
121 'callback' => [$this, 'preview_dates'],
122 'permission_callback' => [$this, 'check_permission'],
123 ]);
124
125 // Generate dates for a trip
126 register_rest_route($namespace, '/' . $base . '/generate/(?P<trip_id>[\d]+)', [
127 'methods' => \WP_REST_Server::READABLE,
128 'callback' => [$this, 'generate_dates'],
129 'permission_callback' => [$this, 'check_permission'],
130 'args' => [
131 'from_date' => [
132 'type' => 'string',
133 'default' => '',
134 ],
135 'to_date' => [
136 'type' => 'string',
137 'default' => '',
138 ],
139 ],
140 ]);
141 }
142
143 /**
144 * Get status counts for recurring rules
145 */
146 public function get_counts(WP_REST_Request $request)
147 {
148 try {
149 $tripId = (int) $request->get_param('trip_id');
150
151 $counts = $this->service->getStatusCounts($tripId);
152
153 return new WP_REST_Response($counts, 200);
154 } catch (\Exception $e) {
155 return new WP_Error('error', $e->getMessage(), ['status' => 500]);
156 }
157 }
158
159 /**
160 * Get all rules for a trip
161 */
162 public function get_items(WP_REST_Request $request)
163 {
164 try {
165 $tripId = (int) $request->get_param('trip_id');
166
167 $filters = [
168 'status' => $request->get_param('status') ?? 'all',
169 'rule_type' => $request->get_param('rule_type') ?? 'all',
170 'search' => $request->get_param('search') ?? '',
171 'page' => $request->get_param('page') ?? 1,
172 'per_page' => $request->get_param('per_page') ?? 50,
173 ];
174
175 $items = $this->service->getByTripId($tripId, $filters);
176 $total = $this->service->countByTripId($tripId, $filters);
177
178 // Add generated dates count to each rule
179 foreach ($items as &$item) {
180 $preview = $this->service->previewDates((array) $item, 0);
181 $item->generated_count = $preview['total'];
182 }
183
184 return new WP_REST_Response([
185 'data' => $items,
186 'total' => $total,
187 'pages' => ceil($total / ($filters['per_page'] ?: 1)),
188 'page' => (int) $filters['page'],
189 'per_page' => (int) $filters['per_page'],
190 ], 200);
191 } catch (\Exception $e) {
192 return new WP_Error('error', $e->getMessage(), ['status' => 500]);
193 }
194 }
195
196 /**
197 * Get single rule
198 */
199 public function get_item(WP_REST_Request $request)
200 {
201 try {
202 $id = (int) $request->get_param('id');
203 $item = $this->service->find($id);
204
205 if (!$item) {
206 return new WP_Error('not_found', 'Rule not found', ['status' => 404]);
207 }
208
209 // Add preview data
210 $preview = $this->service->previewDates((array) $item, 20);
211 $item->preview = $preview;
212
213 return new WP_REST_Response(['data' => $item], 200);
214 } catch (\Exception $e) {
215 return new WP_Error('error', $e->getMessage(), ['status' => 500]);
216 }
217 }
218
219 /**
220 * Create new rule
221 */
222 public function create_item(WP_REST_Request $request)
223 {
224 try {
225 $data = $request->get_json_params();
226
227 if (empty($data)) {
228 $data = $request->get_body_params();
229 }
230
231 $id = $this->service->create($data);
232
233 return new WP_REST_Response([
234 'id' => $id,
235 'message' => __('Recurring rule created successfully', 'yatra'),
236 ], 201);
237 } catch (\InvalidArgumentException $e) {
238 return new WP_Error('validation_error', $e->getMessage(), ['status' => 400]);
239 } catch (\Exception $e) {
240 return new WP_Error('error', $e->getMessage(), ['status' => 500]);
241 }
242 }
243
244 /**
245 * Update rule
246 */
247 public function update_item(WP_REST_Request $request)
248 {
249 try {
250 $id = (int) $request->get_param('id');
251 $data = $request->get_json_params();
252
253 if (empty($data)) {
254 $data = $request->get_body_params();
255 }
256
257 $existing = $this->service->find($id);
258 if (!$existing) {
259 return new WP_Error('not_found', 'Rule not found', ['status' => 404]);
260 }
261
262 $success = $this->service->update($id, $data);
263
264 if (!$success) {
265 return new WP_Error('error', 'Failed to update rule', ['status' => 500]);
266 }
267
268 return new WP_REST_Response([
269 'message' => __('Recurring rule updated successfully', 'yatra'),
270 ], 200);
271 } catch (\InvalidArgumentException $e) {
272 return new WP_Error('validation_error', $e->getMessage(), ['status' => 400]);
273 } catch (\Exception $e) {
274 return new WP_Error('error', $e->getMessage(), ['status' => 500]);
275 }
276 }
277
278 /**
279 * Delete rule
280 */
281 public function delete_item(WP_REST_Request $request)
282 {
283 try {
284 $id = (int) $request->get_param('id');
285
286 $existing = $this->service->find($id);
287 if (!$existing) {
288 return new WP_Error('not_found', 'Rule not found', ['status' => 404]);
289 }
290
291 $success = $this->service->delete($id);
292
293 if (!$success) {
294 return new WP_Error('error', 'Failed to delete rule', ['status' => 500]);
295 }
296
297 return new WP_REST_Response([
298 'message' => __('Recurring rule deleted successfully', 'yatra'),
299 ], 200);
300 } catch (\Exception $e) {
301 return new WP_Error('error', $e->getMessage(), ['status' => 500]);
302 }
303 }
304
305 /**
306 * Preview generated dates from rule data
307 */
308 public function preview_dates(WP_REST_Request $request)
309 {
310 try {
311 $data = $request->get_json_params();
312
313 if (empty($data)) {
314 $data = $request->get_body_params();
315 }
316
317 if (empty($data['rule_type']) || empty($data['start_date'])) {
318 return new WP_Error('validation_error', 'Rule type and start date are required for preview', ['status' => 400]);
319 }
320
321 $limit = (int) ($data['preview_limit'] ?? 20);
322 $preview = $this->service->previewDates($data, $limit);
323
324 return new WP_REST_Response(['data' => $preview], 200);
325 } catch (\Exception $e) {
326 return new WP_Error('error', $e->getMessage(), ['status' => 500]);
327 }
328 }
329
330 /**
331 * Generate dates for a trip from all active rules
332 */
333 public function generate_dates(WP_REST_Request $request)
334 {
335 try {
336 $tripId = (int) $request->get_param('trip_id');
337
338 $fromDate = $request->get_param('from_date') ?: date('Y-m-d');
339 $toDate = $request->get_param('to_date') ?: date('Y-m-d', strtotime('+90 days'));
340
341 $dates = $this->service->generateDatesForTrip($tripId, $fromDate, $toDate);
342
343 return new WP_REST_Response([
344 'data' => $dates,
345 'total' => count($dates),
346 'from_date' => $fromDate,
347 'to_date' => $toDate,
348 ], 200);
349 } catch (\Exception $e) {
350 return new WP_Error('error', $e->getMessage(), ['status' => 500]);
351 }
352 }
353
354 /**
355 * Recurring availability writes — trip-edits cap. Same gate as the
356 * other availability controllers. WP admins pass via the Team
357 * module's admin-fallback filter.
358 */
359 public function check_permission(?\WP_REST_Request $request = null): bool
360 {
361 return current_user_can('yatra_edit_trips');
362 }
363 }
364
365