PluginProbe
Yatra – Travel Booking & Tour Operator Software / 3.0.16
Yatra – Travel Booking & Tour Operator Software v3.0.16
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
← All changes | app/Services/RecurringAvailabilityService.php +85 -4 3.0.6 → 3.0.16 View file →
@@ -350,9 +350,9 @@
350 350 }
351 351
352 352 if (in_array($dayOfWeek, $targetDays, true)) {
353 353 // Check if not excluded
354 - if (!in_array($dateStr, $excludedDates, true)) {
354 + if (!$this->isDateExcluded($dateStr, $excludedDates)) {
355 355 // Check cutoff
356 356 if ($this->isBookable($current, $rule)) {
357 357 $generatedDates = $this->createAvailabilityFromRule($rule, $dateStr, $dayOfWeek);
358 358 $dates = array_merge($dates, $generatedDates);
@@ -408,9 +408,9 @@
408 408
409 409 // Check if within range
410 410 if ($targetTimestamp >= strtotime($fromDate) && $targetTimestamp <= $end) {
411 411 // Check if not excluded
412 - if (!in_array($targetDate, $excludedDates, true)) {
412 + if (!$this->isDateExcluded($targetDate, $excludedDates)) {
413 413 // Check cutoff
414 414 if ($this->isBookable($targetTimestamp, $rule)) {
415 415 $generatedDates = $this->createAvailabilityFromRule($rule, $targetDate, $dayOfWeek);
416 416 $dates = array_merge($dates, $generatedDates);
@@ -489,9 +489,9 @@
489 489 $dayOfWeek = (int) date('w', $current);
490 490 $month = (int) date('n', $current); // 1-12
491 491
492 492 if (empty($selectedMonths) || in_array($month, $selectedMonths, true)) {
493 - if (!in_array($dateStr, $excludedDates, true)) {
493 + if (!$this->isDateExcluded($dateStr, $excludedDates)) {
494 494 if ($this->isBookable($current, $rule)) {
495 495 $generatedDates = $this->createAvailabilityFromRule($rule, $dateStr, $dayOfWeek);
496 496 $dates = array_merge($dates, $generatedDates);
497 497 }
@@ -659,13 +659,94 @@
659 659
660 660 /**
661 661 * Preview generated dates (for admin UI)
662 662 */
663 + /**
664 + * Has the operator explicitly closed this date on any of the trip's active
665 + * rules — a holiday, or a period such as a business vacation?
666 + *
667 + * Only answers for dates the operator deliberately listed. A date that is
668 + * simply not generated by a rule (a Tuesday on a Mon/Wed/Fri pattern) is
669 + * not "excluded" and is left to the rest of the resolution chain.
670 + */
671 + public function isDateExcludedForTrip(int $tripId, string $date): bool
672 + {
673 + if ($tripId < 1 || $date === '') {
674 + return false;
675 + }
676 +
677 + foreach ($this->repository->getActiveRulesForDateRange($tripId, $date, $date) as $rule) {
678 + if ($this->isDateExcluded($date, $rule->excluded_dates ?? [])) {
679 + return true;
680 + }
681 + }
682 +
683 + return false;
684 + }
685 +
686 + /**
687 + * Is this date excluded by the rule?
688 + *
689 + * An entry in `excluded_dates` is either a single 'Y-m-d' string (what the
690 + * admin has always been able to add one day at a time) or an inclusive
691 + * period ['start' => 'Y-m-d', 'end' => 'Y-m-d'] — a business vacation or
692 + * seasonal closure, added in one go instead of day by day.
693 + *
694 + * Both shapes share the one column so existing rules keep working
695 + * untouched: a stored list of plain strings behaves exactly as before.
696 + * Dates are ISO, so plain string comparison is chronological.
697 + *
698 + * @param string $date Date being generated, 'Y-m-d'.
699 + * @param mixed $excluded Stored exclusions (a list; anything else = none).
700 + */
701 + public function isDateExcluded(string $date, $excluded): bool
702 + {
703 + if (!is_array($excluded)) {
704 + return false;
705 + }
706 +
707 + foreach ($excluded as $entry) {
708 + if (is_string($entry)) {
709 + if ($entry === $date) {
710 + return true;
711 + }
712 +
713 + continue;
714 + }
715 +
716 + if (!is_array($entry)) {
717 + continue;
718 + }
719 +
720 + $start = isset($entry['start']) ? (string) $entry['start'] : '';
721 + $end = isset($entry['end']) ? (string) $entry['end'] : '';
722 +
723 + if ($start === '' || $end === '') {
724 + continue;
725 + }
726 +
727 + // Tolerate a reversed period rather than silently ignoring it.
728 + if ($start > $end) {
729 + [$start, $end] = [$end, $start];
730 + }
731 +
732 + if ($date >= $start && $date <= $end) {
733 + return true;
734 + }
735 + }
736 +
737 + return false;
738 + }
739 +
663 740 public function previewDates(array $ruleData, int $limit = 20): array
664 741 {
665 742 // Create a temporary rule object
666 743 $rule = (object) $ruleData;
667 - $rule->excluded_dates = $rule->excluded_dates ?? [];
744 + // Normalise once: a malformed value (e.g. a bare string from a
745 + // hand-rolled API call) must not reach count() below as a fatal.
746 + $rule->excluded_dates = is_array($rule->excluded_dates ?? null)
747 + ? $rule->excluded_dates
748 + : [];
668 749 $rule->day_overrides = $rule->day_overrides ?? [];
669 750 $rule->days_of_week_array = isset($rule->days_of_week)
670 751 ? (is_array($rule->days_of_week) ? $rule->days_of_week : array_map('intval', explode(',', (string) $rule->days_of_week)))
671 752 : [];