mein-sterntours/app/Http/Controllers/BookingController.php
Phase-1-Rollback-Agent e3dc1afd8e WIP: Sicherheitsnetz vor Phase-1-R\u00fcckbau
Enth\u00e4lt gemischt: Laravel-10-Upgrade + Phase 1 (Contacts-Modul, Duplicats-Commands,
Soft-Delete+Merge-Fields) + Phase 2 Code-Umstellungen (inquiry_id, $table='contacts'/'inquiries')
+ Offers-Modul (Migrationen, Models, offer_id in Booking, offer-Disk in filesystems.php).

Phase 2 + Offers werden im folgenden Commit nach dev/backups/phase2-offers-2026-04-17/
verschoben, damit der Workspace auf Phase-1-only (= Test-System-Stand) reduziert ist
und direkt auf Live deploybar wird.

Tarball-Backup zus\u00e4tzlich unter: ../backups-safety/workspace-pre-phase1-rollback-2026-04-17.tar.gz

Made-with: Cursor
2026-04-17 13:40:31 +00:00

599 lines
26 KiB
PHP
Executable file

<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\Booking;
use App\Models\BookingFile;
use App\Models\Participant;
use App\Models\BookingNotice;
use App\Models\TravelCompany;
use App\Models\ServiceProvider;
use App\Models\BookingDraftItem;
use App\Models\BookingServiceItem;
use App\Models\ServiceProviderEntry;
use App\Repositories\DraftRepository;
use App\Repositories\BookingRepository;
use App\Repositories\CustomerRepository;
use App\Repositories\BookingPDFRepository;
use App\Repositories\BookingFileRepository;
use App\Repositories\CustomerFileRepository;
use App\Repositories\CustomerMailRepository;
class BookingController extends Controller
{
protected $bookingRepo;
protected $custRepo;
public function __construct(BookingRepository $bookingRepo, CustomerRepository $custRepo)
{
$this->middleware(['admin', '2fa']);
$this->bookingRepo = $bookingRepo;
$this->custRepo = $custRepo;
}
public function index($step = false)
{
$data = [
//'bookings' => Booking::all()->sortByDesc("id"),
'step' => $step
];
return view('booking.index', $data);
}
public function detail($id)
{
if ($id == "new") {
$booking = new Booking();
$id = 'new';
} else {
$booking = Booking::findOrFail($id);
$booking->getPassolutionPDF(true);
$id = $booking->id;
}
$data = [
'booking' => $booking,
'id' => $id,
'show_modal_quill_preview' => true,
];
return view('booking.detail', $data);
}
public function store(Request $request, $id)
{
$data = $request->all();
if ($id === "new") {
$booking = new Booking();
} else {
$booking = Booking::findOrFail($id);
}
if ($data['action'] === 'convertArrangementsToDrafts') {
if (!$booking->arrangements || $booking->arrangements->count() == 0) {
\Session()->flash('alert-warning', __('Keine Arrangements zum Konvertieren vorhanden'));
return redirect(route('booking_detail', [$booking->id]) . "#collapseBookingOrganisation");
}
$this->bookingRepo->convertArrangementsToDrafts($booking);
\Session()->flash('alert-success', __('Arrangements wurden erfolgreich in die neue Draft-Struktur übernommen'));
return redirect(route('booking_detail', [$booking->id]) . "#collapseBookingOrganisation");
}
if ($data['action'] === 'loadDraftToBooking') {
if (!isset($data['draft_id']) || !$data['draft_id']) {
\Session()->flash('alert-error', __('Keine Vorlage ausgewählt'));
return redirect(route('booking_detail', [$booking->id]) . "#collapseBookingOrganisation");
}
$this->bookingRepo->loadDraftToBooking($booking->id, $data['draft_id']);
\Session()->flash('alert-success', __('Vorlage wurde erfolgreich geladen'));
return redirect(route('booking_detail', [$booking->id]) . "#collapseBookingOrganisation");
}
if ($data['action'] === 'deleteAllChecked') {
if (!isset($data['draft_item_delete']) || !$data['draft_item_delete']) {
\Session()->flash('alert-error', 'Es wurden keine Leistungen ausgewählt');
return redirect(route('booking_detail', [$booking->id]) . "#collapseBookingOrganisation");
}
foreach ($data['draft_item_delete'] as $draft_item_delete_id => $v) {
$booking_draft_item = BookingDraftItem::findOrFail($draft_item_delete_id);
if ($booking_draft_item->booking_id === $booking->id) {
$booking_draft_item->delete();
}
}
$booking->calculate_price_total();
return redirect(route('booking_detail', [$booking->id]) . "#collapseBookingOrganisation");
}
if ($data['action'] === 'save_notice') {
$booking = $this->bookingRepo->updateNotice($id, $data);
\Session()->flash('alert-save', '1');
return redirect(route('booking_detail', [$booking->id]) . "#collapseBookingNotice");
}
if ($data['action'] === 'edit_notice') {
$booking = $this->bookingRepo->updateNotice($id, $data);
\Session()->flash('alert-save', '1');
return redirect(route('booking_detail', [$booking->id]) . "#collapseBookingNotice");
}
if (strpos($data['action'], 'createPDF') !== false) {
$bookingPDF = new BookingPDFRepository($booking);
$bookingPDF->createPDF($id, $data);
\Session()->flash('alert-success', 'PDF Datei erstellt');
return redirect(route('booking_detail', [$booking->id]) . "#collapseBookingFiles");
}
$redirect = route('booking_detail', [$booking->id]);
$i = 1;
if ($data['action'] === 'addItemUp') {
$travel_program_id = null;
$request_date = null;
$comfort = 0;
if (count($booking->booking_draft_items)) {
$first_booking_draft_item = $booking->booking_draft_items()->first();
$travel_program_id = $first_booking_draft_item->travel_program_id;
$request_date = $first_booking_draft_item->request_date;
$comfort = $first_booking_draft_item->comfort;
}
$add_draft_items_up_number = isset($data['add_draft_items_up_number']) ? intval($data['add_draft_items_up_number']) : 1;
for ($j = 0; $j < $add_draft_items_up_number; $j++) {
$booking->booking_draft_items()->create([
'booking_id' => $booking->id,
'travel_program_id' => $travel_program_id,
'fewo_lodging_id' => null,
'travel_class_id' => null,
'draft_item_id' => null,
'draft_type_id' => null,
'request_date' => $request_date,
'days_start' => null,
'days_duration' => null,
'start_date' => null,
'end_date' => null,
'service' => '',
'price_adult' => null,
'adult' => null,
'price_children' => 0,
'children' => 0,
'price' => 0,
'pos' => $i,
'in_pdf' => true,
'comfort' => $comfort
]);
$i++;
}
$redirect = redirect(route('booking_detail', [$booking->id]) . "#collapseBookingOrganisation");
}
if (isset($data['draft_item'])) {
foreach ($data['draft_item'] as $booking_draft_item_id => $draft_item) {
$BookingDraftItem = BookingDraftItem::findOrFail($booking_draft_item_id);
$draft_item['price_adult'] = isset($draft_item['price_adult']) ? $draft_item['price_adult'] : null;
$draft_item['adult'] = isset($draft_item['adult']) ? $draft_item['adult'] : null;
$draft_item['price_children'] = isset($draft_item['price_children']) ? $draft_item['price_children'] : null;
$draft_item['children'] = isset($draft_item['children']) ? $draft_item['children'] : null;
$draft_item['price'] = isset($draft_item['price']) ? $draft_item['price'] : null;
$draft_item['pos'] = $i++;
$draft_item['in_pdf'] = isset($draft_item['in_pdf']) ? true : false;
$BookingDraftItem->fill($draft_item);
$BookingDraftItem->save();
}
}
if ($data['action'] === 'addItemDown') {
$travel_program_id = null;
$request_date = null;
$comfort = 0;
if (count($booking->booking_draft_items)) {
$first_booking_draft_item = $booking->booking_draft_items()->first();
$travel_program_id = $first_booking_draft_item->travel_program_id;
$request_date = $first_booking_draft_item->request_date;
$comfort = $first_booking_draft_item->comfort;
}
$add_draft_items_up_number = isset($data['add_draft_items_down_number']) ? intval($data['add_draft_items_down_number']) : 1;
for ($j = 0; $j < $add_draft_items_up_number; $j++) {
$booking->booking_draft_items()->create([
'booking_id' => $booking->id,
'travel_program_id' => $travel_program_id,
'fewo_lodging_id' => null,
'travel_class_id' => null,
'draft_item_id' => null,
'draft_type_id' => null,
'request_date' => $request_date,
'days_start' => null,
'days_duration' => null,
'start_date' => null,
'end_date' => null,
'service' => '',
'price_adult' => null,
'adult' => null,
'price_children' => 0,
'children' => 0,
'price' => 0,
'pos' => $i,
'in_pdf' => true,
'comfort' => $comfort
]);
$i++;
}
$redirect = redirect(route('booking_detail', [$booking->id]) . "#collapseBookingOrganisation");
}
if (
$data['action'] === 'saveCustomer' || $data['action'] === 'saveAll' || $data['action'] === 'save_lead_status' || $data['action'] === 'update_booking' ||
$data['action'] === 'update_booking_services' || $data['action'] === 'update_booking_number' || $data['action'] === 'update_booking_price' ||
$data['action'] === 'update_service_provider_entry' || $data['action'] === 'update_booking_service_item' || $data['action'] === 'update_booking_participant'
) {
$customer = $this->custRepo->updateCustomerFromBooking($id, $data);
$booking = $this->bookingRepo->updateLeadStatus($id, $data);
$booking = $this->bookingRepo->updateBooking($id, $data);
$booking = $this->bookingRepo->updateBookingServices($id, $data);
$booking = $this->bookingRepo->updateBookingNumber($id, $data);
$booking = $this->bookingRepo->updateBookingPrice($id, $data);
$booking = $this->bookingRepo->updateServiceProviderEntry($id, $data);
$booking = $this->bookingRepo->updateBookingServiceItem($id, $data);
$booking = $this->bookingRepo->updateBookingParticipant($id, $data);
\Session()->flash('alert-save', '1');
switch ($data['action']) {
case 'saveCustomer':
$redirect = redirect(route('booking_detail', [$booking->id]) . "#collapseBookingCustomer");
break;
case 'saveAll':
$redirect = redirect(route('booking_detail', [$booking->id]) . "#collapseBookingOrganisation");
break;
case 'update_booking':
$redirect = redirect(route('booking_detail', [$booking->id]) . "#collapseBookingBooking");
break;
case 'save_lead_status':
$redirect = redirect(route('booking_detail', [$booking->id]) . "#collapseBookingLead");
break;
case 'update_booking_services':
$redirect = redirect(route('booking_detail', [$booking->id]) . "#collapseBookingServices");
break;
case 'update_booking_number':
$redirect = redirect(route('booking_detail', [$booking->id]) . "#collapseBookingMyJack");
break;
case 'update_booking_price':
$redirect = redirect(route('booking_detail', [$booking->id]) . "#collapseBookingPrice");
break;
case 'update_service_provider_entry':
$redirect = redirect(route('booking_detail', [$booking->id]) . "#collapseBookingProvider");
break;
case 'update_booking_service_item':
$redirect = redirect(route('booking_detail', [$booking->id]) . "#collapseBookingCompany");
break;
case 'update_booking_participant':
$redirect = redirect(route('booking_detail', [$booking->id]) . "#collapseBookingParticipant");
break;
}
}
$booking->calculate_price_total();
if (strpos($data['action'], 'up_') !== false) {
$reId = intval(str_replace('up_', '', $data['action']));
$d_from = BookingDraftItem::findOrFail($reId);
$d_to = $booking->findBeforeDraftItemRelation($reId);
if ($d_to) {
$t_pos = $d_from->pos;
$d_from->pos = $d_to->pos;
$d_to->pos = $t_pos;
$d_from->save();
$d_to->save();
}
}
if (strpos($data['action'], 'down_') !== false) {
$reId = intval(str_replace('down_', '', $data['action']));
$d_from = BookingDraftItem::findOrFail($reId);
$d_to = $booking->findAfterDraftItemRelation($reId);
if ($d_to) {
$t_pos = $d_from->pos;
$d_from->pos = $d_to->pos;
$d_to->pos = $t_pos;
$d_from->save();
$d_to->save();
}
}
\Session()->flash('alert-save', '1');
return $redirect;
}
public function loadModal(Request $request)
{
$data = $request->all();
$ret = "";
if ($request->ajax()) {
if ($data['action'] === "new-customer-mail" || $data['action'] === "reply-customer-mail" || $data['action'] === "show-customer-mail" || $data['action'] === "edit-customer-mail") {
$data['customers'] = [];
if ($data['action'] === "new-customer-mail" && isset($data['booking_id']) && $booking = Booking::find($data['booking_id'])) {
$tmp = [];
$tmp['email'] = $booking->customer ? $booking->customer->email : "";
$tmp['name'] = $booking->customer ? $booking->customer->firstname . " " . $booking->customer->name . " | " : "- | ";
$tmp['name'] .= $booking->travel_country_id ? $booking->travel_country->name . " | " : "- | ";
$tmp['name'] .= $booking->travelagenda_id ? $booking->travel_agenda->name . "" : "-";
$data['customers'][$booking->id] = $tmp;
}
$ret = CustomerMailRepository::loadModal($data);
}
if ($data['action'] === "modal-upload-booking-file") {
$ret = view("booking.upload_modal", compact('data'))->render();
}
if ($data['action'] === "edit_notice") {
$value = BookingNotice::findOrFail($data['id']);
$ret = view("booking.edit_notice_modal", compact('data', 'value'))->render();
}
if ($data['action'] === "createPDF_Coupon") {
$booking = Booking::findOrFail($data['booking_id']);
$data['has_coupon'] = $booking->hasDocument('coupon');
$data['default_value'] = config('booking.coupon_default_value');
$data['issue_date'] = date('d.m.Y');
$data['valid_date'] = \Carbon::now()->addMonths(config('booking.coupon_valid_date_month'))->format('d.m.Y');
$ret = view("booking.modal_create_coupon", compact('data'))->render();
}
if ($data['action'] === "createPDF_Storno") {
$booking = Booking::findOrFail($data['booking_id']);
$data['price'] = $booking->price;
if ($data['has_storno'] = $booking->hasDocument('storno')) {
$document_storno = $booking->getDocument('storno');
$data['storno_date'] = \Carbon::parse($document_storno->data->storno_date)->format('d.m.Y');
$data['storno_print'] = \Carbon::parse($document_storno->data->storno_print)->format('d.m.Y');
$data['storno_status_id'] = $document_storno->data->storno_status_id;
$data['storno_level'] = $document_storno->data->storno_level;
$data['storno_level_number'] = _number_format($document_storno->data->storno_level);
$data['storno_total_price'] = '';
} else {
$data['storno_date'] = date('d.m.Y');
$data['storno_print'] = date('d.m.Y');
$data['storno_status_id'] = null;
$data['storno_level'] = 100;
$data['storno_level_number'] = '';
$data['storno_total_price'] = '';
}
$ret = view("booking.modal_create_storno", compact('data'))->render();
}
if ($data['action'] === "upload-booking-file") {
if ($data['booking_id']) {
$bookingFileRepo = new BookingFileRepository(new BookingFile());
$bookingFileRepo->_set('disk', 'booking');
$bookingFileRepo->_set('booking_id', $data['booking_id']);
$bookingFileRepo->_set('dir', '/files/' . date('Y/m') . '/');
$bookingFileRepo->_set('identifier', 'booking');
return $bookingFileRepo->uploadFile($request->all());
}
}
}
return response()->json(['response' => $data, 'html' => $ret]);
}
public function draftItemDelete($id)
{
$booking_draft_item = BookingDraftItem::findOrFail($id);
$booking = $booking_draft_item->booking;
$booking_draft_item->delete();
$booking->calculate_price_total();
\Session()->flash('alert-success', __('Eintrag gelöscht'));
return redirect(route('booking_detail', [$booking->id]) . "#collapseBookingOrganisation");
}
public function action(Request $request, $action, $id = false)
{
if (!$booking = Booking::find($id)) {
abort(404);
}
if ($action === 'change_travel_dates') {
$draftRepo = new DraftRepository($booking);
$draftRepo->change_dates_drafts_from_booking($request->get('change_travel_start_date'));
\Session()->flash('alert-success', __('Datum der Reise wurde geändert'));
return redirect(route('booking_detail', [$booking->id]) . "#collapseBookingOrganisation");
}
if ($action === 'service_provider_entry_add_discount') {
$ServiceProvider = ServiceProvider::where('type', 'discount')->where('active', true)->first();
ServiceProviderEntry::create([
'booking_id' => $booking->id,
'service_provider_id' => $ServiceProvider->id,
'type' => 'discount',
]);
\Session()->flash('alert-success', __('Leistungsträger neuer Rabatt hinzugefügt'));
return redirect(route('booking_detail', [$booking->id]) . "#collapseBookingProvider");
}
if ($action === 'service_provider_entry_add_payment') {
$ServiceProvider = ServiceProvider::where('type', 'payment')->where('active', true)->first();
ServiceProviderEntry::create([
'booking_id' => $booking->id,
'service_provider_id' => $ServiceProvider->id,
'type' => 'payment',
]);
\Session()->flash('alert-success', __('Leistungsträger neue Zahlung hinzugefügt'));
return redirect(route('booking_detail', [$booking->id]) . "#collapseBookingProvider");
}
if ($action === 'booking_service_item_add') {
$TravelCompany = TravelCompany::where('active', true)->first();
BookingServiceItem::create([
'booking_id' => $booking->id,
'travel_company_id' => $TravelCompany->id,
'travel_date' => now(),
]);
\Session()->flash('alert-success', __('Reiseveranstalter neue Leistung hinzugefügt'));
return redirect(route('booking_detail', [$booking->id]) . "#collapseBookingCompany");
}
if ($action === 'booking_participant_add') {
Participant::create([
'booking_id' => $booking->id,
'nationality_id' => 1,
'participant_salutation_id' => 1,
]);
\Session()->flash('alert-success', __('Neuen Teilnehmer hinzugefügt'));
return redirect(route('booking_detail', [$booking->id]) . "#collapseBookingParticipant");
}
}
public function delete($id, $del = "booking")
{
if ($del === 'booking_file') {
$booking_file = BookingFile::findOrFail($id);
$booking = $booking_file->booking;
$this->deleteBookingFile($booking_file);
\Session()->flash('alert-success', 'Datei gelöscht');
return redirect(route('booking_detail', [$booking->id]) . "#collapseBookingFiles");
}
if ($del === 'booking_notice') {
$booking_notice = BookingNotice::findOrFail($id);
$booking = $booking_notice->booking;
$booking_notice->delete();
\Session()->flash('alert-success', 'Notiz gelöscht');
return redirect(route('booking_detail', [$booking->id]) . "#collapseBookingNotice");
}
if ($del === 'passolution_file') {
$booking = Booking::findOrFail($id);
$booking->resyncPassolutionPDF();
\Session()->flash('alert-success', 'Passolution erneuert');
return redirect(route('booking_detail', [$booking->id]) . "#collapseBookingFiles");
}
if ($del === 'service_provider_entry') {
$ServiceProviderEntry = ServiceProviderEntry::findOrFail($id);
$booking = $ServiceProviderEntry->booking;
$ServiceProviderEntry->delete();
\Session()->flash('alert-success', 'Leistungsträger gelöscht');
return redirect(route('booking_detail', [$booking->id]) . "#collapseBookingProvider");
}
if ($del === 'booking_service_item') {
$BookingServiceItem = BookingServiceItem::findOrFail($id);
$booking = $BookingServiceItem->booking;
$BookingServiceItem->delete();
\Session()->flash('alert-success', 'Reiseveranstalter gelöscht');
return redirect(route('booking_detail', [$booking->id]) . "#collapseBookingCompany");
}
if ($del === 'participant') {
$Participant = Participant::findOrFail($id);
$booking = $Participant->booking;
$Participant->delete();
\Session()->flash('alert-success', 'Teilnehmer gelöscht');
return redirect(route('booking_detail', [$booking->id]) . "#collapseBookingParticipant");
}
return redirect(route('requests'));
}
private function deleteBookingFile($booking_file)
{
$fileRepo = new BookingFileRepository($booking_file);
$fileRepo->_set('disk', 'booking');
$fileRepo->delete();
$booking_file->delete();
}
private function deleteCustomerFile($customer_file)
{
$fileRepo = new CustomerFileRepository($customer_file);
$fileRepo->_set('disk', 'customer');
$fileRepo->delete();
$customer_file->delete();
}
private function deleteBookingDocument($booking_document)
{
$booking_document->deleteFile();
$booking_document->delete();
}
public function deleteComplete($id)
{
$booking = Booking::findOrFail($id);
if ($booking->booking_files) {
foreach ($booking->booking_files as $booking_file) {
$this->deleteBookingFile($booking_file);
}
}
if ($booking->booking_notices) {
foreach ($booking->booking_notices as $booking_notice) {
$booking_notice->delete();
}
}
if ($booking->service_provider_entries) {
foreach ($booking->service_provider_entries as $service_provider_entry) {
$service_provider_entry->delete();
}
}
if ($booking->booking_service_items) {
foreach ($booking->booking_service_items as $booking_service_item) {
$booking_service_item->delete();
}
}
if ($booking->booking_provider_services) {
foreach ($booking->booking_provider_services as $booking_provider_service) {
$booking_provider_service->delete();
}
}
if ($booking->booking_country_services) {
foreach ($booking->booking_country_services as $booking_country_service) {
$booking_country_service->delete();
}
}
if ($booking->participants) {
foreach ($booking->participants as $participant) {
$participant->delete();
}
}
if ($booking->customer_mails) {
foreach ($booking->customer_mails_reverse as $customer_mail) {
if ($customer_mail->customer_files) {
foreach ($customer_mail->customer_files as $customer_file) {
$this->deleteCustomerFile($customer_file);
}
}
$customer_mail->delete();
}
}
if ($booking->booking_documents) {
foreach ($booking->booking_documents as $booking_document) {
if ($booking_document->identifier === 'coupon') {
//coupon set booking ID to null <- is need by the customer
$booking_document->booking_id = null;
$booking_document->save();
} else {
$this->deleteBookingDocument($booking_document);
}
}
}
if ($booking->coupons) {
foreach ($booking->coupons as $coupon) {
//coupon set booking ID to null <- is need by the customer
$coupon->booking_id = null;
$coupon->save();
}
}
$booking->delete();
\Session()->flash('alert-success', 'Buchung gelöscht');
return redirect(route('requests'));
}
}