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/ItineraryPdfBuilder.php +40 -9 3.0.5 → 3.0.16 View file →
@@ -75,15 +75,32 @@
75 75 $bookingDate = $createdAt !== '' ? date_i18n(get_option('date_format'), strtotime($createdAt)) : '';
76 76 $travelRaw = (string) ($source['travel_date'] ?? '');
77 77 $travelDate = $travelRaw !== '' ? date_i18n(get_option('date_format'), strtotime($travelRaw)) : '';
78 78
79 + // Departure / return date. The booking already stores the real
80 + // trip end (`end_date`, written at booking time from the selected
81 + // departure or start + duration), so prefer that authoritative
82 + // value rather than re-deriving one — this is what keeps the
83 + // travel timeline showing the ACTUAL booked end date instead of
84 + // repeating the arrival date. Only when no stored end_date exists
85 + // do we derive it, and then the SAME way
86 + // BookingRepository::calculateEndDate does: start + (duration_days
87 + // - 1). A 5-day trip therefore ends on day 5, not day 6 — the old
88 + // "+ duration_days" was off by one and implied an extra night.
79 89 $returnDate = '';
80 - if ($travelRaw !== '' && $trip && !empty($trip->duration)) {
81 - $returnDate = date_i18n(
82 - get_option('date_format'),
83 - strtotime($travelRaw . ' +' . (int) $trip->duration . ' days')
90 + $endRaw = (string) ($source['end_date'] ?? '');
91 + if ($endRaw === '' && $travelRaw !== '' && $trip && (int) ($trip->duration_days ?? 0) > 1) {
92 + $endRaw = date(
93 + 'Y-m-d',
94 + strtotime($travelRaw . ' +' . ((int) $trip->duration_days - 1) . ' days')
84 95 );
85 96 }
97 + // Expose a return date only when it genuinely differs from the
98 + // arrival date. Single-day bookings store end_date == start_date,
99 + // so the timeline renders one item instead of two identical dates.
100 + if ($endRaw !== '' && $endRaw !== $travelRaw) {
101 + $returnDate = date_i18n(get_option('date_format'), strtotime($endRaw));
102 + }
86 103
87 104 $statusRaw = strtolower((string) ($source['booking_status'] ?? $source['status'] ?? ''));
88 105 $statusClass = in_array($statusRaw, ['confirmed', 'completed', 'success'], true)
89 106 ? 'confirmed'
@@ -104,8 +121,9 @@
104 121
105 122 $templateData = [
106 123 'company_name' => SettingsService::get('company_name', get_bloginfo('name')),
107 124 'company_address' => SettingsService::get('company_address', ''),
125 + 'company_address_lines' => \Yatra\Helpers\FormatHelper::companyAddressLines(),
108 126 'company_email' => SettingsService::get('company_email', get_option('admin_email')),
109 127 'company_phone' => SettingsService::get('company_phone', ''),
110 128 'customer_name' => $customerName,
111 129 'customer_email' => (string) ($source['contact_email'] ?? $source['customer_email'] ?? ''),
@@ -114,10 +132,18 @@
114 132 'booking_status' => ucfirst($statusRaw !== '' ? $statusRaw : 'pending'),
115 133 'status_class' => $statusClass,
116 134 'trip_title' => $trip ? ((string) ($trip->title ?? $tripFallbackTitle)) : $tripFallbackTitle,
117 135 'trip_description'=> $trip ? (string) ($trip->description ?? $trip->content ?? '') : '',
118 - /* translators: %d: trip duration in days. */
119 - 'trip_duration' => ($trip && !empty($trip->duration)) ? sprintf(__('%d days', 'yatra'), (int) $trip->duration) : '',
136 + // Duration is duration_days/duration_nights (no `duration` column).
137 + 'trip_duration' => $trip
138 + ? yatra_format_duration(
139 + (int) ($trip->duration_days ?? 0),
140 + isset($trip->duration_nights) ? (int) $trip->duration_nights : null,
141 + // Hour-based day tours: "8 hours" instead of "1 day". Absent
142 + // or NULL on every day-based trip, which keeps its wording.
143 + (int) ($trip->duration_hours ?? 0)
144 + )
145 + : '',
120 146 'trip_difficulty' => $trip ? (string) ($trip->difficulty_name ?? '') : '',
121 147 'trip_highlights' => $trip ? ($trip->highlights ?? $trip->trip_highlights ?? '') : '',
122 148 'trip_includes' => $trip ? ($trip->includes ?? $trip->trip_includes ?? '') : '',
123 149 'trip_excludes' => $trip ? ($trip->excludes ?? $trip->trip_excludes ?? '') : '',
@@ -125,11 +151,11 @@
125 151 'destination' => $trip ? (string) ($trip->destination ?? '') : (string) ($source['destination'] ?? ''),
126 152 'travel_date' => $travelDate,
127 153 'return_date' => $returnDate,
128 154 'currency_symbol' => FormatHelper::getCurrencySymbol($currency),
129 - 'total_amount' => number_format((float) ($source['total_amount'] ?? 0), 2),
130 - 'amount_paid' => number_format((float) ($source['amount_paid'] ?? 0), 2),
131 - 'amount_due' => number_format((float) ($source['amount_due'] ?? 0), 2),
155 + 'total_amount' => yatra_format_price((float) ($source['total_amount'] ?? 0), $currency, false),
156 + 'amount_paid' => yatra_format_price((float) ($source['amount_paid'] ?? 0), $currency, false),
157 + 'amount_due' => yatra_format_price((float) ($source['amount_due'] ?? 0), $currency, false),
132 158 'traveler_count' => (int) ($source['travelers_count'] ?? $source['traveler_count'] ?? $source['travelers'] ?? 1),
133 159 'itinerary_days' => $itineraryDays,
134 160 // Real trip-specific Important Information fields, same
135 161 // ones the single-trip page surfaces in its "Important
@@ -175,8 +201,13 @@
175 201 'trip_id' => $payment->trip_id ?? 0,
176 202 'booking_id' => $payment->booking_id ?? 0,
177 203 'created_at' => $payment->created_at ?? null,
178 204 'travel_date' => $payment->travel_date ?? null,
205 + // Actual booked trip range — used for the arrival/departure
206 + // timeline. Null-safe: build() falls back to a correct
207 + // derivation when the joined record doesn't carry these.
208 + 'start_date' => $payment->start_date ?? null,
209 + 'end_date' => $payment->end_date ?? null,
179 210 // Use the BOOKING status, not the payment status. Payment
180 211 // status can be "completed" while the booking itself is
181 212 // still "pending" admin confirmation — the itinerary
182 213 // header should reflect the booking, not the transaction.