PluginProbe
Yatra – Travel Booking & Tour Operator Software / 3.0.3
Yatra – Travel Booking & Tour Operator Software v3.0.3
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 / Services / SettingsService.php

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

748 lines 26.0 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\Services;
6
7 /**
8 * Centralized Settings Service
9 *
10 * Provides a single point of access for all plugin settings.
11 * Caches settings to avoid multiple database queries.
12 *
13 * @package Yatra
14 */
15 class SettingsService
16 {
17 /**
18 * Cached settings
19 */
20 private static ?array $settings = null;
21
22 /**
23 * Settings option prefix in database
24 * Each setting is stored as yatra_{key}
25 */
26 private const OPTION_PREFIX = 'yatra_';
27
28 /**
29 * Default settings
30 */
31 private static array $defaults = [
32 // General
33 'company_name' => '',
34 'company_email' => '',
35 'company_phone' => '',
36 'company_address' => '',
37 'timezone' => 'UTC',
38 'date_format' => 'Y-m-d',
39 'time_format' => 'H:i',
40 /** Primary brand color (hex) for trip/booking/listing frontend — see FrontendThemeCss */
41 'frontend_primary_color' => '#3b82f6',
42 /** Max width for Yatra trip/booking/listing containers (CSS length). Empty = theme.json / content width / filter. */
43 'frontend_container_max_width' => '',
44
45 // Booking
46 'booking_base' => 'book',
47 'use_booking_page' => false,
48 'booking_page_id' => 0,
49 'terms_page_id' => 0,
50 'privacy_policy_page_id' => 0,
51 'enable_guest_booking' => true,
52 'booking_confirmation' => true,
53 'auto_confirm_bookings' => false,
54 'require_login' => false,
55 'allow_guest_checkout' => true,
56 'cancellation_policy' => 'full_refund',
57 'cancellation_days' => 7,
58 'refund_policy' => '',
59 'booking_expiry_hours' => 24,
60 'booking_reminder_days' => 3,
61 'allow_waitlist' => true,
62 'waitlist_auto_confirm' => false,
63
64 // Payment
65 'currency' => 'USD',
66 'payment_test_mode' => true,
67 'currency_position' => 'before',
68 'thousand_separator' => ',',
69 'decimal_separator' => '.',
70 'decimal_places' => 2,
71 // Flexible payments (deposit/partial) - Pro feature
72 // These defaults are overridden by Pro's FlexiblePaymentsModule when active
73 'enable_deposit' => false,
74 'deposit_type' => 'percentage',
75 'deposit_amount' => 20,
76 'deposit_required' => false,
77 'deposit_percentage' => 20,
78 'partial_payment' => false,
79 'partial_payment_percentage' => 30,
80 'auto_confirm_pay_later' => true,
81 'payment_gateways' => ['pay_later'],
82 'payment_methods' => [],
83 'gateway_configs' => [],
84 'gateway_order' => [],
85
86 'allow_save_payment_methods' => false,
87
88 // Email
89 'email_from_name' => '',
90 'email_from_address' => '',
91 'admin_email' => '',
92 'enable_admin_notifications' => true,
93 'enable_customer_notifications' => true,
94
95 // Trip
96 'trip_base' => 'trip',
97 'trips_per_page' => 12,
98 'enable_wishlist' => false,
99 'enable_comparison' => false,
100 'show_sold_out' => true,
101
102 // Customer
103 'enable_customer_accounts' => true,
104 'enable_customer_registration' => true,
105 'customer_account_page' => 0,
106
107 // Review
108 'enable_reviews' => true,
109 'require_booking_to_review' => false,
110 'auto_approve_reviews' => false,
111 'enable_review_moderation' => true,
112 'minimum_rating' => 1,
113 'review_reminder_days' => 7,
114
115 // Tax
116 'enable_tax' => false,
117 'tax_rate' => 0,
118 'tax_inclusive' => false,
119 'tax_label' => 'Tax',
120 'multiple_taxes_enabled' => false,
121 'multiple_taxes' => [],
122 'multiple_taxes_by_country' => [],
123
124 // Currency
125 'enabled_currencies' => ['USD'],
126 'default_currency' => 'USD',
127
128 // Notification
129 'enable_push_notifications' => false,
130 'enable_sms_notifications' => false,
131
132 // Permalink
133 'destination_base' => 'destination',
134 'activity_base' => 'activity',
135 'trip_category_base' => 'trip-category',
136
137 // Advanced
138 'enable_debug_mode' => false,
139 'delete_data_on_uninstall' => false,
140
141 // Booking Form Builder
142 'booking_form_config' => [],
143 ];
144
145 /**
146 * Get default booking form configuration
147 *
148 * @return array
149 */
150 public static function getDefaultBookingFormConfig(): array
151 {
152 return [
153 'contact_form' => [
154 'title' => 'Lead Traveler / Contact Information',
155 'description' => 'Primary contact person for this booking',
156 'fields' => [
157 ['id' => 'first_name', 'type' => 'text', 'label' => 'First Name', 'placeholder' => 'Enter first name', 'required' => true, 'enabled' => true, 'order' => 1, 'width' => 'half', 'locked' => true],
158 ['id' => 'last_name', 'type' => 'text', 'label' => 'Last Name', 'placeholder' => 'Enter last name', 'required' => true, 'enabled' => true, 'order' => 2, 'width' => 'half', 'locked' => true],
159 ['id' => 'email', 'type' => 'email', 'label' => 'Email Address', 'placeholder' => 'your@email.com', 'required' => true, 'enabled' => true, 'order' => 3, 'width' => 'half', 'locked' => true],
160 ['id' => 'phone', 'type' => 'tel', 'label' => 'Phone Number', 'placeholder' => '+1 234 567 8900', 'required' => true, 'enabled' => true, 'order' => 4, 'width' => 'half', 'locked' => true],
161 ['id' => 'country', 'type' => 'country', 'label' => 'Country', 'placeholder' => 'Select Country', 'required' => true, 'enabled' => true, 'order' => 5, 'width' => 'half', 'locked' => true],
162 ['id' => 'nationality', 'type' => 'country', 'label' => 'Nationality', 'placeholder' => 'Select Nationality', 'required' => false, 'enabled' => true, 'order' => 6, 'width' => 'half'],
163 ['id' => 'address', 'type' => 'text', 'label' => 'Address', 'placeholder' => 'Street address (optional)', 'required' => false, 'enabled' => true, 'order' => 7, 'width' => 'full'],
164 ],
165 ],
166 'emergency_contact_form' => [
167 'title' => 'Emergency Contact',
168 'description' => 'Person to contact in case of emergency',
169 'enabled' => true,
170 'fields' => [
171 ['id' => 'name', 'type' => 'text', 'label' => 'Contact Name', 'placeholder' => 'Full name', 'required' => true, 'enabled' => true, 'order' => 1, 'width' => 'half'],
172 ['id' => 'phone', 'type' => 'tel', 'label' => 'Contact Phone', 'placeholder' => '+1 234 567 8900', 'required' => true, 'enabled' => true, 'order' => 2, 'width' => 'half'],
173 ['id' => 'relationship', 'type' => 'select', 'label' => 'Relationship', 'placeholder' => 'Select Relationship', 'required' => false, 'enabled' => true, 'order' => 3, 'width' => 'full', 'options' => [
174 ['value' => 'spouse', 'label' => 'Spouse/Partner'],
175 ['value' => 'parent', 'label' => 'Parent'],
176 ['value' => 'sibling', 'label' => 'Sibling'],
177 ['value' => 'child', 'label' => 'Child'],
178 ['value' => 'friend', 'label' => 'Friend'],
179 ['value' => 'other', 'label' => 'Other'],
180 ]],
181 ],
182 ],
183 'traveler_form' => [
184 'title' => 'Traveler Information',
185 'description' => 'Please provide details for each traveler',
186 'fields' => [
187 ['id' => 'first_name', 'type' => 'text', 'label' => 'First Name', 'placeholder' => 'Legal first name', 'required' => true, 'enabled' => true, 'order' => 1, 'width' => 'half'],
188 ['id' => 'last_name', 'type' => 'text', 'label' => 'Last Name', 'placeholder' => 'Legal last name', 'required' => true, 'enabled' => true, 'order' => 2, 'width' => 'half'],
189 ['id' => 'date_of_birth', 'type' => 'date', 'label' => 'Date of Birth', 'placeholder' => '', 'required' => true, 'enabled' => true, 'order' => 3, 'width' => 'half'],
190 ['id' => 'gender', 'type' => 'select', 'label' => 'Gender', 'placeholder' => 'Select Gender', 'required' => true, 'enabled' => true, 'order' => 4, 'width' => 'half', 'options' => [
191 ['value' => 'male', 'label' => 'Male'],
192 ['value' => 'female', 'label' => 'Female'],
193 ['value' => 'other', 'label' => 'Other'],
194 ]],
195 ['id' => 'nationality', 'type' => 'country', 'label' => 'Nationality', 'placeholder' => 'Select Nationality', 'required' => true, 'enabled' => true, 'order' => 5, 'width' => 'full'],
196 ['id' => 'dietary', 'type' => 'select', 'label' => 'Dietary Requirements', 'placeholder' => 'Select', 'required' => false, 'enabled' => true, 'order' => 6, 'width' => 'half', 'section' => 'dietary_medical', 'options' => [
197 ['value' => 'none', 'label' => 'No special requirements'],
198 ['value' => 'vegetarian', 'label' => 'Vegetarian'],
199 ['value' => 'vegan', 'label' => 'Vegan'],
200 ['value' => 'halal', 'label' => 'Halal'],
201 ['value' => 'kosher', 'label' => 'Kosher'],
202 ['value' => 'gluten_free', 'label' => 'Gluten Free'],
203 ['value' => 'lactose_free', 'label' => 'Lactose Free'],
204 ['value' => 'other', 'label' => 'Other (specify in notes)'],
205 ]],
206 ['id' => 'medical', 'type' => 'text', 'label' => 'Medical Conditions / Allergies', 'placeholder' => 'Any allergies or conditions we should know', 'required' => false, 'enabled' => true, 'order' => 7, 'width' => 'half', 'section' => 'dietary_medical'],
207 ],
208 ],
209 ];
210 }
211
212 /**
213 * Get booking form configuration (merged with defaults)
214 *
215 * @return array
216 */
217 public static function getBookingFormConfig(): array
218 {
219 $saved_config = self::get('booking_form_config', []);
220 $default_config = self::getDefaultBookingFormConfig();
221
222 // If no saved config, return defaults (Pro may filter)
223 if (empty($saved_config)) {
224 return apply_filters('yatra_booking_form_config', $default_config);
225 }
226
227 // Build a map of locked field IDs from defaults
228 $locked_fields = [];
229 foreach ($default_config as $form_type => $form_config) {
230 if (!empty($form_config['fields'])) {
231 foreach ($form_config['fields'] as $field) {
232 if (!empty($field['locked'])) {
233 $locked_fields[$form_type][$field['id']] = true;
234 }
235 }
236 }
237 }
238
239 // Merge saved with defaults
240 $merged = array_replace_recursive($default_config, $saved_config);
241
242 // Ensure locked status is preserved from defaults (locked cannot be overridden)
243 foreach ($merged as $form_type => &$form_config) {
244 if (!empty($form_config['fields']) && is_array($form_config['fields'])) {
245 foreach ($form_config['fields'] as &$field) {
246 // If this field ID is in the locked list, force locked=true and required=true
247 if (isset($locked_fields[$form_type][$field['id']])) {
248 $field['locked'] = true;
249 $field['required'] = true;
250 }
251 }
252 }
253 }
254
255 return apply_filters('yatra_booking_form_config', $merged);
256 }
257
258 private static function isEmailIdentityKey(string $key): bool
259 {
260 return $key === 'admin_email' || $key === 'from_email' || $key === 'from_name';
261 }
262
263 private static function isEmptyScalar($value): bool
264 {
265 return $value === null || $value === false || $value === ''
266 || (is_string($value) && trim($value) === '');
267 }
268
269 /**
270 * When Yatra delivery options are empty, use WordPress site admin email / blog name (same as installer defaults).
271 *
272 * @param mixed $value
273 * @return mixed
274 */
275 private static function applyEmailIdentityFallback(string $key, $value)
276 {
277 if (!self::isEmailIdentityKey($key) || !self::isEmptyScalar($value)) {
278 return $value;
279 }
280 if ($key === 'from_name') {
281 $wp = (string) get_bloginfo('name');
282
283 return $wp !== '' ? $wp : $value;
284 }
285 $wp = (string) get_option('admin_email', '');
286
287 return $wp !== '' ? $wp : $value;
288 }
289
290 /**
291 * Get all settings
292 *
293 * @return array All settings with defaults applied
294 */
295 public static function all(): array
296 {
297 if (self::$settings === null) {
298 self::load();
299 }
300
301 return self::$settings;
302 }
303
304 /**
305 * Get setting value with fallback to default
306 *
307 * @param string $key Setting key
308 * @param mixed $default Default value if setting not found
309 * @return mixed Setting value or default
310 */
311 public static function get(string $key, $default = null)
312 {
313 if (self::$settings === null) {
314 self::load();
315 }
316
317 if (self::isScheduledPaymentSetting($key)) {
318 $scheduledDefaults = self::scheduledPaymentDefaults();
319
320 return apply_filters(
321 'yatra_scheduled_payment_setting',
322 $default ?? ($scheduledDefaults[$key] ?? null),
323 $key
324 );
325 }
326
327 // Support dot notation for nested access (future use)
328 if (strpos($key, '.') !== false) {
329 $keys = explode('.', $key);
330 $value = self::$settings;
331 foreach ($keys as $k) {
332 if (!isset($value[$k])) {
333 return $default ?? (self::$defaults[$key] ?? null);
334 }
335 $value = $value[$k];
336 }
337 return $value;
338 }
339
340 // If setting exists in cache, return it
341 if (isset(self::$settings[$key])) {
342 return self::applyEmailIdentityFallback($key, self::$settings[$key]);
343 }
344
345 // Try to fetch from database directly for settings not in defaults
346 $option_name = self::OPTION_PREFIX . $key;
347 $value = get_option($option_name, null);
348
349 // Installer / migrations used yatra_email_from_*; REST + EmailService use yatra_from_*.
350 if (($value === null || $value === false || $value === '') && $key === 'from_email') {
351 $legacy = get_option(self::OPTION_PREFIX . 'email_from_address', '');
352 if (is_string($legacy) && $legacy !== '') {
353 $value = $legacy;
354 }
355 }
356 if (($value === null || $value === false || $value === '') && $key === 'from_name') {
357 $legacy = get_option(self::OPTION_PREFIX . 'email_from_name', '');
358 if (is_string($legacy) && $legacy !== '') {
359 $value = $legacy;
360 }
361 }
362
363 if ($value !== null) {
364 // Handle serialized arrays
365 if (is_string($value) && is_serialized($value)) {
366 $value = maybe_unserialize($value);
367 }
368 // Cache the value
369 self::$settings[$key] = $value;
370
371 return self::applyEmailIdentityFallback($key, $value);
372 }
373
374 $fallback = $default ?? (self::$defaults[$key] ?? null);
375
376 return self::applyEmailIdentityFallback($key, $fallback);
377 }
378
379 /**
380 * Check if a boolean setting is enabled
381 *
382 * @param string $key Setting key
383 * @return bool
384 */
385 public static function isEnabled(string $key): bool
386 {
387 // Flexible payment settings require Pro module
388 if (self::isFlexiblePaymentSetting($key)) {
389 $value = apply_filters('yatra_flexible_payment_setting', false, $key);
390 return filter_var($value, FILTER_VALIDATE_BOOLEAN);
391 }
392
393 if (self::isScheduledPaymentSetting($key)) {
394 $defaults = self::scheduledPaymentDefaults();
395 $base = $defaults[$key] ?? false;
396 $value = apply_filters('yatra_scheduled_payment_setting', $base, $key);
397
398 return filter_var($value, FILTER_VALIDATE_BOOLEAN);
399 }
400
401 $value = self::get($key, false);
402 return filter_var($value, FILTER_VALIDATE_BOOLEAN);
403 }
404
405 /**
406 * Get a setting as integer
407 *
408 * @param string $key Setting key
409 * @param int $default Default value
410 * @return int
411 */
412 public static function getInt(string $key, int $default = 0): int
413 {
414 // Flexible payment settings require Pro module
415 if (self::isFlexiblePaymentSetting($key)) {
416 return (int) apply_filters('yatra_flexible_payment_setting', $default, $key);
417 }
418
419 if (self::isScheduledPaymentSetting($key)) {
420 $defaults = self::scheduledPaymentDefaults();
421 $base = $defaults[$key] ?? $default;
422
423 return (int) apply_filters('yatra_scheduled_payment_setting', $base, $key);
424 }
425
426 return (int) self::get($key, $default);
427 }
428
429 /**
430 * Get a setting as float
431 *
432 * @param string $key Setting key
433 * @param float $default Default value
434 * @return float
435 */
436 public static function getFloat(string $key, float $default = 0.0): float
437 {
438 return (float) self::get($key, $default);
439 }
440
441 /**
442 * Get a setting as string
443 *
444 * @param string $key Setting key
445 * @param string $default Default value
446 * @return string
447 */
448 public static function getString(string $key, string $default = ''): string
449 {
450 return (string) self::get($key, $default);
451 }
452
453 /**
454 * Load settings from database
455 * Settings are stored as individual options with yatra_ prefix
456 */
457 private static function load(): void
458 {
459 self::$settings = [];
460
461 // Load each setting from individual options
462 foreach (self::$defaults as $key => $default_value) {
463 $option_name = self::OPTION_PREFIX . $key;
464 $value = get_option($option_name, $default_value);
465
466 // Handle serialized arrays
467 if (is_string($value) && is_serialized($value)) {
468 $value = maybe_unserialize($value);
469 }
470
471 self::$settings[$key] = $value;
472 }
473
474 self::mergeAdminReviewOptionAliases();
475 }
476
477 /**
478 * REST/Settings UI uses yatra_require_booking, yatra_review_moderation, yatra_min_rating;
479 * internal helpers use require_booking_to_review, enable_review_moderation, minimum_rating.
480 */
481 private static function mergeAdminReviewOptionAliases(): void
482 {
483 $map = [
484 'require_booking' => 'require_booking_to_review',
485 'review_moderation' => 'enable_review_moderation',
486 'min_rating' => 'minimum_rating',
487 ];
488 foreach ($map as $adminKey => $internalKey) {
489 $v = get_option(self::OPTION_PREFIX . $adminKey, null);
490 if ($v !== null) {
491 self::$settings[$internalKey] = $v;
492 }
493 }
494 }
495
496 /**
497 * Reload settings (clear cache)
498 */
499 public static function reload(): void
500 {
501 self::$settings = null;
502 self::load();
503 }
504
505 /**
506 * Get default settings
507 *
508 * @return array
509 */
510 public static function getDefaults(): array
511 {
512 return self::$defaults;
513 }
514
515 // =========================================
516 // Convenience Methods for Common Settings
517 // =========================================
518
519 /**
520 * Check if reviews are enabled
521 */
522 public static function reviewsEnabled(): bool
523 {
524 return self::isEnabled('enable_reviews');
525 }
526
527 /**
528 * Check if booking is required for reviews
529 */
530 public static function requireBookingForReview(): bool
531 {
532 return self::isEnabled('require_booking_to_review');
533 }
534
535 /**
536 * Check if reviews auto-approve
537 */
538 public static function autoApproveReviews(): bool
539 {
540 return self::isEnabled('auto_approve_reviews');
541 }
542
543 /**
544 * Check if review moderation is enabled
545 */
546 public static function reviewModerationEnabled(): bool
547 {
548 return self::isEnabled('enable_review_moderation');
549 }
550
551 /**
552 * Get minimum rating allowed
553 */
554 public static function getMinimumRating(): int
555 {
556 return self::getInt('minimum_rating', 1);
557 }
558
559 /**
560 * Get currency settings
561 * Checks both 'currency' and 'default_currency' keys for compatibility
562 * (Admin UI Currency Settings saves as 'default_currency')
563 */
564 public static function getCurrency(): string
565 {
566 // Priority: 'currency' key first (Payment Settings), then 'default_currency' (Currency Settings)
567 $currency = self::getString('currency', '');
568 if (!empty($currency) && $currency !== 'USD') {
569 return $currency;
570 }
571
572 // Check default_currency (from Currency Settings section)
573 $defaultCurrency = self::getString('default_currency', '');
574 if (!empty($defaultCurrency)) {
575 return $defaultCurrency;
576 }
577
578 // Return whatever currency is set, even if USD
579 return !empty($currency) ? $currency : 'USD';
580 }
581
582 /**
583 * Get currency position (before/after)
584 */
585 public static function getCurrencyPosition(): string
586 {
587 return self::getString('currency_position', 'before');
588 }
589
590 /**
591 * Get trip base slug
592 */
593 public static function getTripBase(): string
594 {
595 $base = self::getString('trip_base', 'trip');
596 return preg_replace('/[^a-z0-9_-]/i', '', $base) ?: 'trip';
597 }
598
599 /**
600 * Get booking base slug
601 */
602 public static function getBookingBase(): string
603 {
604 $base = self::getString('booking_base', 'booking');
605 return preg_replace('/[^a-z0-9_-]/i', '', $base) ?: 'booking';
606 }
607
608 /**
609 * URL slug for the customer account area (Settings → Customer → account path).
610 * Derives from yatra_customer_account_page first so routing matches the configured path
611 * even when yatra_account_base was never saved or is out of sync.
612 */
613 public static function getAccountBase(): string
614 {
615 $customerPath = get_option('yatra_customer_account_page', '');
616 if (is_string($customerPath) && $customerPath !== '' && $customerPath !== '0') {
617 $slug = self::slugFromAccountPathString($customerPath);
618 if ($slug !== '') {
619 return $slug;
620 }
621 }
622
623 $base = self::getString('account_base', '');
624 $base = preg_replace('/[^a-z0-9_-]/i', '', $base) ?: '';
625
626 return $base !== '' ? $base : 'account';
627 }
628
629 private static function slugFromAccountPathString(string $path): string
630 {
631 $path = trim(str_replace('\\', '/', $path), '/');
632 $parts = array_values(array_filter(explode('/', $path), static fn ($p) => $p !== ''));
633 $segment = $parts !== [] ? end($parts) : 'account';
634 $slug = sanitize_title($segment);
635
636 return $slug !== '' ? $slug : 'account';
637 }
638
639 /**
640 * Check if using custom booking page
641 */
642 public static function useCustomBookingPage(): bool
643 {
644 return self::isEnabled('use_booking_page') && self::getInt('booking_page_id') > 0;
645 }
646
647 /**
648 * Get booking page ID
649 */
650 public static function getBookingPageId(): int
651 {
652 return self::getInt('booking_page_id', 0);
653 }
654
655 /**
656 * Check if guest booking is allowed
657 */
658 public static function guestBookingEnabled(): bool
659 {
660 return self::isEnabled('enable_guest_booking');
661 }
662
663 /**
664 * Wishlist (saved trips) is a Yatra Pro feature and must be enabled in settings.
665 */
666 public static function wishlistEnabled(): bool
667 {
668 if (!apply_filters('yatra_is_pro_active', false)) {
669 return false;
670 }
671
672 return self::isEnabled('enable_wishlist');
673 }
674
675 /**
676 * Trips per page on front-end listings (aligned with WordPress Reading "posts per page").
677 */
678 public static function getTripsPerPage(): int
679 {
680 if (function_exists('yatra_get_posts_per_page')) {
681 return yatra_get_posts_per_page();
682 }
683
684 return max(1, absint((int) get_option('posts_per_page', 10)));
685 }
686
687 /**
688 * Check if a setting key is a flexible payment setting (Pro feature)
689 *
690 * @param string $key Setting key
691 * @return bool
692 */
693 private static function isFlexiblePaymentSetting(string $key): bool
694 {
695 $flexiblePaymentSettings = [
696 'deposit_required',
697 'deposit_percentage',
698 'partial_payment',
699 'partial_payment_percentage',
700 'enable_deposit',
701 'allow_save_payment_methods',
702 ];
703
704 return in_array($key, $flexiblePaymentSettings, true);
705 }
706
707 /**
708 * Settings owned by Yatra Pro "Scheduled Payments" module (not core options).
709 *
710 * @return array<string, mixed>
711 */
712 private static function scheduledPaymentDefaults(): array
713 {
714 return [
715 'enable_scheduled_payments' => false,
716 'scheduled_payment_type' => 'single',
717 'scheduled_payment_days' => 15,
718 'scheduled_payment_installments' => 1,
719 'scheduled_payment_interval' => 30,
720 'scheduled_payment_reminder_days' => 3,
721 ];
722 }
723
724 private static function isScheduledPaymentSetting(string $key): bool
725 {
726 return array_key_exists($key, self::scheduledPaymentDefaults());
727 }
728
729 /**
730 * Check if flexible payments module is available (Pro active + module enabled)
731 *
732 * @return bool
733 */
734 public static function isFlexiblePaymentsAvailable(): bool
735 {
736 return apply_filters('yatra_flexible_payments_enabled', false);
737 }
738
739 /**
740 * Global payment test/sandbox toggle (Settings → Payment).
741 */
742 public static function isPaymentTestMode(): bool
743 {
744 return self::isEnabled('payment_test_mode');
745 }
746 }
747
748