| @@ -259,8 +259,11 @@ | ||
| 259 | 259 | 'trip_id' => (int) $request->get_param('trip_id'), |
| 260 | 260 | 'search' => $request->get_param('search') ?: '', |
| 261 | 261 | 'date_from' => $request->get_param('date_from') ?: '', |
| 262 | 262 | 'date_to' => $request->get_param('date_to') ?: '', |
| 263 | + // Column sorting from the table headers — whitelisted in the repository. | |
| 264 | + 'orderby' => $request->get_param('orderby') ?: '', | |
| 265 | + 'order' => $request->get_param('order') ?: '', | |
| 263 | 266 | ]; |
| 264 | 267 | |
| 265 | 268 | // Delegate to service |
| 266 | 269 | $result = $this->bookingService->getBookings($filters); |
| @@ -359,9 +362,9 @@ | ||
| 359 | 362 | return $this->error_response($result['message'] ?? 'Failed to update booking', 400); |
| 360 | 363 | } |
| 361 | 364 | |
| 362 | 365 | Logger::info("Booking updated successfully", ['booking_id' => $id]); |
| 363 | - return $this->success_response($result['data']); | |
| 366 | + return $this->success_response($result['data'] ?? null); | |
| 364 | 367 | |
| 365 | 368 | } catch (\Exception $e) { |
| 366 | 369 | Logger::error("Failed to update booking", ['booking_id' => $id ?? 0, 'data' => $data ?? [], 'error' => $e->getMessage()]); |
| 367 | 370 | return $this->handle_exception($e); |
| @@ -778,11 +781,21 @@ | ||
| 778 | 781 | $bookingDate = !empty($createdAt) ? date_i18n(get_option('date_format'), strtotime((string) $createdAt)) : ''; |
| 779 | 782 | $travelDateRaw = $booking['travel_date'] ?? ''; |
| 780 | 783 | $travelDate = !empty($travelDateRaw) ? date_i18n(get_option('date_format'), strtotime((string) $travelDateRaw)) : ''; |
| 781 | 784 | |
| 785 | + // Return date. Prefer the booking's STORED end_date — the actual booked | |
| 786 | + // return (accounts for a flexible window or a trip duration changed after | |
| 787 | + // booking). Fall back to the trip duration only when no end is stored: | |
| 788 | + // duration_days is INCLUSIVE, so the return is travel_date + (days - 1) | |
| 789 | + // (matches BookingRepository::calculateEndDate; a bare "+ duration_days" | |
| 790 | + // was one day too far and implied an extra night — see ItineraryPdfBuilder). | |
| 782 | 791 | $returnDate = ''; |
| 783 | - if (!empty($travelDateRaw) && $trip && !empty($trip->duration)) { | |
| 784 | - $returnTimestamp = strtotime((string) $travelDateRaw . ' +' . (int) $trip->duration . ' days'); | |
| 792 | + $storedEnd = (string) ($booking['end_date'] ?? ''); | |
| 793 | + if ($storedEnd !== '' && ($travelDateRaw === '' || $storedEnd >= $travelDateRaw)) { | |
| 794 | + $returnDate = date_i18n(get_option('date_format'), strtotime($storedEnd)); | |
| 795 | + } elseif (!empty($travelDateRaw) && $trip && !empty($trip->duration_days)) { | |
| 796 | + $returnOffset = max(0, (int) $trip->duration_days - 1); | |
| 797 | + $returnTimestamp = strtotime((string) $travelDateRaw . ' +' . $returnOffset . ' days'); | |
| 785 | 798 | $returnDate = date_i18n(get_option('date_format'), $returnTimestamp); |
| 786 | 799 | } |
| 787 | 800 | |
| 788 | 801 | $statusRaw = (string) ($booking['booking_status'] ?? $booking['status'] ?? ''); |
| @@ -795,12 +808,14 @@ | ||
| 795 | 808 | |
| 796 | 809 | $templateData = [ |
| 797 | 810 | 'company_name' => $companyName, |
| 798 | 811 | 'company_address' => $companyAddress, |
| 812 | + 'company_address_lines' => \Yatra\Helpers\FormatHelper::companyAddressLines(), | |
| 799 | 813 | 'company_email' => $companyEmail, |
| 800 | 814 | 'company_phone' => $companyPhone, |
| 801 | 815 | 'customer_name' => $customerName, |
| 802 | 816 | 'customer_email' => (string) ($booking['contact_email'] ?? $booking['customer_email'] ?? ''), |
| 817 | + 'customer_address_lines' => FormatHelper::customerAddressLines($booking), | |
| 803 | 818 | 'booking_ref' => $bookingRef, |
| 804 | 819 | 'booking_date' => $bookingDate, |
| 805 | 820 | 'booking_status' => ucfirst($statusRaw ?: 'pending'), |
| 806 | 821 | 'status_class' => in_array(strtolower($statusRaw), ['confirmed', 'completed', 'success'], true) ? 'confirmed' : |
| @@ -805,10 +820,19 @@ | ||
| 805 | 820 | 'booking_status' => ucfirst($statusRaw ?: 'pending'), |
| 806 | 821 | 'status_class' => in_array(strtolower($statusRaw), ['confirmed', 'completed', 'success'], true) ? 'confirmed' : |
| 807 | 822 | (in_array(strtolower($statusRaw), ['cancelled'], true) ? 'cancelled' : 'pending'), |
| 808 | 823 | 'trip_title' => $trip ? ($trip->title ?? $booking['trip_title'] ?? __('Trip Booking', 'yatra')) : ($booking['trip_title'] ?? __('Trip Booking', 'yatra')), |
| 809 | - /* translators: %d: trip duration in days. */ | |
| 810 | - 'trip_duration' => $trip && $trip->duration ? sprintf(__('%d days', 'yatra'), (int) $trip->duration) : '', | |
| 824 | + // Trip duration comes from duration_days/duration_nights (there is no | |
| 825 | + // `duration` column — accessing it caused a blank value + PHP notice). | |
| 826 | + 'trip_duration' => $trip | |
| 827 | + ? yatra_format_duration( | |
| 828 | + (int) ($trip->duration_days ?? 0), | |
| 829 | + isset($trip->duration_nights) ? (int) $trip->duration_nights : null, | |
| 830 | + // Hour-based day tours: "8 hours" instead of "1 day". Absent | |
| 831 | + // or NULL on every day-based trip, which keeps its wording. | |
| 832 | + (int) ($trip->duration_hours ?? 0) | |
| 833 | + ) | |
| 834 | + : '', | |
| 811 | 835 | 'trip_difficulty' => $trip ? ($trip->difficulty_name ?? '') : '', |
| 812 | 836 | 'departure_location' => $trip ? ($trip->departure_location ?? '') : '', |
| 813 | 837 | 'destination' => $trip ? ($trip->destination ?? '') : '', |
| 814 | 838 | 'travel_date' => $travelDate, |
| @@ -813,11 +837,11 @@ | ||
| 813 | 837 | 'destination' => $trip ? ($trip->destination ?? '') : '', |
| 814 | 838 | 'travel_date' => $travelDate, |
| 815 | 839 | 'return_date' => $returnDate, |
| 816 | 840 | 'currency_symbol' => $currencySymbol, |
| 817 | - 'total_amount' => number_format((float) ($booking['total_amount'] ?? 0), 2), | |
| 818 | - 'amount_paid' => number_format((float) ($booking['amount_paid'] ?? 0), 2), | |
| 819 | - 'amount_due' => number_format((float) ($booking['amount_due'] ?? 0), 2), | |
| 841 | + 'total_amount' => yatra_format_price((float) ($booking['total_amount'] ?? 0), $currency, false), | |
| 842 | + 'amount_paid' => yatra_format_price((float) ($booking['amount_paid'] ?? 0), $currency, false), | |
| 843 | + 'amount_due' => yatra_format_price((float) ($booking['amount_due'] ?? 0), $currency, false), | |
| 820 | 844 | 'traveler_count' => (int) ($booking['travelers_count'] ?? $booking['travelers'] ?? 1), |
| 821 | 845 | ]; |
| 822 | 846 | |
| 823 | 847 | $pdfService = new PdfService(); |