End-to-end-Aufladung der Credit-Wallet, spiegelt den Einzel-PM-Fluss:
- Paket-Staffel mit Bonus in config/credits.php (10->10, 25->27, 50->55,
100->115 Credits; price_cents netto, Stripe Tax ergaenzt USt.)
- credit_topups (Pending->Paid) + CreditTopupService: startTopup legt den
Pending-Kauf an, fulfill() schreibt die Wallet idempotent gut (credited_at)
- StripeCheckoutService::forCreditTopup via checkoutCharge + credit_topup_id
Metadata; ProcessStripeWebhook schreibt bei checkout.session.completed gut
- Checkout-Route /admin/me/checkout/credits/{pack} mit Rechnungsadress-Gate
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
44 lines
996 B
PHP
44 lines
996 B
PHP
<?php
|
|
|
|
namespace App\Models;
|
|
|
|
use App\Enums\SinglePurchaseStatus;
|
|
use App\Services\Billing\CreditTopupService;
|
|
use Illuminate\Database\Eloquent\Model;
|
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
|
|
|
/**
|
|
* Eine Wallet-Aufladung über Stripe. Anlage/Erfüllung über
|
|
* {@see CreditTopupService}.
|
|
*/
|
|
class CreditTopup extends Model
|
|
{
|
|
protected $fillable = [
|
|
'user_id',
|
|
'pack_key',
|
|
'credits',
|
|
'price_cents',
|
|
'currency',
|
|
'status',
|
|
'stripe_checkout_session_id',
|
|
'stripe_payment_intent_id',
|
|
'paid_at',
|
|
'credited_at',
|
|
];
|
|
|
|
protected function casts(): array
|
|
{
|
|
return [
|
|
'credits' => 'integer',
|
|
'price_cents' => 'integer',
|
|
'status' => SinglePurchaseStatus::class,
|
|
'paid_at' => 'datetime',
|
|
'credited_at' => 'datetime',
|
|
];
|
|
}
|
|
|
|
public function user(): BelongsTo
|
|
{
|
|
return $this->belongsTo(User::class);
|
|
}
|
|
}
|