mivita/app/Services/SyS/AboOrdersOverview.php
2026-04-10 17:15:27 +02:00

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;
}
}