PluginProbe
Yatra – Travel Booking & Tour Operator Software / 3.0.9
Yatra – Travel Booking & Tour Operator Software v3.0.9
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 / Services / BookingCronService.php

BookingCronService.php in Yatra – Travel Booking & Tour Operator Software 3.0.9, at app/Services/BookingCronService.php

248 lines 7.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Yatra\Services;
4
5 use Yatra\Repositories\BookingRepository;
6 use Yatra\Repositories\TripRepository;
7
8 /**
9 * Handles scheduled booking tasks:
10 * - Sending reminder emails before departure
11 * - Auto-cancelling expired pending bookings
12 */
13 class BookingCronService
14 {
15 /**
16 * Get BookingRepository instance
17 *
18 * @return BookingRepository
19 */
20 private static function getBookingRepository(): BookingRepository
21 {
22 static $repository = null;
23 if ($repository === null) {
24 $repository = new BookingRepository();
25 }
26 return $repository;
27 }
28
29 /**
30 * Get TripRepository instance
31 *
32 * @return TripRepository
33 */
34 private static function getTripRepository(): TripRepository
35 {
36 static $repository = null;
37 if ($repository === null) {
38 $repository = new TripRepository();
39 }
40 return $repository;
41 }
42
43 /**
44 * Register cron hooks
45 */
46 public static function register(): void
47 {
48 // Register cron hooks
49 add_action('yatra_booking_reminder', [self::class, 'sendBookingReminders']);
50 add_action('yatra_booking_expiry', [self::class, 'expirePendingBookings']);
51
52 // Schedule events if not already scheduled
53 self::scheduleEvents();
54 }
55
56 /**
57 * Schedule cron events
58 */
59 public static function scheduleEvents(): void
60 {
61 // Schedule reminder emails - run daily
62 if (!wp_next_scheduled('yatra_booking_reminder')) {
63 wp_schedule_event(time(), 'daily', 'yatra_booking_reminder');
64 }
65
66 // Schedule expiry check - run hourly
67 if (!wp_next_scheduled('yatra_booking_expiry')) {
68 wp_schedule_event(time(), 'hourly', 'yatra_booking_expiry');
69 }
70 }
71
72 /**
73 * Unschedule cron events (on plugin deactivation)
74 */
75 public static function unscheduleEvents(): void
76 {
77 $timestamp = wp_next_scheduled('yatra_booking_reminder');
78 if ($timestamp) {
79 wp_unschedule_event($timestamp, 'yatra_booking_reminder');
80 }
81
82 $timestamp = wp_next_scheduled('yatra_booking_expiry');
83 if ($timestamp) {
84 wp_unschedule_event($timestamp, 'yatra_booking_expiry');
85 }
86 }
87
88 /**
89 * Send reminder emails for upcoming trips
90 */
91 public static function sendBookingReminders(): void
92 {
93 $reminder_days = (int) SettingsService::get('booking_reminder_days', 3);
94
95 if ($reminder_days <= 0) {
96 return; // Reminders disabled
97 }
98
99 $bookingRepository = self::getBookingRepository();
100
101 // Calculate the target date (X days from now)
102 $target_date = date('Y-m-d', strtotime("+{$reminder_days} days"));
103
104 // Get confirmed bookings with travel date matching the target
105 $bookings = $bookingRepository->getBookingsForReminder($target_date);
106
107 if (empty($bookings)) {
108 return;
109 }
110
111 foreach ($bookings as $booking) {
112 if (self::sendReminderEmail($booking)) {
113 $bookingRepository->markReminderSent($booking->id);
114 }
115 }
116
117 // Log the operation
118 if (defined('WP_DEBUG') && WP_DEBUG) {
119 }
120 }
121
122 /**
123 * Send a reminder email to the customer
124 */
125 private static function sendReminderEmail(object $booking): bool
126 {
127 $customer_email = $booking->contact_email;
128
129 if (empty($customer_email)) {
130 return false;
131 }
132
133 $reminder_days = (int) SettingsService::get('booking_reminder_days', 3);
134 $vars = TransactionalEmailTemplateService::variablesFromBooking($booking);
135 $vars['reminder_days'] = (string) $reminder_days;
136 $vars['days_until_trip'] = (string) $reminder_days;
137
138 $amount_due = (float) $booking->amount_due;
139 $extra = '';
140 if ($amount_due > 0) {
141 $extra = '<p><strong>' . esc_html__('Payment reminder', 'yatra') . '</strong></p>'
142 . '<p>' . esc_html(sprintf(
143 /* translators: %s: formatted outstanding balance amount. */
144 __('Outstanding balance: %s — please pay before travel.', 'yatra'),
145 yatra_format_price($amount_due)
146 )) . '</p>';
147 }
148 $extra .= '<p><strong>' . esc_html__('Preparation checklist', 'yatra') . '</strong></p><ul>'
149 . '<li>' . esc_html__('Valid government-issued ID', 'yatra') . '</li>'
150 . '<li>' . esc_html__('Travel insurance', 'yatra') . '</li>'
151 . '<li>' . esc_html__('Emergency contacts', 'yatra') . '</li>'
152 . '</ul>';
153 $vars['reminder_extra_html'] = $extra;
154
155 return TransactionalEmailTemplateService::sendIfEnabled(
156 TransactionalEmailTemplateService::TYPE_BOOKING_REMINDER,
157 $customer_email,
158 $vars
159 );
160 }
161
162 /**
163 * Expire pending bookings that have passed the expiry time
164 */
165 public static function expirePendingBookings(): void
166 {
167 $expiry_hours = (int) SettingsService::get('booking_expiry_hours', 24);
168
169 if ($expiry_hours <= 0) {
170 return; // Expiry disabled
171 }
172
173 $bookingRepository = self::getBookingRepository();
174 $tripRepository = self::getTripRepository();
175
176 // Calculate the expiry threshold
177 $expiry_threshold = date('Y-m-d H:i:s', strtotime("-{$expiry_hours} hours"));
178
179 // Get pending bookings that are older than the expiry threshold
180 $expired_bookings = $bookingRepository->getExpiredPendingBookings($expiry_threshold);
181
182 if (empty($expired_bookings)) {
183 return;
184 }
185
186 foreach ($expired_bookings as $booking) {
187 // Update booking status to expired/cancelled
188 $bookingRepository->expireBooking(
189 $booking->id,
190 __('Booking expired due to non-payment', 'yatra')
191 );
192
193 do_action('yatra_booking_status_changed', (int) $booking->id, 'pending', 'cancelled');
194
195 // Get trip title for email
196 $trip = $tripRepository->find($booking->trip_id);
197
198 // Send expiry notification email
199 self::sendExpiryEmail($booking, $trip);
200 }
201
202 // Log the operation
203 if (defined('WP_DEBUG') && WP_DEBUG) {
204 }
205 }
206
207 /**
208 * Send expiry notification email
209 */
210 private static function sendExpiryEmail(object $booking, ?object $trip): void
211 {
212 $customer_email = $booking->contact_email;
213
214 if (empty($customer_email)) {
215 return;
216 }
217
218 $expiry_hours = (int) SettingsService::get('booking_expiry_hours', 24);
219 $full = self::getBookingRepository()->findWithTrip((int) $booking->id) ?: $booking;
220
221 $vars = TransactionalEmailTemplateService::variablesFromBooking($full);
222 if ($trip && !empty($trip->title)) {
223 $vars['trip_name'] = (string) $trip->title;
224 }
225 $vars['expiry_policy_note'] = sprintf(
226 /* translators: %d: hours until unpaid booking expires */
227 __('Unpaid bookings are released after %d hours.', 'yatra'),
228 $expiry_hours
229 );
230
231 TransactionalEmailTemplateService::sendIfEnabled(
232 TransactionalEmailTemplateService::TYPE_BOOKING_EXPIRED_CUSTOMER,
233 (string) $customer_email,
234 $vars
235 );
236
237 $admin_email = sanitize_email((string) SettingsService::getString('admin_email', (string) get_option('admin_email', '')));
238 if ($admin_email !== '' && is_email($admin_email)) {
239 TransactionalEmailTemplateService::sendIfEnabled(
240 TransactionalEmailTemplateService::TYPE_ADMIN_BOOKING_EXPIRED,
241 $admin_email,
242 $vars
243 );
244 }
245 }
246 }
247
248