328 lines
20 KiB
PHP
328 lines
20 KiB
PHP
@extends('layouts.layout-2')
|
|
|
|
@section('content')
|
|
|
|
<div class="d-flex justify-content-between align-items-center mb-3">
|
|
<div>
|
|
<a href="{{ route('admin.payment-dashboard.index') }}" class="btn btn-sm btn-outline-secondary mr-2">
|
|
<i class="ion ion-md-arrow-back"></i> Zurück
|
|
</a>
|
|
<strong>Zahlungs-Übersicht</strong>
|
|
<small class="text-muted ml-2">ShoppingPayments mit Transaktionen und Bestellung</small>
|
|
</div>
|
|
</div>
|
|
|
|
{{-- Stat-Karten --}}
|
|
<div class="row mb-4">
|
|
<div class="col-6 col-xl-2">
|
|
<div class="card">
|
|
<div class="card-body text-center py-2">
|
|
<div class="text-muted small">Zahlungen gesamt</div>
|
|
<div class="h4 font-weight-bold mb-0">{{ $paymentStats['total'] }}</div>
|
|
<div class="text-muted" style="font-size:0.7rem">{{ $paymentStats['days'] }} Tage</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-6 col-xl-2">
|
|
<div class="card">
|
|
<div class="card-body text-center py-2">
|
|
<div class="text-muted small">Bezahlt</div>
|
|
<div class="h4 font-weight-bold mb-0 text-success">{{ $paymentStats['paid'] }}</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-6 col-xl-2">
|
|
<div class="card {{ $paymentStats['failed'] > 0 ? 'border-danger' : '' }}">
|
|
<div class="card-body text-center py-2">
|
|
<div class="text-muted small">Mit Fehler</div>
|
|
<div class="h4 font-weight-bold mb-0 {{ $paymentStats['failed'] > 0 ? 'text-danger' : 'text-muted' }}">
|
|
{{ $paymentStats['failed'] }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-6 col-xl-2">
|
|
<div class="card">
|
|
<div class="card-body text-center py-2">
|
|
<div class="text-muted small">Ausstehend</div>
|
|
<div class="h4 font-weight-bold mb-0 text-warning">{{ $paymentStats['pending'] }}</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-6 col-xl-2">
|
|
<div class="card">
|
|
<div class="card-body text-center py-2">
|
|
<div class="text-muted small">Volumen gesamt</div>
|
|
<div class="h5 font-weight-bold mb-0">{{ number_format($paymentStats['total_amount'], 2, ',', '.') }} €</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-6 col-xl-2">
|
|
<div class="card {{ $paymentStats['failed_amount'] > 0 ? 'border-danger' : '' }}">
|
|
<div class="card-body text-center py-2">
|
|
<div class="text-muted small">Fehlvolumen</div>
|
|
<div class="h5 font-weight-bold mb-0 {{ $paymentStats['failed_amount'] > 0 ? 'text-danger' : 'text-muted' }}">
|
|
{{ number_format($paymentStats['failed_amount'], 2, ',', '.') }} €
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{{-- Filter --}}
|
|
<div class="card mb-3">
|
|
<div class="card-body py-2">
|
|
<form method="GET" action="{{ route('admin.payment-dashboard.payments') }}" class="form-inline flex-wrap">
|
|
<label class="mr-2 small">Zeitraum:</label>
|
|
<select name="days" class="custom-select custom-select-sm mr-3 mb-1" onchange="this.form.submit()">
|
|
@foreach([1 => 'Heute', 7 => '7 Tage', 14 => '14 Tage', 30 => '30 Tage', 0 => 'Alle'] as $val => $label)
|
|
<option value="{{ $val }}" {{ (int)$days === $val ? 'selected' : '' }}>{{ $label }}</option>
|
|
@endforeach
|
|
</select>
|
|
<label class="mr-2 small">Status:</label>
|
|
<select name="txaction" class="custom-select custom-select-sm mr-3 mb-1" onchange="this.form.submit()">
|
|
<option value="">Alle</option>
|
|
@foreach(['paid' => 'Bezahlt', 'appointed' => 'Vorgemerkt', 'pending' => 'Ausstehend', 'failed' => 'Fehlgeschlagen'] as $val => $label)
|
|
<option value="{{ $val }}" {{ $statusFilter === $val ? 'selected' : '' }}>{{ $label }}</option>
|
|
@endforeach
|
|
</select>
|
|
<label class="mr-2 small">Modus:</label>
|
|
<select name="mode" class="custom-select custom-select-sm mr-3 mb-1" onchange="this.form.submit()">
|
|
<option value="">Alle</option>
|
|
<option value="live" {{ $modeFilter === 'live' ? 'selected' : '' }}>Live</option>
|
|
<option value="test" {{ $modeFilter === 'test' ? 'selected' : '' }}>Test</option>
|
|
</select>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
{{-- Zahlungs-Tabelle --}}
|
|
<div class="card">
|
|
<div class="card-body p-0">
|
|
<div class="table-responsive">
|
|
<table class="table table-sm table-hover mb-0">
|
|
<thead class="thead-light">
|
|
<tr>
|
|
<th style="width:30px"></th>
|
|
<th>Payment ID</th>
|
|
<th>Bestellung</th>
|
|
<th>Kunde</th>
|
|
<th>Zahlart</th>
|
|
<th>Betrag</th>
|
|
<th>Status</th>
|
|
<th>Modus</th>
|
|
<th>Transaktionen</th>
|
|
<th>Datum</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@forelse($payments as $payment)
|
|
@php
|
|
$hasFailed = $payment->payment_transactions->where('txaction', 'failed')->count() > 0;
|
|
$isPaid = $payment->txaction === 'paid';
|
|
$rowClass = $hasFailed ? 'table-danger' : ($isPaid ? 'table-success' : '');
|
|
@endphp
|
|
<tr class="{{ $rowClass }}">
|
|
<td class="text-center align-middle">
|
|
@if($payment->payment_transactions->count() > 0)
|
|
<button class="btn btn-sm btn-link p-0 text-muted"
|
|
data-toggle="collapse"
|
|
data-target="#tx-{{ $payment->id }}"
|
|
title="{{ $payment->payment_transactions->count() }} Transaktionen">
|
|
<i class="ion ion-md-arrow-dropdown"></i>
|
|
</button>
|
|
@endif
|
|
</td>
|
|
<td class="align-middle">
|
|
<code class="small">{{ $payment->reference }}</code>
|
|
</td>
|
|
<td class="align-middle">
|
|
@if($payment->shopping_order)
|
|
@php
|
|
$isCustomerOrder = in_array($payment->shopping_order->payment_for, [6, 7]);
|
|
$orderRoute = $isCustomerOrder
|
|
? route('admin_sales_customers_detail', $payment->shopping_order->id)
|
|
: route('admin_sales_users_detail', $payment->shopping_order->id);
|
|
@endphp
|
|
<a href="{{ $orderRoute }}" class="font-weight-bold" target="_blank">
|
|
#{{ $payment->shopping_order->id }}
|
|
</a>
|
|
@if($payment->shopping_order->paid)
|
|
<i class="ion ion-md-checkmark-circle text-success ml-1" title="Bezahlt"></i>
|
|
@endif
|
|
<div class="text-muted" style="font-size:0.7rem">
|
|
{{ number_format($payment->shopping_order->total ?? 0, 2, ',', '.') }} €
|
|
</div>
|
|
@else
|
|
<span class="text-muted">—</span>
|
|
@endif
|
|
</td>
|
|
<td class="align-middle small">
|
|
@if($payment->shopping_order?->auth_user_id && $payment->shopping_order->auth_user)
|
|
{{-- Berater-Bestellung --}}
|
|
<span class="badge badge-primary mb-1">Berater</span>
|
|
<div>{{ $payment->shopping_order->auth_user->name }}</div>
|
|
<div class="text-muted" style="font-size:0.7rem">
|
|
{{ $payment->shopping_order->auth_user->email }}
|
|
</div>
|
|
@elseif($payment->shopping_order?->shopping_user)
|
|
{{-- Kunden-Bestellung --}}
|
|
@php $su = $payment->shopping_order->shopping_user; @endphp
|
|
<span class="badge badge-info mb-1">Kunde</span>
|
|
<div>
|
|
{{ trim($su->billing_firstname . ' ' . $su->billing_lastname) ?: '—' }}
|
|
</div>
|
|
<div class="text-muted" style="font-size:0.7rem">
|
|
{{ $su->billing_email }}
|
|
</div>
|
|
@else
|
|
<span class="text-muted">—</span>
|
|
@endif
|
|
</td>
|
|
<td class="align-middle small">
|
|
{{ $payment->getPaymentType() }}
|
|
@if($payment->clearingtype)
|
|
<span class="badge badge-secondary ml-1">{{ $payment->clearingtype }}</span>
|
|
@endif
|
|
</td>
|
|
<td class="align-middle text-nowrap">
|
|
<strong>{{ number_format($payment->amount / 100, 2, ',', '.') }}</strong>
|
|
<small class="text-muted">{{ $payment->currency }}</small>
|
|
</td>
|
|
<td class="align-middle">
|
|
@php
|
|
$txColor = match($payment->txaction) {
|
|
'paid' => 'success',
|
|
'failed' => 'danger',
|
|
'appointed' => 'info',
|
|
'pending' => 'warning',
|
|
default => 'secondary',
|
|
};
|
|
@endphp
|
|
<span class="badge badge-{{ $txColor }}">{{ $payment->txaction ?? '—' }}</span>
|
|
@if($hasFailed && $isPaid)
|
|
<span class="badge badge-warning ml-1" title="Hatte fehlerhafte Transaktionen">
|
|
<i class="ion ion-md-warning"></i>
|
|
</span>
|
|
@endif
|
|
</td>
|
|
<td class="align-middle">
|
|
@if($payment->mode)
|
|
<span class="badge badge-{{ $payment->mode === 'test' ? 'warning' : 'light' }}">
|
|
{{ $payment->mode }}
|
|
</span>
|
|
@endif
|
|
</td>
|
|
<td class="align-middle text-center">
|
|
@if($payment->payment_transactions->count() > 0)
|
|
<span class="badge badge-{{ $hasFailed ? 'danger' : 'secondary' }}">
|
|
{{ $payment->payment_transactions->count() }}
|
|
</span>
|
|
@else
|
|
<span class="text-muted">0</span>
|
|
@endif
|
|
</td>
|
|
<td class="align-middle text-nowrap small text-muted">
|
|
{{ $payment->created_at->format('d.m.Y H:i') }}
|
|
</td>
|
|
</tr>
|
|
|
|
{{-- Aufklappbare Transaktions-Sub-Tabelle --}}
|
|
@if($payment->payment_transactions->count() > 0)
|
|
<tr class="collapse" id="tx-{{ $payment->id }}">
|
|
<td colspan="10" class="p-0">
|
|
<div class="bg-light border-bottom px-3 py-2">
|
|
<small class="font-weight-bold text-muted text-uppercase">
|
|
Transaktionen zu Payment #{{ $payment->id }} / Referenz {{ $payment->reference }}
|
|
</small>
|
|
</div>
|
|
<table class="table table-sm table-bordered mb-0" style="background:#fafafa">
|
|
<thead>
|
|
<tr class="bg-light">
|
|
<th class="pl-4">TX-ID</th>
|
|
<th>Aktion</th>
|
|
<th>Status</th>
|
|
<th>Fehlercode</th>
|
|
<th>Fehlermeldung</th>
|
|
<th>Kundennachricht</th>
|
|
<th>Modus</th>
|
|
<th>Datum</th>
|
|
<th></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@foreach($payment->payment_transactions as $tx)
|
|
<tr class="{{ $tx->txaction === 'failed' ? 'table-danger' : ($tx->txaction === 'paid' ? 'table-success' : '') }}">
|
|
<td class="pl-4 small">{{ $tx->txid ?? '—' }}</td>
|
|
<td>
|
|
@php
|
|
$txaColor = match($tx->txaction) {
|
|
'paid' => 'success', 'failed' => 'danger',
|
|
'appointed' => 'info', 'pending' => 'warning',
|
|
default => 'secondary',
|
|
};
|
|
@endphp
|
|
<span class="badge badge-{{ $txaColor }}">{{ $tx->txaction ?? '—' }}</span>
|
|
</td>
|
|
<td class="small">{{ $tx->status ?? '—' }}</td>
|
|
<td>
|
|
@if($tx->errorcode)
|
|
<span class="text-danger font-weight-bold">{{ $tx->errorcode }}</span>
|
|
@else
|
|
<span class="text-muted">—</span>
|
|
@endif
|
|
</td>
|
|
<td class="small text-muted" style="max-width:200px">
|
|
{{ \Illuminate\Support\Str::limit($tx->errormessage, 60) }}
|
|
</td>
|
|
<td class="small text-muted" style="max-width:150px">
|
|
{{ \Illuminate\Support\Str::limit($tx->customermessage, 50) }}
|
|
</td>
|
|
<td>
|
|
@if($tx->mode)
|
|
<span class="badge badge-{{ $tx->mode === 'test' ? 'warning' : 'light' }}">{{ $tx->mode }}</span>
|
|
@endif
|
|
</td>
|
|
<td class="text-nowrap small text-muted">{{ $tx->created_at->format('d.m.Y H:i') }}</td>
|
|
<td>
|
|
@if($tx->transmitted_data)
|
|
<button class="btn btn-xs btn-outline-secondary"
|
|
data-toggle="collapse"
|
|
data-target="#raw-{{ $tx->id }}"
|
|
title="Rohdaten">
|
|
<i class="ion ion-md-code"></i>
|
|
</button>
|
|
@endif
|
|
</td>
|
|
</tr>
|
|
@if($tx->transmitted_data)
|
|
<tr class="collapse" id="raw-{{ $tx->id }}">
|
|
<td colspan="9" class="bg-white">
|
|
<pre class="mb-0 small" style="max-height:150px; overflow-y:auto; font-size:0.75rem">{{ json_encode($tx->transmitted_data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) }}</pre>
|
|
</td>
|
|
</tr>
|
|
@endif
|
|
@endforeach
|
|
</tbody>
|
|
</table>
|
|
</td>
|
|
</tr>
|
|
@endif
|
|
@empty
|
|
<tr>
|
|
<td colspan="10" class="text-center text-muted py-4">
|
|
Keine Zahlungen im gewählten Zeitraum gefunden.
|
|
</td>
|
|
</tr>
|
|
@endforelse
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mt-3">
|
|
{{ $payments->links() }}
|
|
</div>
|
|
|
|
@endsection
|