mivita/app/Models/OrderWithdrawal.php
Kevin 63c36555a5 Widerruf: Gesetzliche Online-Widerrufsfunktion (Formular, Bestätigungsmail, Admin-Verwaltung)
- Öffentliches Widerrufsformular /widerruf mit Bestell-Lookup (throttled)
- Bestätigungsmail an Kunde + Weiterleitung an bestellungen@ (config app.withdrawal_mail)
- Admin-Übersicht/-Detail unter /admin/withdrawals inkl. Sidenav-Eintrag
- Widerruf-Button in Portal-Bestellansicht und Footer-Links
- Model OrderWithdrawal + Migration + Factory + Tests

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-08 15:56:02 +00:00

107 lines
2.6 KiB
PHP

<?php
namespace App\Models;
use Database\Factories\OrderWithdrawalFactory;
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;
use Illuminate\Support\Carbon;
/**
* Online-Widerruf einer Verbraucherbestellung (gesetzliche Widerrufs-Button-Pflicht).
*
* @property int $id
* @property int|null $shopping_order_id
* @property int|null $user_shop_id
* @property string $type
* @property string $status
* @property string|null $order_reference
* @property string $customer_email
* @property string|null $customer_name
* @property string|null $reason
* @property array|null $items
* @property string|null $ip_address
* @property string|null $user_agent
* @property string|null $admin_note
* @property Carbon|null $declared_at
*/
class OrderWithdrawal extends Model
{
/** @use HasFactory<OrderWithdrawalFactory> */
use HasFactory, SoftDeletes;
public const TYPE_FULL = 'full';
public const TYPE_PARTIAL = 'partial';
public const STATUS_RECEIVED = 'received';
public const STATUS_PROCESSING = 'processing';
public const STATUS_DONE = 'done';
public const STATUS_REJECTED = 'rejected';
protected $fillable = [
'shopping_order_id',
'user_shop_id',
'type',
'status',
'order_reference',
'customer_email',
'customer_name',
'reason',
'items',
'ip_address',
'user_agent',
'admin_note',
'declared_at',
];
/**
* @return array<string, string>
*/
protected function casts(): array
{
return [
'items' => 'array',
'declared_at' => 'datetime',
];
}
public function shopping_order(): BelongsTo
{
return $this->belongsTo(ShoppingOrder::class, 'shopping_order_id');
}
public function user_shop(): BelongsTo
{
return $this->belongsTo(UserShop::class, 'user_shop_id');
}
public function scopeReceived(Builder $query): Builder
{
return $query->where('status', self::STATUS_RECEIVED);
}
/**
* @return array<int, string>
*/
public static function statuses(): array
{
return [
self::STATUS_RECEIVED,
self::STATUS_PROCESSING,
self::STATUS_DONE,
self::STATUS_REJECTED,
];
}
public function isFullWithdrawal(): bool
{
return $this->type === self::TYPE_FULL;
}
}