deplay phase 1

This commit is contained in:
Kevin Adametz 2026-04-17 17:19:11 +02:00
parent e3dc1afd8e
commit 5a7478907e
68 changed files with 2831 additions and 818 deletions

View file

@ -37,7 +37,7 @@ class ContactsFindDuplicates extends Command
// ── HIGH: gleiche E-Mail ──────────────────────────────────────────
if ($this->shouldCheck('HIGH')) {
$emailDupes = DB::table('contacts')
$emailDupes = DB::table('customer')
->select('email', DB::raw('COUNT(*) as cnt'), DB::raw('GROUP_CONCAT(id ORDER BY updated_at DESC) as ids'))
->whereNotNull('email')
->where('email', '!=', '')
@ -60,7 +60,7 @@ class ContactsFindDuplicates extends Command
// ── MEDIUM: Name + Vorname + Geburtsdatum ────────────────────────
if ($this->shouldCheck('MEDIUM')) {
$nameBdDupes = DB::table('contacts')
$nameBdDupes = DB::table('customer')
->select(
'name', 'firstname', 'birthdate',
DB::raw('COUNT(*) as cnt'),
@ -88,7 +88,7 @@ class ContactsFindDuplicates extends Command
// ── LOW: Name + Vorname + PLZ ─────────────────────────────────────
if ($this->shouldCheck('LOW')) {
$nameZipDupes = DB::table('contacts')
$nameZipDupes = DB::table('customer')
->select(
'name', 'firstname', 'zip',
DB::raw('COUNT(*) as cnt'),

View file

@ -90,7 +90,7 @@ class ContactsMergeDuplicates extends Command
private function findByEmail(): array
{
return DB::table('contacts')
return DB::table('customer')
->select('email', DB::raw('GROUP_CONCAT(id ORDER BY updated_at DESC, id DESC) as ids'))
->whereNotNull('email')
->where('email', '!=', '')
@ -104,7 +104,7 @@ class ContactsMergeDuplicates extends Command
private function findByNameBirthdate(): array
{
return DB::table('contacts')
return DB::table('customer')
->select(DB::raw('GROUP_CONCAT(id ORDER BY updated_at DESC, id DESC) as ids'))
->whereNotNull('name')
->whereNotNull('firstname')
@ -119,7 +119,7 @@ class ContactsMergeDuplicates extends Command
private function findByNameZip(): array
{
return DB::table('contacts')
return DB::table('customer')
->select(DB::raw('GROUP_CONCAT(id ORDER BY updated_at DESC, id DESC) as ids'))
->whereNotNull('name')
->whereNotNull('firstname')
@ -173,11 +173,11 @@ class ContactsMergeDuplicates extends Command
private function mergeInto(int $masterId, int $dupeId): void
{
// 1. Leads umhängen
$leadCount = DB::table('inquiries')->where('customer_id', $dupeId)->count();
$leadCount = DB::table('lead')->where('customer_id', $dupeId)->count();
if ($leadCount > 0) {
$this->line(" lead.customer_id: {$leadCount} Zeile(n) → #{$masterId}");
if (!$this->dryRun) {
DB::table('inquiries')
DB::table('lead')
->where('customer_id', $dupeId)
->update(['customer_id' => $masterId]);
}
@ -220,7 +220,7 @@ class ContactsMergeDuplicates extends Command
// 5. Duplikat als zusammengeführt markieren
if (!$this->dryRun) {
DB::table('contacts')
DB::table('customer')
->where('id', $dupeId)
->update([
'merged_into_id' => $masterId,

View file

@ -193,8 +193,7 @@ class SyncNewsletterKulturreisen extends Command
'description' => 'Kontakt durch Kulturreisen-Buchung erstellt',
'metadata' => [
'booking_id' => $booking->id,
// Metadaten-Key bleibt `lead_id`; Wert kommt aus booking.inquiry_id.
'lead_id' => $booking->inquiry_id,
'lead_id' => $booking->lead_id,
],
]);
}

View file

@ -2,7 +2,16 @@
namespace App\Exceptions;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Auth\AuthenticationException;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Illuminate\Session\TokenMismatchException;
use Illuminate\Support\Facades\Mail;
use Illuminate\Validation\ValidationException;
use Symfony\Component\ErrorHandler\ErrorRenderer\HtmlErrorRenderer;
use Symfony\Component\ErrorHandler\Exception\FlattenException;
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
use Throwable;
class Handler extends ExceptionHandler
@ -37,6 +46,65 @@ class Handler extends ExceptionHandler
public function report(Throwable $exception)
{
parent::report($exception);
$e = $this->mapException($exception);
if ($this->shouldMailServerError($e)) {
$this->sendEmail($e);
}
}
/**
* E-Mail nur bei echten Serverfeilern (5xx bzw. unbehandelte Exceptions), nicht bei lokalem Entwickeln.
*/
protected function shouldMailServerError(Throwable $e): bool
{
if (app()->environment('local', 'testing')) {
return false;
}
if (! config('app.exception_mail')) {
return false;
}
return $this->exceptionIndicatesServerError($e);
}
/**
* Entspricht dem, was üblicherweise als HTTP500 ausgeliefert würde.
*/
protected function exceptionIndicatesServerError(Throwable $e): bool
{
if (
$e instanceof AuthenticationException
|| $e instanceof AuthorizationException
|| $e instanceof ModelNotFoundException
|| $e instanceof ValidationException
|| $e instanceof TokenMismatchException
) {
return false;
}
if ($e instanceof HttpExceptionInterface) {
return $e->getStatusCode() >= 500;
}
return true;
}
protected function exceptionMailContextLine(): string
{
if (app()->runningInConsole()) {
$argv = $_SERVER['argv'] ?? [];
return 'CLI: ' . (count($argv) ? implode(' ', $argv) : php_sapi_name());
}
if (app()->bound('request') && request()) {
return request()->fullUrl();
}
return 'n/a';
}
/**
@ -52,4 +120,28 @@ class Handler extends ExceptionHandler
{
return parent::render($request, $exception);
}
public function sendEmail(Throwable $exception)
{
try {
$e = FlattenException::create($exception);
$handler = new HtmlErrorRenderer(true);
$css = $handler->getStylesheet();
$content = $handler->getBody($e);
$to = config('app.exception_mail');
$subject = config('app.name') . ' Exception: ' . $this->exceptionMailContextLine();
if ($to) {
Mail::send('emails.exception', compact('css', 'content'), function ($message) use ($to, $subject) {
$message->to($to)->subject($subject);
});
}
} catch (Throwable $ex) {
file_put_contents(
storage_path('logs/laravel-' . date('Y-m-d') . '.log'),
'[' . date('Y-m-d H:i:s') . '] exception-handler-error: ' . $ex->getMessage() . "\n",
FILE_APPEND
);
}
}
}

View file

@ -34,9 +34,7 @@ class BookingController extends Controller
$ret = [
'url_v1' => make_old_url('/index.php/booking/' . $booking->id . '/edit'),
'url_v3' => route('booking_detail', $booking->id),
// API-Feld bleibt `lead_id` aus Abwärtskompatibilität für API-Konsumenten;
// Wert kommt nach Modul 3 Phase 2 aus booking.inquiry_id.
'lead_id' => $booking->inquiry_id
'lead_id' => $booking->lead_id
];
return response()->json(['success' => "import", "ret" => $ret], $this->successStatus);

View file

@ -400,10 +400,10 @@ class ReportController extends Controller
$price = 0;
$isset = [];
foreach ($all as $v){
if(!in_array($v->booking->inquiry_id, $isset)){
if(!in_array($v->booking->lead_id, $isset)){
$price += $v->booking->isCanceled() ? $v->booking->getPriceCanceledRaw() : $v->booking->getPriceRaw();
}
$isset[] = $v->booking->inquiry_id;
$isset[] = $v->booking->lead_id;
}
return Util::_number_format($price);
@ -416,8 +416,8 @@ class ReportController extends Controller
$price = 0;
$isset = [];
foreach ($all as $v){
$price += in_array($v->booking->inquiry_id, $isset) ? 0 : $v->booking->getPriceTotalRaw();
$isset[] = $v->booking->inquiry_id;
$price += in_array($v->booking->lead_id, $isset) ? 0 : $v->booking->getPriceTotalRaw();
$isset[] = $v->booking->lead_id;
}
return Util::_number_format($price);
})
@ -429,8 +429,8 @@ class ReportController extends Controller
$proceeds = 0;
$isset = [];
foreach ($all as $v){
$proceeds += in_array($v->booking->inquiry_id, $isset) ? 0 : $v->booking->proceeds(true);
$isset[] = $v->booking->inquiry_id;
$proceeds += in_array($v->booking->lead_id, $isset) ? 0 : $v->booking->proceeds(true);
$isset[] = $v->booking->lead_id;
}
return Util::_number_format($proceeds);
/*$all = $query->get();
@ -562,7 +562,7 @@ class ReportController extends Controller
$ctemps[$export->booking->id][] = array(
'Zähler' => $new ? $export->getCounter() : "",
'MyJack Nr.' => $new ? $export->booking->merlin_order_number : "",
'CRM Nr' => $new ? $export->booking->inquiry_id : "",
'CRM Nr' => $new ? $export->booking->lead_id : "",
'Kunde' => $new ? $export->booking->customer->name : "",
'Reisedatum' => $new ? $export->booking->getStartDateFormat() : "",
'Organisation' => $new ? ($export->booking->isCanceled() ? $export->booking->price_canceled : $export->booking->price) : "",
@ -630,7 +630,7 @@ class ReportController extends Controller
$ctemps[$export->booking->id][] = array(
'Zähler' => $new ? $export->getCounter() : "",
'MyJack Nr.' => $new ? $export->booking->merlin_order_number : "",
'CRM Nr' => $new ? $export->booking->inquiry_id : "",
'CRM Nr' => $new ? $export->booking->lead_id : "",
'Kunde' => $new ? $export->booking->customer->name : "",
'Reisedatum' => $new ? $export->booking->getStartDateFormat() : "",
'Reiseland' => $new && $export->booking->travel_country ? $export->booking->travel_country->name : "",

View file

@ -49,7 +49,7 @@ class ReportLeadsController extends Controller
{
$query = Lead::with('customer')->with('sf_guard_user')->with('status')
->select('inquiries.*');
->select('lead.*');
//->where('deleted_at', '=', null);
/*
@ -132,7 +132,7 @@ class ReportLeadsController extends Controller
// $q->select('sent_at')->where('sent_at', DB::raw("(select max('sent_at') customer_mails)")); //)
})->orderBy(
LeadMail::select('sent_at')
->whereColumn('lead_id', 'inquiries.id')
->whereColumn('lead_id', 'lead.id')
->orderBy('sent_at', 'DESC')
->limit(1)
, $order);

View file

@ -104,10 +104,10 @@ class ReportProviderController extends Controller
$price = 0;
$isset = [];
foreach ($all as $v){
if(!in_array($v->booking->inquiry_id, $isset)){
if(!in_array($v->booking->lead_id, $isset)){
$price += $v->booking->isCanceled() ? $v->booking->getPriceCanceledRaw() : $v->booking->getPriceRaw();
}
$isset[] = $v->booking->inquiry_id;
$isset[] = $v->booking->lead_id;
}
return Util::_number_format($price);
@ -120,8 +120,8 @@ class ReportProviderController extends Controller
$price = 0;
$isset = [];
foreach ($all as $v){
$price += in_array($v->booking->inquiry_id, $isset) ? 0 : $v->booking->getPriceTotalRaw();
$isset[] = $v->booking->inquiry_id;
$price += in_array($v->booking->lead_id, $isset) ? 0 : $v->booking->getPriceTotalRaw();
$isset[] = $v->booking->lead_id;
}
return Util::_number_format($price);
})
@ -133,8 +133,8 @@ class ReportProviderController extends Controller
$proceeds = 0;
$isset = [];
foreach ($all as $v){
$proceeds += in_array($v->booking->inquiry_id, $isset) ? 0 : $v->booking->proceeds(true);
$isset[] = $v->booking->inquiry_id;
$proceeds += in_array($v->booking->lead_id, $isset) ? 0 : $v->booking->proceeds(true);
$isset[] = $v->booking->lead_id;
}
return Util::_number_format($proceeds);
/*$all = $query->get();
@ -272,7 +272,7 @@ class ReportProviderController extends Controller
$ctemps[$export->booking->id][] = array(
'Zähler' => $new ? $export->getCounter() : "",
'MyJack Nr.' => $new ? $export->booking->merlin_order_number : "",
'CRM Nr' => $new ? $export->booking->inquiry_id : "",
'CRM Nr' => $new ? $export->booking->lead_id : "",
'Kunde' => $new ? $export->booking->customer->name : "",
'Reisedatum' => $new ? $export->booking->getStartDateFormat() : "",
'bis' => $new ? $export->booking->getEndDateFormat() : "",
@ -346,7 +346,7 @@ class ReportProviderController extends Controller
$ctemps[$export->booking->id][] = array(
'Zähler' => $new ? $export->getCounter() : "",
'MyJack Nr.' => $new ? $export->booking->merlin_order_number : "",
'CRM Nr' => $new ? $export->booking->inquiry_id : "",
'CRM Nr' => $new ? $export->booking->lead_id : "",
'Kunde' => $new ? $export->booking->customer->name : "",
'Reisedatum' => $new ? $export->booking->getStartDateFormat() : "",
'bis' => $new ? $export->booking->getEndDateFormat() : "",

View file

@ -157,11 +157,11 @@ class ContactController extends Controller
}
DB::transaction(function () use ($masterId, $dupeId) {
DB::table('inquiries')->where('customer_id', $dupeId)->update(['customer_id' => $masterId]);
DB::table('lead')->where('customer_id', $dupeId)->update(['customer_id' => $masterId]);
DB::table('booking')->where('customer_id', $dupeId)->update(['customer_id' => $masterId]);
DB::table('customer_mails')->where('customer_id', $dupeId)->update(['customer_id' => $masterId]);
DB::table('lead_mails')->where('customer_id', $dupeId)->update(['customer_id' => $masterId]);
DB::table('contacts')->where('id', $dupeId)->update([
DB::table('customer')->where('id', $dupeId)->update([
'merged_into_id' => $masterId,
'merged_at' => now(),
]);
@ -175,16 +175,16 @@ class ContactController extends Controller
private function countDuplicateGroups(string $type): int
{
return match ($type) {
'email' => DB::table('contacts')->selectRaw('COUNT(*) as cnt')->whereNotNull('email')->where('email', '!=', '')->whereNull('merged_into_id')->whereNull('deleted_at')->groupBy('email')->havingRaw('COUNT(*) > 1')->get()->count(),
'name_birthdate' => DB::table('contacts')->selectRaw('COUNT(*) as cnt')->whereNotNull('name')->whereNotNull('firstname')->whereNotNull('birthdate')->whereNull('merged_into_id')->whereNull('deleted_at')->groupBy('name', 'firstname', 'birthdate')->havingRaw('COUNT(*) > 1')->get()->count(),
'name_zip' => DB::table('contacts')->selectRaw('COUNT(*) as cnt')->whereNotNull('name')->whereNotNull('firstname')->whereNotNull('zip')->where('zip', '!=', '')->whereNull('merged_into_id')->whereNull('deleted_at')->groupBy('name', 'firstname', 'zip')->havingRaw('COUNT(*) > 1')->get()->count(),
'email' => DB::table('customer')->selectRaw('COUNT(*) as cnt')->whereNotNull('email')->where('email', '!=', '')->whereNull('merged_into_id')->whereNull('deleted_at')->groupBy('email')->havingRaw('COUNT(*) > 1')->get()->count(),
'name_birthdate' => DB::table('customer')->selectRaw('COUNT(*) as cnt')->whereNotNull('name')->whereNotNull('firstname')->whereNotNull('birthdate')->whereNull('merged_into_id')->whereNull('deleted_at')->groupBy('name', 'firstname', 'birthdate')->havingRaw('COUNT(*) > 1')->get()->count(),
'name_zip' => DB::table('customer')->selectRaw('COUNT(*) as cnt')->whereNotNull('name')->whereNotNull('firstname')->whereNotNull('zip')->where('zip', '!=', '')->whereNull('merged_into_id')->whereNull('deleted_at')->groupBy('name', 'firstname', 'zip')->havingRaw('COUNT(*) > 1')->get()->count(),
default => 0,
};
}
private function findByEmail(): array
{
return DB::table('contacts')
return DB::table('customer')
->selectRaw('GROUP_CONCAT(id ORDER BY updated_at DESC, id DESC) as ids')
->whereNotNull('email')->where('email', '!=', '')
->whereNull('merged_into_id')->whereNull('deleted_at')
@ -194,7 +194,7 @@ class ContactController extends Controller
private function findByNameBirthdate(): array
{
return DB::table('contacts')
return DB::table('customer')
->selectRaw('GROUP_CONCAT(id ORDER BY updated_at DESC, id DESC) as ids')
->whereNotNull('name')->whereNotNull('firstname')->whereNotNull('birthdate')
->whereNull('merged_into_id')->whereNull('deleted_at')
@ -204,7 +204,7 @@ class ContactController extends Controller
private function findByNameZip(): array
{
return DB::table('contacts')
return DB::table('customer')
->selectRaw('GROUP_CONCAT(id ORDER BY updated_at DESC, id DESC) as ids')
->whereNotNull('name')->whereNotNull('firstname')
->whereNotNull('zip')->where('zip', '!=', '')
@ -228,8 +228,8 @@ class ContactController extends Controller
// Reihenfolge wichtig: select() zuerst, dann withCount() — sonst überschreibt
// select() die COUNT-Subqueries die withCount() per addSelect() eingetragen hat.
$query = $showDeleted
? Contact::onlyTrashed()->withoutGlobalScope('not_merged')->select('contacts.*')->withCount(['leads', 'bookings'])
: Contact::select('contacts.*')->withCount(['leads', 'bookings']);
? Contact::onlyTrashed()->withoutGlobalScope('not_merged')->select('customer.*')->withCount(['leads', 'bookings'])
: Contact::select('customer.*')->withCount(['leads', 'bookings']);
// Zusatzfilter aus der UI (werden als extra GET-Parameter gesendet)
if ($request->filled('filter_has_leads')) {
@ -275,7 +275,7 @@ class ContactController extends Controller
->orderColumn('deleted_at', 'customer.deleted_at $1')
->filterColumn('id', function ($query, $keyword) {
if ($keyword !== '') {
$query->where('contacts.id', 'LIKE', '%' . $keyword . '%');
$query->where('customer.id', 'LIKE', '%' . $keyword . '%');
}
})
->filterColumn('name', function ($query, $keyword) {

View file

@ -68,7 +68,7 @@ class CustomerController extends Controller
public function getCustomers()
{
$query = Customer::with('salutation')->select('contacts.*');
$query = Customer::with('salutation')->select('customer.*');
return \DataTables::eloquent($query)
->addColumn('action_edit', function (Customer $customer) {

View file

@ -232,7 +232,7 @@ class LeadController extends Controller
public function getLeads()
{
$query = Lead::with('customer')->with('sf_guard_user')->with('status')->select('inquiries.*');
$query = Lead::with('customer')->with('sf_guard_user')->with('status')->select('lead.*');
return \DataTables::eloquent($query)
->addColumn('action_edit', function (Lead $lead) {
@ -296,7 +296,7 @@ class LeadController extends Controller
// $q->select('sent_at')->where('sent_at', DB::raw("(select max('sent_at') customer_mails)")); //)
})->orderBy(
LeadMail::select('sent_at')
->whereColumn('lead_id', 'inquiries.id')
->whereColumn('lead_id', 'lead.id')
->orderBy('sent_at', 'DESC')
->limit(1)
, $order);

View file

@ -89,7 +89,7 @@ class RequestController extends Controller
wirte old where has state to new has travel_documents
$bs = Booking::whereHas('arrangements', function($q){
$q->where('state', '!=', NULL);
})->where('inquiry_id', '!=', NULL)->where('new_drafts', 0)->get();
})->where('lead_id', '!=', NULL)->where('new_drafts', 0)->get();
foreach ($bs as $b){
$b->travel_documents = true;
@ -101,7 +101,7 @@ class RequestController extends Controller
private function getSearchRequests()
{
$query = Booking::with('lead')->with('customer')->with('customer_mails')->with('customer_mails')->select('booking.*')->where('inquiry_id', '!=', NULL);
$query = Booking::with('lead')->with('customer')->with('customer_mails')->with('customer_mails')->select('booking.*')->where('lead_id', '!=', NULL);
if (Request::get('full_firstname_search') != "") {
$query->whereHas('customer', function ($q) {
@ -241,7 +241,7 @@ class RequestController extends Controller
}
if (Request::get('full_lead_id_search') != "") {
$query->where('inquiry_id', 'LIKE', '%' . Request::get('full_lead_id_search') . '%');
$query->where('lead_id', 'LIKE', '%' . Request::get('full_lead_id_search') . '%');
}
if (Request::get('full_booking_id_search') != "") {
$query->where('id', 'LIKE', '%' . Request::get('full_booking_id_search') . '%');
@ -398,10 +398,10 @@ class RequestController extends Controller
return '<a data-order="' . $booking->id . '" href="' . make_old_url('booking/' . $booking->id . '/edit') . '" data-id="' . $booking->id . '">' . $booking->id . '</a>';
})
->addColumn('action_lead_edit', function (Booking $booking) {
return '<a href="' . route('lead_detail', [$booking->inquiry_id]) . '" class="btn icon-btn btn-sm btn-primary"><span class="fa fa-edit"></span></a>';
return '<a href="' . route('lead_detail', [$booking->lead_id]) . '" class="btn icon-btn btn-sm btn-primary"><span class="fa fa-edit"></span></a>';
})
->addColumn('lead_id', function (Booking $booking) {
return '<a data-order="' . $booking->inquiry_id . '" href="' . make_old_url('leads/' . $booking->inquiry_id . '/edit') . '" data-id="' . $booking->inquiry_id . '">' . $booking->inquiry_id . '</a>';
return '<a data-order="' . $booking->lead_id . '" href="' . make_old_url('leads/' . $booking->lead_id . '/edit') . '" data-id="' . $booking->lead_id . '">' . $booking->lead_id . '</a>';
})
->addColumn('travel_country_id', function (Booking $booking) {
return '<span data-order="' . ($booking->travel_country_id ? $booking->travel_country_id : 0) . '">' . ($booking->travel_country_id ? $booking->travel_country->name : "-") . '</span>';
@ -523,7 +523,7 @@ class RequestController extends Controller
}
})
*/
->orderColumn('lead_id', 'inquiry_id $1')
->orderColumn('lead_id', 'lead_id $1')
->orderColumn('id', 'id $1')
->orderColumn('travel_country_id', 'travel_country_id $1')
->orderColumn('travelagenda_id', 'travelagenda_id $1')

View file

@ -19,7 +19,7 @@ use Illuminate\Database\Eloquent\Collection;
* @property int $id
* @property Carbon $booking_date
* @property int $customer_id
* @property int $inquiry_id
* @property int $lead_id
* @property bool $new_drafts
* @property int $sf_guard_user_id
* @property int $branch_id
@ -212,8 +212,7 @@ class Booking extends Model
protected $casts = [
'customer_id' => 'int',
'inquiry_id' => 'int',
'offer_id' => 'int',
'lead_id' => 'int',
'new_drafts' => 'bool',
'sf_guard_user_id' => 'int',
'branch_id' => 'int',
@ -257,8 +256,7 @@ class Booking extends Model
protected $fillable = [
'booking_date',
'customer_id',
'inquiry_id',
'offer_id',
'lead_id',
'new_drafts',
'sf_guard_user_id',
'branch_id',
@ -395,29 +393,9 @@ class Booking extends Model
return $this->belongsTo(Customer::class);
}
/**
* Lead/Inquiry der Buchung.
* FK-Spalte `inquiry_id` (vormals `lead_id` Modul 3 Phase 2 Rename).
* Methodenname bleibt `lead()` für Legacy-Kompatibilität; {@see self::inquiry()}
* ist der fachlich korrekte Alias und sollte in neuem Code verwendet werden.
*/
public function lead()
{
return $this->belongsTo(Lead::class, 'inquiry_id');
}
public function inquiry()
{
return $this->belongsTo(Lead::class, 'inquiry_id');
}
/**
* Angebot, aus dem diese Buchung entstanden ist (Modul 6, Ticket B8).
* Nullable nicht jede Buchung hat einen Angebots-Vorlauf.
*/
public function offer()
{
return $this->belongsTo(\App\Models\Offer::class);
return $this->belongsTo(Lead::class);
}
public function sf_guard_user()

View file

@ -18,7 +18,7 @@ use Illuminate\Database\Eloquent\SoftDeletes;
* - merged_into_id + merged_at in $fillable
* - mergedInto() / mergedContacts() Beziehungen
*
* Tabellen-Name: 'contacts' (nach Phase 2 RENAME TABLE customer contacts).
* Tabellen-Name: 'customer' (wird in Phase 2 in 'contacts' umbenannt).
*
* @property int $id
* @property int|null $salutation_id
@ -50,7 +50,7 @@ class Contact extends Model
protected $connection = 'mysql';
protected $table = 'contacts';
protected $table = 'customer';
protected $casts = [
'salutation_id' => 'int',

View file

@ -88,12 +88,7 @@ class Customer extends Model
protected $connection = 'mysql';
/**
* Modul 3 Phase 2: customer contacts (RENAME TABLE).
* Der Model-Name bleibt aus Kompatibilität zum Legacy-Code bestehen;
* für die Neuimplementierung steht {@see Contact} bereit.
*/
protected $table = 'contacts';
protected $table = 'customer';
protected $casts = [
'salutation_id' => 'int',

View file

@ -112,12 +112,7 @@ class Lead extends Model
protected $connection = 'mysql';
/**
* Modul 3 Phase 2: lead inquiries (RENAME TABLE).
* Model-Name bleibt (um Breaking Changes in der gesamten Codebase zu vermeiden);
* fachlich ist das Modell jetzt eine "Inquiry" (Anfrage).
*/
protected $table = 'inquiries';
protected $table = 'lead';
protected $casts = [
'customer_id' => 'int',

View file

@ -1,132 +1,56 @@
<?php
/**
* Created by Reliese Model.
*/
namespace App\Models;
use App\User;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\SoftDeletes;
/**
* Angebot (Modul 6).
*
* Ein Offer ist der logische Angebots-Kopf (Angebotsnummer, Status,
* Referenzen). Die Inhalte (Texte, Positionen, PDF) liegen versionsweise
* in {@see OfferVersion}. Nach dem ersten Versand ist jede Änderung
* eine neue Version (Entscheidung 17.1 Entwicklungsplan).
* Class Offer
*
* @property int $id
* @property string $offer_number
* @property int $contact_id
* @property int|null $inquiry_id
* @property int|null $booking_id
* @property string $status
* @property int|null $current_version_id
* @property int $created_by
* @property int $lead_id
* @property float $total
* @property boolean $binary_data
* @property Carbon $created_at
* @property Carbon $updated_at
* @property Carbon|null $deleted_at
* @property-read Contact $contact
* @property-read Lead|null $inquiry
* @property-read Booking|null $booking
* @property-read OfferVersion|null $currentVersion
* @property-read Collection|OfferVersion[] $versions
* @property-read Collection|OfferAccessToken[] $accessTokens
* @property-read User $creator
* @property Lead $lead
* @package App\Models
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Offer newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Offer newQuery()
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Offer query()
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Offer whereBinaryData($value)
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Offer whereCreatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Offer whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Offer whereLeadId($value)
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Offer whereTotal($value)
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Offer whereUpdatedAt($value)
* @mixin \Eloquent
*/
class Offer extends Model
{
use HasFactory, SoftDeletes;
protected $connection = 'mysql';
public const STATUS_DRAFT = 'draft';
public const STATUS_SENT = 'sent';
public const STATUS_ACCEPTED = 'accepted';
public const STATUS_DECLINED = 'declined';
public const STATUS_EXPIRED = 'expired';
public const STATUS_WITHDRAWN = 'withdrawn';
protected $table = 'offer';
public const STATUSES = [
self::STATUS_DRAFT,
self::STATUS_SENT,
self::STATUS_ACCEPTED,
self::STATUS_DECLINED,
self::STATUS_EXPIRED,
self::STATUS_WITHDRAWN,
];
protected $casts = [
'lead_id' => 'int',
'total' => 'float',
'binary_data' => 'boolean'
];
protected $table = 'offers';
protected $fillable = [
'lead_id',
'total',
'binary_data'
];
protected $fillable = [
'offer_number',
'contact_id',
'inquiry_id',
'booking_id',
'status',
'current_version_id',
'created_by',
];
protected $casts = [
'contact_id' => 'int',
'inquiry_id' => 'int',
'booking_id' => 'int',
'current_version_id' => 'int',
'created_by' => 'int',
];
public function contact(): BelongsTo
{
return $this->belongsTo(Contact::class);
}
public function inquiry(): BelongsTo
{
// Nach Modul 3 Phase 2: `Lead`-Model bildet die `inquiries`-Tabelle ab
return $this->belongsTo(Lead::class, 'inquiry_id');
}
public function booking(): BelongsTo
{
return $this->belongsTo(Booking::class);
}
public function currentVersion(): BelongsTo
{
return $this->belongsTo(OfferVersion::class, 'current_version_id');
}
public function versions(): HasMany
{
return $this->hasMany(OfferVersion::class)->orderBy('version_no');
}
public function accessTokens(): HasMany
{
return $this->hasMany(OfferAccessToken::class);
}
public function creator(): BelongsTo
{
return $this->belongsTo(User::class, 'created_by');
}
public function scopeStatus(Builder $q, string $status): Builder
{
return $q->where('status', $status);
}
public function scopeOpen(Builder $q): Builder
{
return $q->whereIn('status', [self::STATUS_DRAFT, self::STATUS_SENT]);
}
public function isEditable(): bool
{
return in_array($this->status, [self::STATUS_DRAFT, self::STATUS_SENT], true);
}
public function lead()
{
return $this->belongsTo(Lead::class);
}
}

View file

@ -1,120 +0,0 @@
<?php
namespace App\Models;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Support\Str;
/**
* Kundenseitiger Zugriffstoken für /angebot/{token} (Modul 6 / Phase D).
*
* In der Datenbank wird ausschließlich der SHA-256-Hash des Klartext-
* Tokens gespeichert. Der Klartext wird einmalig bei der Erzeugung
* zurückgegeben (siehe {@see self::generate()}) und an den Kunden
* per Mail-Link ausgeliefert.
*
* Pro Angebot + Version existiert genau ein aktiver Token; wird eine
* neue Version versendet, setzt der OfferService den Vorgänger auf
* `revoked_at`.
*
* @property int $id
* @property int $offer_id
* @property int $offer_version_id
* @property string $token_hash
* @property Carbon|null $expires_at
* @property Carbon|null $first_opened_at
* @property Carbon|null $revoked_at
* @property Carbon $created_at
* @property Carbon $updated_at
* @property-read Offer $offer
* @property-read OfferVersion $version
*/
class OfferAccessToken extends Model
{
use HasFactory;
protected $table = 'offer_access_tokens';
protected $fillable = [
'offer_id',
'offer_version_id',
'token_hash',
'expires_at',
'first_opened_at',
'revoked_at',
];
protected $casts = [
'offer_id' => 'int',
'offer_version_id' => 'int',
'expires_at' => 'datetime',
'first_opened_at' => 'datetime',
'revoked_at' => 'datetime',
];
public function offer(): BelongsTo
{
return $this->belongsTo(Offer::class);
}
public function version(): BelongsTo
{
return $this->belongsTo(OfferVersion::class, 'offer_version_id');
}
public function scopeActive(Builder $q): Builder
{
return $q->whereNull('revoked_at')
->where(function (Builder $q) {
$q->whereNull('expires_at')->orWhere('expires_at', '>', now());
});
}
/**
* Erzeugt ein neues Token für die angegebene Version und liefert
* den Klartext-Token zurück (nur einmalig abrufbar). In der
* Datenbank wird nur der Hash persistiert.
*/
public static function generate(
Offer $offer,
OfferVersion $version,
?Carbon $expiresAt = null
): array {
$plain = Str::random(48);
$hash = hash('sha256', $plain);
/** @var self $token */
$token = self::create([
'offer_id' => $offer->id,
'offer_version_id' => $version->id,
'token_hash' => $hash,
'expires_at' => $expiresAt,
]);
return ['plain' => $plain, 'token' => $token];
}
/**
* Lookup per Klartext-Token (konstantzeitig via DB-Unique-Index).
*/
public static function findByPlainToken(string $plain): ?self
{
return self::where('token_hash', hash('sha256', $plain))->first();
}
public function isActive(): bool
{
if ($this->revoked_at !== null) {
return false;
}
if ($this->expires_at !== null && $this->expires_at->isPast()) {
return false;
}
return true;
}
}

View file

@ -1,99 +0,0 @@
<?php
namespace App\Models;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
/**
* Datei-Anhang einer Angebotsversion (Modul 6).
*
* Struktur ist bewusst an {@see BookingFile} angelehnt (identifier,
* filename, dir, original_name, ext, mine, size), damit der vorhandene
* `FileRepository::store()` 1:1 wiederverwendet werden kann. `mine`
* bleibt so geschrieben (statt `mime`) zur Konsistenz mit der
* booking_files-Konvention.
*
* @property int $id
* @property int $offer_version_id
* @property string|null $identifier
* @property string $filename
* @property string $dir
* @property string $original_name
* @property string $ext
* @property string $mine
* @property int $size
* @property bool $include_in_pdf
* @property Carbon $created_at
* @property Carbon $updated_at
* @property-read OfferVersion $version
*/
class OfferFile extends Model
{
use HasFactory;
protected $table = 'offer_files';
protected $fillable = [
'offer_version_id',
'identifier',
'filename',
'dir',
'original_name',
'ext',
'mine',
'size',
'include_in_pdf',
];
protected $casts = [
'offer_version_id' => 'int',
'size' => 'int',
'include_in_pdf' => 'bool',
];
public static array $iconExt = [
'default' => 'fa fa-file',
'pdf' => 'fa fa-file-pdf',
'jpg' => 'fa fa-file-image',
'jpeg' => 'fa fa-file-image',
'png' => 'fa fa-file-image',
'doc' => 'fa fa-file-word',
'docx' => 'fa fa-file-word',
];
public function version(): BelongsTo
{
return $this->belongsTo(OfferVersion::class, 'offer_version_id');
}
public function getIconExt(): string
{
return self::$iconExt[$this->ext] ?? self::$iconExt['default'];
}
public function getURL(bool|string $do = false): string
{
return route('storage_file', [$this->id, 'offer', $do]);
}
public function getPath(): string
{
return \Storage::disk('offer')->path($this->dir . $this->filename);
}
public function formatBytes(int $precision = 2): string
{
$size = $this->size;
if ($size <= 0) {
return (string) $size;
}
$base = log($size) / log(1024);
$suffixes = [' bytes', ' KB', ' MB', ' GB', ' TB'];
return round(1024 ** ($base - floor($base)), $precision) . $suffixes[floor($base)];
}
}

View file

@ -1,86 +0,0 @@
<?php
namespace App\Models;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
/**
* Position einer Angebotsversion (Modul 6).
*
* `travel_program_id` und `fewo_lodging_id` bleiben FK-frei, solange
* Modul 12 (v2-Reiseverwaltung) noch nicht nach Laravel migriert ist.
* `metadata` enthält einen Snapshot der Referenzdaten (Titel, Preis,
* Leistungen) so bleiben Positionen lesbar, auch wenn das Original
* später gelöscht / migriert / umbenannt wird.
*
* @property int $id
* @property int $offer_version_id
* @property int $position
* @property string $type
* @property string $title
* @property string|null $description
* @property int $quantity
* @property float $price_per_unit
* @property float $total_price
* @property int|null $travel_program_id
* @property int|null $fewo_lodging_id
* @property array|null $metadata
* @property Carbon $created_at
* @property Carbon $updated_at
* @property-read OfferVersion $version
*/
class OfferItem extends Model
{
use HasFactory;
public const TYPE_TRAVEL = 'travel';
public const TYPE_SERVICE = 'service';
public const TYPE_OPTION = 'option';
public const TYPE_DISCOUNT = 'discount';
public const TYPE_INSURANCE = 'insurance';
public const TYPE_CUSTOM = 'custom';
protected $table = 'offer_items';
protected $fillable = [
'offer_version_id',
'position',
'type',
'title',
'description',
'quantity',
'price_per_unit',
'total_price',
'travel_program_id',
'fewo_lodging_id',
'metadata',
];
protected $casts = [
'offer_version_id' => 'int',
'position' => 'int',
'quantity' => 'int',
'price_per_unit' => 'decimal:2',
'total_price' => 'decimal:2',
'travel_program_id' => 'int',
'fewo_lodging_id' => 'int',
'metadata' => 'array',
];
public function version(): BelongsTo
{
return $this->belongsTo(OfferVersion::class, 'offer_version_id');
}
/**
* Aus Menge × Einzelpreis den Positions-Gesamtpreis berechnen
* (Rabatte negativ gehört in den Service-Layer zur Summierung).
*/
public function calculateTotal(): float
{
return round($this->quantity * (float) $this->price_per_unit, 2);
}
}

View file

@ -1,77 +0,0 @@
<?php
namespace App\Models;
use App\User;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;
/**
* Wiederverwendbare Angebots-Vorlage (Modul 6).
*
* Liefert Default-Texte + Default-Positionen für neue Angebote.
* `default_items` ist ein JSON-Array von Positionen im Schema
* [{title, description, type, price_per_unit, quantity}, ].
*
* @property int $id
* @property int|null $branch_id
* @property string $name
* @property string|null $description
* @property string|null $default_headline
* @property string|null $default_intro
* @property string|null $default_itinerary
* @property string|null $default_closing
* @property array|null $default_items
* @property bool $is_active
* @property int $created_by
* @property Carbon $created_at
* @property Carbon $updated_at
* @property Carbon|null $deleted_at
* @property-read Branch|null $branch
* @property-read User $creator
*/
class OfferTemplate extends Model
{
use HasFactory, SoftDeletes;
protected $table = 'offer_templates';
protected $fillable = [
'branch_id',
'name',
'description',
'default_headline',
'default_intro',
'default_itinerary',
'default_closing',
'default_items',
'is_active',
'created_by',
];
protected $casts = [
'branch_id' => 'int',
'default_items' => 'array',
'is_active' => 'bool',
'created_by' => 'int',
];
public function branch(): BelongsTo
{
return $this->belongsTo(Branch::class);
}
public function creator(): BelongsTo
{
return $this->belongsTo(User::class, 'created_by');
}
public function scopeActive(Builder $q): Builder
{
return $q->where('is_active', true);
}
}

View file

@ -1,126 +0,0 @@
<?php
namespace App\Models;
use App\User;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
/**
* Version eines Angebots (Modul 6).
*
* Jede versendete Fassung wird hier festgehalten Texte, Positionen
* und PDF bleiben damit unveränderlich, sobald ein Kunde sie per
* Freigabe-Link einsehen kann. Neue Änderungen nach dem Versand
* erzeugen eine neue Version (version_no = max+1, status = draft).
*
* @property int $id
* @property int $offer_id
* @property int $version_no
* @property string $status
* @property Carbon|null $valid_until
* @property float $total_price
* @property string|null $headline
* @property string|null $intro_text
* @property string|null $itinerary_text
* @property string|null $closing_text
* @property int|null $template_id
* @property string|null $pdf_path
* @property bool $pdf_archived
* @property Carbon|null $sent_at
* @property Carbon|null $accepted_at
* @property string|null $accepted_via
* @property array|null $template_document_ids
* @property int $created_by
* @property Carbon $created_at
* @property Carbon $updated_at
* @property-read Offer $offer
* @property-read OfferTemplate|null $template
* @property-read Collection|OfferItem[] $items
* @property-read Collection|OfferFile[] $files
* @property-read User $creator
*/
class OfferVersion extends Model
{
use HasFactory;
public const STATUS_DRAFT = 'draft';
public const STATUS_SENT = 'sent';
public const STATUS_ACCEPTED = 'accepted';
public const STATUS_DECLINED = 'declined';
public const STATUS_EXPIRED = 'expired';
public const STATUS_SUPERSEDED = 'superseded';
public const ACCEPTED_VIA_LINK = 'customer_link';
public const ACCEPTED_VIA_ADMIN = 'admin';
public const ACCEPTED_VIA_MAIL = 'email';
protected $table = 'offer_versions';
protected $fillable = [
'offer_id',
'version_no',
'status',
'valid_until',
'total_price',
'headline',
'intro_text',
'itinerary_text',
'closing_text',
'template_id',
'pdf_path',
'pdf_archived',
'sent_at',
'accepted_at',
'accepted_via',
'template_document_ids',
'created_by',
];
protected $casts = [
'offer_id' => 'int',
'version_no' => 'int',
'valid_until' => 'date',
'total_price' => 'decimal:2',
'template_id' => 'int',
'pdf_archived' => 'bool',
'sent_at' => 'datetime',
'accepted_at' => 'datetime',
'template_document_ids' => 'array',
'created_by' => 'int',
];
public function offer(): BelongsTo
{
return $this->belongsTo(Offer::class);
}
public function template(): BelongsTo
{
return $this->belongsTo(OfferTemplate::class, 'template_id');
}
public function items(): HasMany
{
return $this->hasMany(OfferItem::class)->orderBy('position');
}
public function files(): HasMany
{
return $this->hasMany(OfferFile::class);
}
public function creator(): BelongsTo
{
return $this->belongsTo(User::class, 'created_by');
}
public function isEditable(): bool
{
return $this->status === self::STATUS_DRAFT;
}
}

View file

@ -63,13 +63,13 @@ class BookingPDFRepository extends BaseRepository
{
$document = new stdClass();
$document->name = 'registration';
$document->number = $this->model->inquiry_id;
$document->number = $this->model->lead_id;
$document->title = 'BUCHUNGSAUFTRAG';
$document->voucher = null;
$document->date = now();
$document->total = $this->model->getPriceRaw();
$dir = $this->getDirPath('pdf', 'booking', $document->date->format('Y'));
$filename = "Buchnungsauftrag-" . $this->model->inquiry_id . ".pdf";
$filename = "Buchnungsauftrag-" . $this->model->lead_id . ".pdf";
$pdf_file = new CreatePDF('pdf.booking_registration');
$data = [
'booking' => $this->model,
@ -85,7 +85,7 @@ class BookingPDFRepository extends BaseRepository
{
$document = new stdClass();
$document->name = 'confirmation';
$document->number = $this->model->inquiry_id;
$document->number = $this->model->lead_id;
$document->title = 'REISEBESTÄTIGUNG';
$document->voucher = null;
$document->date = now();
@ -104,7 +104,7 @@ class BookingPDFRepository extends BaseRepository
$document->final_payment_date = date('Y-m-d');
}
$dir = $this->getDirPath('pdf', 'booking', $document->date->format('Y'));
$filename = "Reisebestätigung-" . $this->model->inquiry_id . ".pdf";
$filename = "Reisebestätigung-" . $this->model->lead_id . ".pdf";
$pdf_file = new CreatePDF('pdf.booking_confirmation');
$data = [
@ -160,14 +160,14 @@ class BookingPDFRepository extends BaseRepository
{
$document = new stdClass();
$document->name = 'voucher';
$document->number = $this->model->inquiry_id;
$document->number = $this->model->lead_id;
$document->name = 'voucher';
$document->title = $agency ? 'VOUCHER Agentur' : 'VOUCHER';
$document->voucher = $agency ? 'agency' : 'client';
$document->date = now();
$dir = $this->getDirPath('pdf', 'voucher', $document->date->format('Y'));
$filename = ($agency ? 'VoucherAgentur' : 'Voucher') . "-" . $this->model->inquiry_id . ".pdf";
$filename = ($agency ? 'VoucherAgentur' : 'Voucher') . "-" . $this->model->lead_id . ".pdf";
$pdf_file = new CreatePDF('pdf.booking_voucher');
$data = [
@ -224,7 +224,7 @@ class BookingPDFRepository extends BaseRepository
//init document
$document = new stdClass();
$document->name = $identifier;
$document->number = $this->model->inquiry_id;
$document->number = $this->model->lead_id;
$document->title = 'STORNOBESTÄTIGUNG';
$document->voucher = null;
$document->date = Carbon::parse($data['storno_print']);
@ -253,7 +253,7 @@ class BookingPDFRepository extends BaseRepository
$dir = $this->getDirPath('pdf', 'storno', $document->date->format('Y'));
$filename = "Reisestornierung -" . $this->model->inquiry_id . ".pdf";
$filename = "Reisestornierung -" . $this->model->lead_id . ".pdf";
$pdf_file = new CreatePDF('pdf.booking_storno');
$data = [
@ -288,9 +288,7 @@ class BookingPDFRepository extends BaseRepository
$fill = [
'booking_id' => $this->model->id,
'customer_id' => $this->model->customer_id,
// booking_documents.lead_id ist ein Shadow-Feld von booking.inquiry_id;
// die Spalte selbst wird von Phase 2 nicht umbenannt.
'lead_id' => $this->model->inquiry_id,
'lead_id' => $this->model->lead_id,
'identifier' => $identifier,
'filename' => $filename,
'dir' => $dir,

View file

@ -135,8 +135,7 @@ class CustomerMailRepository extends BaseRepository {
$customer_mail->fill([
'booking_id' => $booking->id,
'customer_id' => $booking->customer_id,
// customer_mails.lead_id-Spalte bleibt unverändert; Wert kommt aus booking.inquiry_id
'lead_id' => $booking->inquiry_id,
'lead_id' => $booking->lead_id,
'is_answer' => $is_answer,
'reply_id' => $reply_id,
'email' => $mail_from,
@ -154,8 +153,7 @@ class CustomerMailRepository extends BaseRepository {
$customer_mail = CustomerMail::create([
'booking_id' => $booking->id,
'customer_id' => $booking->customer_id,
// customer_mails.lead_id-Spalte bleibt unverändert; Wert kommt aus booking.inquiry_id
'lead_id' => $booking->inquiry_id,
'lead_id' => $booking->lead_id,
'is_answer' => $is_answer,
'reply_id' => $reply_id,
'email' => $mail_from,
@ -302,7 +300,7 @@ class CustomerMailRepository extends BaseRepository {
$value->id = $customer_mail->booking_id;
$value->booking = $booking;
$value->show = 'single';
$value->lead_title_id = " - (".$value->booking->inquiry_id.")";
$value->lead_title_id = " - (".$value->booking->lead_id.")";
$tmp = [];
@ -344,7 +342,7 @@ class CustomerMailRepository extends BaseRepository {
$value->booking = $booking;
$value->show = 'single';
$value->draft = true;
$value->lead_title_id = " - (".$value->booking->inquiry_id.")";
$value->lead_title_id = " - (".$value->booking->lead_id.")";
}else{
//multi
@ -381,8 +379,8 @@ class CustomerMailRepository extends BaseRepository {
$value->draft = false;
$value->booking = $booking;
$value->message = "";
$value->subject = " - (".$value->booking->inquiry_id.")";
$value->lead_title_id = " - (".$value->booking->inquiry_id.")";
$value->subject = " - (".$value->booking->lead_id.")";
$value->lead_title_id = " - (".$value->booking->lead_id.")";
$value->s_placeholder = "Betreff des Kunden";
$value->m_placeholder = "Nachricht des Kunden";
if(isset($data['customer_mail_id']) && $customer_mail = CustomerMail::find($data['customer_mail_id'])){

View file

@ -134,7 +134,7 @@ class LeadRepository extends BaseRepository {
$data = [
'booking_date' => date('Y-m-d'), //now
'customer_id' => $this->model->customer->id,
'inquiry_id' => $this->model->id,
'lead_id' => $this->model->id,
'new_drafts' => 1,
'sf_guard_user_id' => $this->model->sf_guard_user_id,
'branch_id' => 4,

View file

@ -53,7 +53,7 @@ class BookingImport
$data = [
'booking_date' => $travel_booking->created->format('Y-m-d'),
'customer_id' => $customer->id,
'inquiry_id' => $lead->id,
'lead_id' => $lead->id,
'new_drafts' => $travel_booking->drafts === null ? 0 : 1,
'sf_guard_user_id' => 15,
'branch_id' => 4,