Bill transfer storage monthly with a 15-day grace period before deletion.
Deploy Ladill Transfer / deploy (push) Successful in 51s
Deploy Ladill Transfer / deploy (push) Successful in 51s
Files stay available while wallet renewals succeed each month. Failed renewals keep files for TRANSFER_GRACE_PERIOD_DAYS (default 15) before automatic cleanup. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+71
-3
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Carbon\CarbonInterface;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
@@ -10,6 +12,8 @@ class Transfer extends Model
|
||||
{
|
||||
public const STATUS_ACTIVE = 'active';
|
||||
|
||||
public const STATUS_GRACE = 'grace';
|
||||
|
||||
public const STATUS_EXPIRED = 'expired';
|
||||
|
||||
public const STATUS_DELETED = 'deleted';
|
||||
@@ -22,6 +26,9 @@ class Transfer extends Model
|
||||
'password_hash',
|
||||
'retention_days',
|
||||
'expires_at',
|
||||
'paid_until',
|
||||
'grace_ends_at',
|
||||
'last_billed_at',
|
||||
'status',
|
||||
'downloads_total',
|
||||
'storage_bytes',
|
||||
@@ -30,6 +37,9 @@ class Transfer extends Model
|
||||
protected $casts = [
|
||||
'retention_days' => 'integer',
|
||||
'expires_at' => 'datetime',
|
||||
'paid_until' => 'datetime',
|
||||
'grace_ends_at' => 'datetime',
|
||||
'last_billed_at' => 'datetime',
|
||||
'downloads_total' => 'integer',
|
||||
'storage_bytes' => 'integer',
|
||||
];
|
||||
@@ -54,17 +64,52 @@ class Transfer extends Model
|
||||
return $this->hasMany(TransferDownloadEvent::class);
|
||||
}
|
||||
|
||||
/** Files are available to recipients while paid or within the unpaid grace window. */
|
||||
public function isAccessible(): bool
|
||||
{
|
||||
if ($this->status === self::STATUS_DELETED) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->isPaid()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $this->isInGracePeriod();
|
||||
}
|
||||
|
||||
/** @deprecated Use isAccessible() — kept for existing call sites. */
|
||||
public function isActive(): bool
|
||||
{
|
||||
if ($this->status !== self::STATUS_ACTIVE) {
|
||||
return $this->isAccessible();
|
||||
}
|
||||
|
||||
public function isPaid(): bool
|
||||
{
|
||||
if (! in_array($this->status, [self::STATUS_ACTIVE, self::STATUS_GRACE], true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->expires_at && $this->expires_at->isPast()) {
|
||||
return $this->paid_until instanceof CarbonInterface && $this->paid_until->isFuture();
|
||||
}
|
||||
|
||||
public function isInGracePeriod(): bool
|
||||
{
|
||||
if ($this->status !== self::STATUS_GRACE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return $this->grace_ends_at instanceof CarbonInterface && $this->grace_ends_at->isFuture();
|
||||
}
|
||||
|
||||
public function isPastGracePeriod(): bool
|
||||
{
|
||||
return $this->grace_ends_at instanceof CarbonInterface && $this->grace_ends_at->isPast();
|
||||
}
|
||||
|
||||
public function billingPeriodEndsAt(): ?CarbonInterface
|
||||
{
|
||||
return $this->paid_until;
|
||||
}
|
||||
|
||||
public function isPasswordProtected(): bool
|
||||
@@ -81,4 +126,27 @@ class Transfer extends Model
|
||||
{
|
||||
return round($this->storageGb() * (float) config('transfer.price_per_gb_month', 0.30), 2);
|
||||
}
|
||||
|
||||
public function billingStatusLabel(): string
|
||||
{
|
||||
if ($this->isPaid()) {
|
||||
return 'Active';
|
||||
}
|
||||
|
||||
if ($this->isInGracePeriod()) {
|
||||
return 'Payment due';
|
||||
}
|
||||
|
||||
return 'Unavailable';
|
||||
}
|
||||
|
||||
public function scopeAccessible(Builder $query): Builder
|
||||
{
|
||||
return $query
|
||||
->whereIn('status', [self::STATUS_ACTIVE, self::STATUS_GRACE])
|
||||
->where(function (Builder $inner) {
|
||||
$inner->where('paid_until', '>', now())
|
||||
->orWhere('grace_ends_at', '>', now());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user