gruene-seele/resources/views/admin/inventory/orders/index.blade.php
Kevin Adametz c21cc63428 Warenwirtschaft: AP-33a — Abwicklungs-Tabelle kompakter (Namen gekürzt, Positionen ans Ende)
Kundenname mit Ellipsis begrenzt (150px, iPad 110px; voller Name als Tooltip),
Zellen-Padding reduziert, Positionen-Toggle als schmale letzte Spalte —
zusammen mit den Aktionen rechts angepinnt, beim Scrollen bleibt beides sichtbar.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 11:56:31 +00:00

274 lines
18 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

@extends('layouts.layout-2')
@section('content')
@include('admin.inventory.partials.wawi-ui')
<style>
/* AP-33a: iPad-Optimierung — Positionen (letzte Spalte) und Aktionen bleiben
beim horizontalen Scrollen rechts angepinnt, alles andere ist kompakt. */
#of-table th, #of-table td { padding: .45rem .5rem; }
#of-table td { vertical-align: middle; }
#of-table th.of-pos,
#of-table td.of-pos {
position: sticky;
right: 0;
width: 56px;
min-width: 56px;
background: #fff;
text-align: center;
}
#of-table th.of-actions,
#of-table td.of-actions {
position: sticky;
right: 56px;
background: #fff;
box-shadow: -6px 0 6px -6px rgba(24, 28, 33, .15);
white-space: nowrap;
}
#of-table td.of-customer { max-width: 150px; }
#of-table td.of-customer .wawi-item-name {
display: inline-block;
max-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
vertical-align: bottom;
}
@media (max-width: 1199.98px) {
.of-btn-text { display: none; }
#of-table .btn .mr-1 { margin-right: 0 !important; }
#of-table td.of-customer { max-width: 110px; }
}
</style>
<div class="wawi-page">
<div class="wawi-page-head">
<div>
<h1 class="wawi-page-head__title">{{ __('Bestell-Abwicklung') }}</h1>
<p class="wawi-page-head__subtitle">{{ __('Tagesübersicht: konfektionieren, Dokumente drucken, versenden — versandfertig = bezahlt (Rechnung sofort, Vorkasse nach Zahlungseingang, API immer)') }}</p>
</div>
<div class="wawi-page-head__actions">
<a href="{{ route('admin.inventory.api-orders.index') }}" class="btn btn-outline-secondary btn-sm">
<span class="fas fa-cloud-download-alt mr-1"></span>{{ __('API-Bestellungen') }}
</a>
</div>
</div>
<div class="wawi-stats">
<a class="wawi-stat is-clickable text-reset" href="{{ route('admin.inventory.orders.index', ['filter' => 'today']) }}">
<div class="wawi-stat__icon"><span class="fas fa-inbox"></span></div>
<div class="wawi-stat__body">
<div class="wawi-stat__value">{{ $counts['today'] }}</div>
<div class="wawi-stat__label">{{ __('Heute eingegangen') }}</div>
</div>
</a>
<a class="wawi-stat wawi-stat--warning is-clickable text-reset" href="{{ route('admin.inventory.orders.index', ['filter' => 'pick']) }}">
<div class="wawi-stat__icon"><span class="fas fa-box-open"></span></div>
<div class="wawi-stat__body">
<div class="wawi-stat__value">{{ $counts['pick'] }}</div>
<div class="wawi-stat__label">{{ __('Zu konfektionieren') }}</div>
</div>
</a>
<a class="wawi-stat wawi-stat--ok is-clickable text-reset" href="{{ route('admin.inventory.orders.index', ['filter' => 'ready']) }}">
<div class="wawi-stat__icon"><span class="fas fa-truck-loading"></span></div>
<div class="wawi-stat__body">
<div class="wawi-stat__value">{{ $counts['ready'] }}</div>
<div class="wawi-stat__label">{{ __('Versandfertig') }}</div>
</div>
</a>
<a class="wawi-stat is-clickable text-reset" href="{{ route('admin.inventory.orders.index', ['filter' => 'shipped_today']) }}">
<div class="wawi-stat__icon"><span class="fas fa-shipping-fast"></span></div>
<div class="wawi-stat__body">
<div class="wawi-stat__value">{{ $counts['shipped_today'] }}</div>
<div class="wawi-stat__label">{{ __('Heute versendet') }}</div>
</div>
</a>
</div>
<div class="wawi-card">
<div class="wawi-toolbar">
<div class="d-flex align-items-center" style="gap:.75rem;">
@if ($filter !== '')
<a href="{{ route('admin.inventory.orders.index') }}" class="btn btn-sm btn-outline-secondary">
<span class="fas fa-times mr-1"></span>{{ __('Filter zurücksetzen') }}
</a>
@endif
<input type="search" id="of-search" class="form-control form-control-sm" style="width:240px"
placeholder="{{ __('Suche Bestellnr. / Kunde …') }}">
</div>
</div>
<div class="table-responsive">
<table class="table wawi-table" id="of-table">
<thead>
<tr>
<th>{{ __('Bestellung') }}</th>
<th>{{ __('Kunde') }}</th>
<th>{{ __('Status') }}</th>
<th>{{ __('Dokumente') }}</th>
<th class="text-right of-actions">{{ __('Aktionen') }}</th>
<th class="of-pos" title="{{ __('Positionen') }}">{{ __('Pos.') }}</th>
</tr>
</thead>
<tbody>
@forelse ($orders as $order)
@php
$customer = $order->shopping_user
? trim(($order->shopping_user->shipping_firstname ?: $order->shopping_user->billing_firstname ?? '').' '.($order->shopping_user->shipping_lastname ?: $order->shopping_user->billing_lastname ?? ''))
: '';
$clearingtype = $order->shopping_payment_last?->clearingtype;
$readyToShip = $order->isReadyToShip();
$itemCount = $order->shopping_order_items->sum('qty');
@endphp
<tr class="of-row" data-search="{{ mb_strtolower($order->id.' '.$customer) }}">
<td>
<a href="{{ route('admin_sales_detail', $order->id) }}">#{{ $order->id }}</a>
@if ($order->isApiOrder())
<span class="wawi-pill" style="background:rgba(24,28,33,.06);color:#6c757d;">API</span>
@elseif ($order->user_shop_id)
<span class="wawi-pill" style="background:rgba(24,28,33,.06);color:#6c757d;">{{ __('Shop') }}</span>
@elseif ($order->promotion_user_id)
<span class="wawi-pill" style="background:rgba(24,28,33,.06);color:#6c757d;">{{ __('Promo') }}</span>
@endif
<div class="small text-muted">{{ $order->created_at->format('d.m.Y H:i') }}</div>
</td>
<td class="of-customer" title="{{ $customer }}">
<span class="wawi-item-name">{{ $customer !== '' ? $customer : '—' }}</span>
@if ($order->shipping_country?->country)
<span class="text-muted small">{{ strtoupper($order->shipping_country->country->code) }}</span>
@endif
</td>
<td>
@if ((int) $order->shipped === 0)
<span class="wawi-pill wawi-pill--warning">{{ __('offen') }}</span>
@else
<span class="wawi-pill" style="background:rgba(3,155,229,.12);color:#0277bd;">{{ $order->getShippedType() }}</span>
@endif
<div class="small mt-1">
@if ($readyToShip)
<span class="wawi-pill wawi-pill--ok">{{ __('versandfertig') }}</span>
@else
<span class="wawi-pill wawi-pill--danger">{{ __('wartet auf Zahlung') }}</span>
@endif
@if ($clearingtype === 'fnc')
<span class="text-muted">{{ __('Rechnung') }}</span>
@elseif ($clearingtype === 'vor')
<span class="text-muted">{{ __('Vorkasse') }}</span>
@endif
</div>
</td>
<td style="white-space:nowrap;">
@if ($order->isApiOrder())
@if ($order->wp_invoice_path)
<a href="{{ $order->wp_invoice_path }}" target="_blank" rel="noopener" title="{{ __('Externe Rechnung (Shop)') }}">
<span class="fas fa-external-link-alt"></span> {{ __('Extern') }}
</a>
@else
<span class="text-muted small">{{ __('extern') }}</span>
@endif
@elseif (\App\Services\Invoice::isInvoice($order))
<a href="{{ route('admin.inventory.orders.document', [$order->id, 'invoice']) }}" target="_blank" title="{{ __('Rechnung') }}" class="mr-1"><span class="far fa-file-alt"></span> {{ __('Re.') }}</a>
<a href="{{ route('admin.inventory.orders.document', [$order->id, 'delivery']) }}" target="_blank" title="{{ __('Lieferschein') }}" class="mr-1"><span class="fas fa-dolly"></span> {{ __('LS') }}</a>
<a href="{{ route('admin.inventory.orders.document', [$order->id, 'combined']) }}" target="_blank" title="{{ __('Rechnung + Lieferschein') }}"><span class="fas fa-print"></span></a>
@else
<form action="{{ route('admin.inventory.orders.documents', $order->id) }}" method="post" class="d-inline">
@csrf
<input type="hidden" name="back_filter" value="{{ $filter }}">
<button type="submit" class="btn btn-sm btn-outline-secondary" title="{{ __('Rechnung + Lieferschein erstellen (ohne E-Mail-Versand)') }}"
onclick="return confirm(@json(__('Rechnung + Lieferschein jetzt erstellen? (Es wird keine E-Mail versendet — Versand wie gewohnt über die Bestell-Details.)')));">
<span class="fas fa-file-medical mr-1"></span><span class="of-btn-text">{{ __('erstellen') }}</span>
</button>
</form>
@endif
</td>
<td class="text-right of-actions">
@if ((int) $order->shipped === 0)
<form action="{{ route('admin.inventory.orders.status', $order->id) }}" method="post" class="d-inline">
@csrf
<input type="hidden" name="shipped" value="1">
<input type="hidden" name="back_filter" value="{{ $filter }}">
<button type="submit" class="btn btn-sm btn-outline-primary" title="{{ __('Als konfektioniert (in Bearbeitung) markieren') }}">
<span class="fas fa-box mr-1"></span><span class="of-btn-text">{{ __('Konfektioniert') }}</span>
</button>
</form>
@endif
@if (in_array((int) $order->shipped, [0, 1], true))
<form action="{{ route('admin.inventory.orders.status', $order->id) }}" method="post" class="d-inline"
onsubmit="return confirm(@json(__('Bestellung als versendet buchen? Der Produktbestand wird abgezogen.')));">
@csrf
<input type="hidden" name="shipped" value="2">
<input type="hidden" name="back_filter" value="{{ $filter }}">
<button type="submit" class="btn btn-sm btn-primary" title="{{ __('Als versendet buchen (Bestandsabzug)') }}">
<span class="fas fa-shipping-fast mr-1"></span><span class="of-btn-text">{{ __('Versendet') }}</span>
</button>
</form>
@endif
</td>
<td class="of-pos">
<button type="button" class="btn btn-sm btn-link p-0 js-of-toggle" data-target="of-items-{{ $order->id }}" title="{{ __('Packliste anzeigen') }}">
{{ $itemCount }} <span class="fas fa-chevron-down small"></span>
</button>
</td>
</tr>
<tr class="of-items d-none" id="of-items-{{ $order->id }}">
<td colspan="6" class="pl-4" style="background:rgba(24,28,33,.02);">
<strong class="small text-muted">{{ __('Packliste') }}</strong>
@if ($order->weight)
<span class="small text-muted">· {{ __('Gewicht') }}: {{ number_format($order->weight / 1000, 2, ',', '.') }} kg</span>
@endif
<ul class="mb-1 small">
@foreach ($order->shopping_order_items as $item)
<li>
{{ $item->qty }} × {{ $item->product?->name ?? __('(Produkt gelöscht)') }}
@if ($item->product?->is_set)
<span class="wawi-pill" style="background:rgba(24,28,33,.06);color:#6c757d;">SET</span>
<ul class="text-muted">
@foreach ($item->product->setItems as $component)
<li>{{ $item->qty * $component->pivot->quantity }} × {{ $component->name }}</li>
@endforeach
</ul>
@endif
</li>
@endforeach
</ul>
</td>
</tr>
@empty
<tr>
<td colspan="6">
<div class="wawi-empty">
<div><span class="fas fa-mug-hot"></span></div>
{{ __('Nichts zu tun — keine Bestellungen in diesem Filter.') }}
</div>
</td>
</tr>
@endforelse
</tbody>
</table>
</div>
@if (($listLimit ?? null) !== null && $orders->count() >= $listLimit)
<p class="text-muted small px-3 pb-2 mb-0">
{{ __('Es werden die neuesten :n Bestellungen angezeigt.', ['n' => $listLimit]) }}
<a href="{{ route('admin.inventory.orders.index', array_filter(['all' => 1, 'filter' => $filter])) }}">{{ __('Alle anzeigen') }}</a>
</p>
@endif
</div>
</div>
<script>
$(function () {
$('.js-of-toggle').on('click', function () {
$('#' + $(this).data('target')).toggleClass('d-none');
});
$('#of-search').on('input', function () {
var term = ($(this).val() || '').toLowerCase().trim();
$('#of-table tbody tr.of-row').each(function () {
var show = term === '' || ($(this).data('search') || '').toString().indexOf(term) !== -1;
$(this).toggle(show);
if (!show) {
$('#of-items-' + $(this).find('a').first().text().replace('#', '')).addClass('d-none');
}
});
});
});
</script>
@endsection