|ShoppingPayment whereIdentifier($value) * * @mixin \Eloquent */ class ShoppingPayment extends Model { protected $table = 'shopping_payments'; protected $casts = [ 'carddata' => 'array', ]; protected $fillable = [ 'shopping_order_id', 'payment_provider', 'external_reference', 'clearingtype', 'wallettype', 'onlinebanktransfertype', 'carddata', 'reference', 'amount', 'currency', 'mode', 'is_abo', 'abo_interval', 'identifier', 'stripe_customer_id', 'stripe_payment_method_id', 'user_abo_id', ]; public function shopping_order() { return $this->belongsTo('App\Models\ShoppingOrder', 'shopping_order_id'); } public function payment_transactions() { return $this->hasMany('App\Models\PaymentTransaction', 'shopping_payment_id'); } public function getPaymentType() { if ($this->payment_provider === 'stripe') { return $this->stripePaymentTypeLabel(); } if ($this->clearingtype === 'wlt') { if ($this->wallettype === 'PPE') { return __('payment.paypal'); } } if ($this->clearingtype === 'cc') { return __('payment.credit_card'); } if ($this->clearingtype === 'vor') { return __('payment.prepayment'); } if ($this->clearingtype === 'elv') { return __('payment.sepa_direct_debit'); } if ($this->clearingtype === 'sb') { if ($this->onlinebanktransfertype === 'PNT') { return __('payment.sofort_bank_transfer'); } } if ($this->clearingtype === 'fnc') { if ($this->onlinebanktransfertype === 'MIV') { return __('payment.purchase_on_account'); } } return __('payment.unknown'); } public function getPaymentAmount() { return Util::formatNumber($this->amount / 100).' '.$this->currency; } /** * Anzeige-Label für Stripe-Zahlungen aus den gespeicherten * payment_method_details (StripeWebhookHandler::storePaymentMethodDetails). */ private function stripePaymentTypeLabel(): string { return self::stripeLabelFromSummary(is_array($this->carddata) ? $this->carddata : []); } /** * Statisch nutzbar für alle Stellen mit derselben carddata-Summary * (z. B. UserAbo::getPaymentType für Stripe-Abos). * * @param array $details */ public static function stripeLabelFromSummary(array $details): string { $type = $details['type'] ?? null; $cardSuffix = ! empty($details['brand']) && ! empty($details['last4']) ? ' ('.ucfirst($details['brand']).' •••• '.$details['last4'].')' : ''; if ($type === 'card') { $wallet = $details['wallet'] ?? null; if ($wallet === 'apple_pay') { return 'Apple Pay'.$cardSuffix; } if ($wallet === 'google_pay') { return 'Google Pay'.$cardSuffix; } return __('payment.credit_card').$cardSuffix; } return match ($type) { 'paypal' => __('payment.paypal'), 'klarna' => 'Klarna', 'amazon_pay' => 'Amazon Pay', 'sepa_debit' => __('payment.sepa_direct_debit').(! empty($details['last4']) ? ' (•••• '.$details['last4'].')' : ''), default => __('payment.stripe_online_short'), }; } /** * Deep-Link ins Stripe-Dashboard, sobald ein PaymentIntent zugeordnet ist * (external_reference; vor dem ersten Webhook steht dort noch die Session-ID). */ public function stripeDashboardUrl(): ?string { if ($this->payment_provider !== 'stripe' || ! str_starts_with((string) $this->external_reference, 'pi_')) { return null; } $base = $this->mode === 'test' ? 'https://dashboard.stripe.com/test' : 'https://dashboard.stripe.com'; return $base.'/payments/'.$this->external_reference; } }