CluPilotCloud/app/Models/DunningCase.php

74 lines
2.2 KiB
PHP

<?php
namespace App\Models;
use App\Services\Billing\DunningSchedule;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
/**
* Eine Rückstands-Episode: von der ersten gescheiterten Abbuchung bis zur
* Begleichung oder zur Sperre.
*/
class DunningCase extends Model
{
protected $fillable = [
'subscription_id', 'stripe_invoice_id', 'level',
'opened_at', 'next_step_at', 'settled_at', 'fee_invoice_ids', 'notified_levels', 'note',
];
protected function casts(): array
{
return [
'level' => 'integer',
'opened_at' => 'datetime',
'next_step_at' => 'datetime',
'settled_at' => 'datetime',
'fee_invoice_ids' => 'array',
'notified_levels' => 'array',
];
}
public function subscription(): BelongsTo
{
return $this->belongsTo(Subscription::class);
}
/**
* Die Cloud, um die es in diesem Fall geht — und nur diese.
*
* EINE Stelle für die Frage, weil Sperre und Freigabe sie beide stellen und
* zwei Antworten darauf der Weg wären, auf dem sie auseinanderlaufen: eine
* Cloud, die abgeschaltet wird und nie zurückkommt.
*
* Über die BESTELLUNG, nicht über `subscriptions.instance_id`. Die Spalte
* gibt es, aber OpenSubscription füllt sie nicht — auf dieser Installation
* war sie am 31.7.2026 bei drei von fünf Verträgen leer. Eine Sperre, die
* daran hängt, wäre für die meisten Kunden ein stiller Nulleffekt gewesen:
* nie abgeschaltet, nie eine Meldung. `order_id` war bei keinem Vertrag und
* keiner Instanz leer.
*/
public function instance(): ?Instance
{
$subscription = $this->subscription;
if ($subscription === null) {
return null;
}
return $subscription->instance
?? Instance::query()->where('order_id', $subscription->order_id)->first();
}
/** Läuft noch — weder beglichen noch von Hand geschlossen. */
public function isOpen(): bool
{
return $this->settled_at === null;
}
public function isSuspended(): bool
{
return $this->level >= DunningSchedule::SUSPENDED;
}
}