127 lines
4.4 KiB
PHP
127 lines
4.4 KiB
PHP
<?php
|
|
|
|
namespace App\Services\SyS;
|
|
|
|
use App\Models\ShoppingOrder;
|
|
use App\Models\UserAboOrder;
|
|
|
|
class AboOrdersOverview
|
|
{
|
|
/**
|
|
* Payone-/Shop-Zahlungsstatus: tatsächlich eingezogen.
|
|
*
|
|
* @var list<string>
|
|
*/
|
|
private const SUCCESS_TXACTIONS = ['paid', 'extern_paid', 'invoice_paid'];
|
|
|
|
public static function show()
|
|
{
|
|
$filter = request('filter', 'all');
|
|
|
|
$aboOrders = UserAboOrder::with([
|
|
'user_abo',
|
|
'user_abo.user',
|
|
'user_abo.user.account',
|
|
'shopping_order',
|
|
'shopping_order.shopping_user',
|
|
'shopping_order.shopping_payments',
|
|
])
|
|
->whereHas('shopping_order')
|
|
->when($filter === 'berater', fn ($q) => $q->whereHas('user_abo', fn ($q) => $q->where('is_for', 'me')))
|
|
->when($filter === 'kunde', fn ($q) => $q->whereHas('user_abo', fn ($q) => $q->where('is_for', '!=', 'me')))
|
|
->orderByDesc('created_at')
|
|
->get();
|
|
|
|
$summary = [
|
|
'total_orders' => $aboOrders->count(),
|
|
'total_diff' => 0.0,
|
|
'affected_orders' => 0,
|
|
];
|
|
|
|
$rows = [];
|
|
|
|
foreach ($aboOrders as $aboOrder) {
|
|
$order = $aboOrder->shopping_order;
|
|
if (! $order) {
|
|
continue;
|
|
}
|
|
|
|
$subtotalWs = (float) $order->subtotal_ws;
|
|
$totalShipping = (float) $order->total_shipping;
|
|
$tax = (float) $order->tax;
|
|
|
|
$expectedCents = (int) round($totalShipping * 100);
|
|
$actualCents = self::actualChargedCentsFromPayments($order);
|
|
|
|
$actualEur = $actualCents !== null ? round($actualCents / 100, 2) : null;
|
|
$diff = ($actualCents !== null)
|
|
? round(($expectedCents - $actualCents) / 100, 2)
|
|
: null;
|
|
|
|
if ($diff !== null && abs($diff) <= 0.01) {
|
|
$diff = 0;
|
|
}
|
|
|
|
$payments = $order->shopping_payments;
|
|
$paymentTxSummary = $payments->isEmpty()
|
|
? null
|
|
: $payments->pluck('txaction')->filter()->unique()->implode(', ');
|
|
|
|
$user = $aboOrder->user_abo->user ?? null;
|
|
|
|
$rows[] = [
|
|
'abo_order_id' => $aboOrder->id,
|
|
'abo_id' => $aboOrder->user_abo_id,
|
|
'order_id' => '<a href='.route('admin_sales_customers_detail', [$aboOrder->shopping_order_id]).'>'.$aboOrder->shopping_order_id.'</a>',
|
|
'user_id' => $user->id ?? null,
|
|
'user_name' => $aboOrder->shopping_order->shopping_user ? ($aboOrder->shopping_order->shopping_user->billing_firstname ?? '').' '.($aboOrder->shopping_order->shopping_user->billing_lastname ?? '') : '-',
|
|
'user_email' => $aboOrder->shopping_order->shopping_user ? $aboOrder->shopping_order->shopping_user->billing_email ?? '-' : '-',
|
|
'is_for' => $aboOrder->user_abo->is_for ?? '-',
|
|
'subtotal_ws' => $subtotalWs,
|
|
'tax' => $tax,
|
|
'total_shipping' => $totalShipping,
|
|
'actual_charged_eur' => $actualEur,
|
|
'payment_count' => $payments->count(),
|
|
'payment_txactions' => $paymentTxSummary,
|
|
'diff' => $diff,
|
|
'status' => $aboOrder->status,
|
|
'paid' => $aboOrder->paid,
|
|
'txaction' => $order->txaction,
|
|
'created_at' => $aboOrder->created_at,
|
|
];
|
|
|
|
if ($diff !== null && abs($diff) >= 0.01) {
|
|
$summary['total_diff'] += $diff;
|
|
$summary['affected_orders']++;
|
|
}
|
|
}
|
|
|
|
$summary['total_diff'] = round($summary['total_diff'], 2);
|
|
|
|
return view('sys.tools.abo-orders-overview', [
|
|
'rows' => $rows,
|
|
'summary' => $summary,
|
|
'filter' => $filter,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Summiert erfolgreiche Abbuchungen aus `shopping_payments` (Cent).
|
|
* Kein Treffer bei erfolgreichen Status → null (kein belastbarer Eingang).
|
|
*/
|
|
public static function actualChargedCentsFromPayments(ShoppingOrder $order): ?int
|
|
{
|
|
$payments = $order->shopping_payments;
|
|
if ($payments === null || $payments->isEmpty()) {
|
|
return null;
|
|
}
|
|
|
|
$successful = $payments->filter(
|
|
fn ($p) => in_array($p->txaction, self::SUCCESS_TXACTIONS, true)
|
|
);
|
|
|
|
$sum = (int) $successful->sum('amount');
|
|
|
|
return $sum > 0 ? $sum : null;
|
|
}
|
|
}
|