148 lines
4.8 KiB
PHP
148 lines
4.8 KiB
PHP
<?php
|
|
|
|
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;
|
|
|
|
/**
|
|
* Angebots-Kopfdatensatz (Modul 6 — Offers).
|
|
*
|
|
* Trägt Angebotsnummer + Beziehungen zu Kontakt / Anfrage / Buchung und
|
|
* zeigt via `current_version_id` auf die aktuell gültige OfferVersion.
|
|
* Die eigentlichen Inhalte (Texte, Positionen, Preise, PDF) liegen in
|
|
* `offer_versions`. Jede Änderung nach dem ersten Versand erzeugt eine
|
|
* neue Version (siehe OfferVersion::isEditable()).
|
|
*
|
|
* @property int $id
|
|
* @property string $offer_number
|
|
* @property int $contact_id
|
|
* @property int|null $inquiry_id
|
|
* @property int|null $booking_id
|
|
* @property string $status draft|sent|accepted|declined|expired|withdrawn
|
|
* @property int|null $current_version_id
|
|
* @property int $created_by
|
|
* @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 Collection|OfferVersion[] $versions
|
|
* @property-read OfferVersion|null $currentVersion
|
|
* @property-read User $createdBy
|
|
*/
|
|
class Offer extends Model
|
|
{
|
|
use HasFactory, SoftDeletes;
|
|
|
|
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';
|
|
|
|
/** Stati, die als „nicht abgeschlossen" gelten (Offer läuft noch). */
|
|
public const OPEN_STATUSES = [
|
|
self::STATUS_DRAFT,
|
|
self::STATUS_SENT,
|
|
];
|
|
|
|
protected $connection = 'mysql';
|
|
protected $table = 'offers';
|
|
|
|
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',
|
|
];
|
|
|
|
// ── Beziehungen ──────────────────────────────────────────────────────────
|
|
|
|
public function contact(): BelongsTo
|
|
{
|
|
return $this->belongsTo(Contact::class, 'contact_id');
|
|
}
|
|
|
|
/**
|
|
* Die Anfrage (Phase 2 heißt die Tabelle `inquiries`, das Eloquent-Model
|
|
* ist weiterhin `Lead` — Umbenennung des Models ist eigenes Ticket).
|
|
*/
|
|
public function inquiry(): BelongsTo
|
|
{
|
|
return $this->belongsTo(Lead::class, 'inquiry_id');
|
|
}
|
|
|
|
public function booking(): BelongsTo
|
|
{
|
|
return $this->belongsTo(Booking::class, 'booking_id');
|
|
}
|
|
|
|
public function versions(): HasMany
|
|
{
|
|
return $this->hasMany(OfferVersion::class, 'offer_id')->orderBy('version_no');
|
|
}
|
|
|
|
public function currentVersion(): BelongsTo
|
|
{
|
|
return $this->belongsTo(OfferVersion::class, 'current_version_id');
|
|
}
|
|
|
|
public function createdBy(): BelongsTo
|
|
{
|
|
return $this->belongsTo(User::class, 'created_by');
|
|
}
|
|
|
|
// ── Scopes ───────────────────────────────────────────────────────────────
|
|
|
|
/** Nur noch nicht abgeschlossene Angebote (draft + sent). */
|
|
public function scopeOpen(Builder $query): Builder
|
|
{
|
|
return $query->whereIn('status', self::OPEN_STATUSES);
|
|
}
|
|
|
|
public function scopeForContact(Builder $query, int $contactId): Builder
|
|
{
|
|
return $query->where('contact_id', $contactId);
|
|
}
|
|
|
|
/**
|
|
* @param string[] $stati
|
|
*/
|
|
public function scopeWithStatus(Builder $query, array $stati): Builder
|
|
{
|
|
return $query->whereIn('status', $stati);
|
|
}
|
|
|
|
// ── Hilfsmethoden ────────────────────────────────────────────────────────
|
|
|
|
public function isEditable(): bool
|
|
{
|
|
return $this->status === self::STATUS_DRAFT;
|
|
}
|
|
|
|
public function isOpen(): bool
|
|
{
|
|
return in_array($this->status, self::OPEN_STATUSES, true);
|
|
}
|
|
}
|