PluginProbe
Yatra – Travel Booking & Tour Operator Software / 3.0.2.8
Yatra – Travel Booking & Tour Operator Software v3.0.2.8
3.0.16 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 All 84 releases
yatra / app / Services / BookingCronService.php

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

259 lines 8.9 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(__('Outstanding balance: %s — please pay before travel.', 'yatra'), yatra_format_price($amount_due))) . '</p>';
143 }
144 $extra .= '<p><strong>' . esc_html__('Preparation checklist', 'yatra') . '</strong></p><ul>'
145 . '<li>' . esc_html__('Valid government-issued ID', 'yatra') . '</li>'
146 . '<li>' . esc_html__('Travel insurance', 'yatra') . '</li>'
147 . '<li>' . esc_html__('Emergency contacts', 'yatra') . '</li>'
148 . '</ul>';
149 $vars['reminder_extra_html'] = $extra;
150
151 return TransactionalEmailTemplateService::sendIfEnabled(
152 TransactionalEmailTemplateService::TYPE_BOOKING_REMINDER,
153 $customer_email,
154 $vars
155 );
156 }
157
158 /**
159 * Expire pending bookings that have passed the expiry time
160 */
161 public static function expirePendingBookings(): void
162 {
163 $expiry_hours = (int) SettingsService::get('booking_expiry_hours', 24);
164
165 if ($expiry_hours <= 0) {
166 return; // Expiry disabled
167 }
168
169 $bookingRepository = self::getBookingRepository();
170 $tripRepository = self::getTripRepository();
171
172 // Calculate the expiry threshold
173 $expiry_threshold = date('Y-m-d H:i:s', strtotime("-{$expiry_hours} hours"));
174
175 // Get pending bookings that are older than the expiry threshold
176 $expired_bookings = $bookingRepository->getExpiredPendingBookings($expiry_threshold);
177
178 if (empty($expired_bookings)) {
179 return;
180 }
181
182 foreach ($expired_bookings as $booking) {
183 // Update booking status to expired/cancelled
184 $bookingRepository->expireBooking(
185 $booking->id,
186 __('Booking expired due to non-payment', 'yatra')
187 );
188
189 do_action('yatra_booking_status_changed', (int) $booking->id, 'pending', 'cancelled');
190
191 // Get trip title for email
192 $trip = $tripRepository->find($booking->trip_id);
193
194 // Send expiry notification email
195 self::sendExpiryEmail($booking, $trip);
196 }
197
198 // Log the operation
199 if (defined('WP_DEBUG') && WP_DEBUG) {
200 }
201 }
202
203 /**
204 * Send expiry notification email
205 */
206 private static function sendExpiryEmail(object $booking, ?object $trip): void
207 {
208 $customer_email = $booking->contact_email;
209 $customer_name = trim($booking->contact_first_name . ' ' . $booking->contact_last_name);
210
211 if (empty($customer_email)) {
212 return;
213 }
214
215 $expiry_hours = (int) SettingsService::get('booking_expiry_hours', 24);
216
217 $subject = sprintf(
218 __('[%s] Booking Expired - %s', 'yatra'),
219 get_bloginfo('name'),
220 $booking->reference
221 );
222
223 $body = sprintf(__("Dear %s,\n\n", 'yatra'), $customer_name ?: 'Customer');
224 $body .= __("We regret to inform you that your booking has been automatically cancelled due to non-payment.\n\n", 'yatra');
225
226 $body .= "═══════════════════════════════════════\n";
227 $body .= sprintf(__("Booking Reference: %s\n", 'yatra'), $booking->reference);
228 $body .= sprintf(__("Trip: %s\n", 'yatra'), $trip ? $trip->title : 'N/A');
229 $body .= "═══════════════════════════════════════\n\n";
230
231 $body .= sprintf(
232 __("Bookings that are not paid within %d hours are automatically cancelled to maintain availability for other travelers.\n\n", 'yatra'),
233 $expiry_hours
234 );
235
236 $body .= __("If you still wish to book this trip, please visit our website to create a new booking.\n\n", 'yatra');
237 $body .= __("If you believe this is an error or have already made a payment, please contact us immediately.\n\n", 'yatra');
238
239 $body .= sprintf(__("Best regards,\n%s Team\n", 'yatra'), get_bloginfo('name'));
240 $body .= home_url() . "\n";
241
242 $headers = ['Content-Type: text/plain; charset=UTF-8'];
243
244 EmailService::send($customer_email, $subject, $body, $headers);
245
246 // Also notify admin
247 $admin_email = get_option('admin_email');
248 $admin_subject = sprintf(__('[%s] Booking Expired - %s', 'yatra'), get_bloginfo('name'), $booking->reference);
249
250 $admin_body = sprintf(__("Booking %s has been automatically cancelled due to non-payment.\n\n", 'yatra'), $booking->reference);
251 $admin_body .= sprintf(__("Customer: %s (%s)\n", 'yatra'), $customer_name, $customer_email);
252 $admin_body .= sprintf(__("Trip: %s\n", 'yatra'), $trip ? $trip->title : 'N/A');
253 $admin_body .= sprintf(__("View: %s\n", 'yatra'), admin_url('admin.php?page=yatra&subpage=bookings&action=view&id=' . $booking->id));
254
255 EmailService::send($admin_email, $admin_subject, $admin_body, $headers);
256 }
257 }
258
259