DHL Modul v0.5 Shipping Label ok

This commit is contained in:
Kevin Adametz 2025-08-22 18:18:26 +02:00
parent 480fdc65ed
commit 8fdaa0ba1d
122 changed files with 17938 additions and 2239 deletions

View file

@ -0,0 +1,600 @@
@extends('layouts.layout-2')
@section('content')
<div class="d-flex justify-content-between align-items-center py-2 mb-4">
<h4 class="font-weight-bold mb-0">
<i class="fas fa-box text-primary"></i>
DHL Sendung #{{ $shipment->id }}
@if($shipment->type == 'return')
<span class="badge badge-info ml-2">
<i class="fas fa-undo"></i> Retoure
</span>
@endif
</h4>
<div>
<a href="{{ route('admin.dhl.cockpit') }}" class="btn btn-outline-secondary">
<i class="fas fa-arrow-left"></i> Zurück zum Cockpit
</a>
@if($shipment->shoppingOrder)
<a href="{{ route('admin_sales_customers_detail', $shipment->shoppingOrder->id) }}"
class="btn btn-outline-primary ml-2">
<i class="fas fa-shopping-cart"></i> Bestellung anzeigen
</a>
@endif
</div>
</div>
<!-- Status & Key Info Row -->
<div class="row mb-4">
<div class="col-xl-3 col-md-6 mb-3">
<div class="card border-left-primary">
<div class="card-body">
<div class="d-flex justify-content-between">
<div>
<div class="text-xs font-weight-bold text-primary text-uppercase mb-1">Status</div>
@switch($shipment->status)
@case('pending')
<div class="h5 mb-0 font-weight-bold text-gray-800">
<span class="badge badge-warning">Wartend</span>
</div>
@break
@case('created')
<div class="h5 mb-0 font-weight-bold text-gray-800">
<span class="badge badge-success">Erstellt</span>
</div>
@break
@case('shipped')
<div class="h5 mb-0 font-weight-bold text-gray-800">
<span class="badge badge-primary">Versendet</span>
</div>
@break
@case('delivered')
<div class="h5 mb-0 font-weight-bold text-gray-800">
<span class="badge badge-info">Zugestellt</span>
</div>
@break
@case('cancelled')
<div class="h5 mb-0 font-weight-bold text-gray-800">
<span class="badge badge-secondary">Storniert</span>
</div>
@break
@case('failed')
<div class="h5 mb-0 font-weight-bold text-gray-800">
<span class="badge badge-danger">Fehler</span>
</div>
@break
@default
<div class="h5 mb-0 font-weight-bold text-gray-800">
<span class="badge badge-light">{{ $shipment->status }}</span>
</div>
@endswitch
</div>
<div class="col-auto">
<i class="fas fa-flag fa-2x text-gray-300"></i>
</div>
</div>
</div>
</div>
</div>
<div class="col-xl-3 col-md-6 mb-3">
<div class="card border-left-success">
<div class="card-body">
<div class="d-flex justify-content-between">
<div>
<div class="text-xs font-weight-bold text-success text-uppercase mb-1">Sendungsnummer</div>
<div class="h6 mb-0 font-weight-bold text-gray-800">
@if($shipment->shipment_number)
<code class="text-success">{{ $shipment->shipment_number }}</code>
@else
<span class="text-muted">Nicht verfügbar</span>
@endif
</div>
</div>
<div class="col-auto">
<i class="fas fa-hashtag fa-2x text-gray-300"></i>
</div>
</div>
</div>
</div>
</div>
<div class="col-xl-3 col-md-6 mb-3">
<div class="card border-left-info">
<div class="card-body">
<div class="d-flex justify-content-between">
<div>
<div class="text-xs font-weight-bold text-info text-uppercase mb-1">Tracking-Nummer</div>
<div class="h6 mb-0 font-weight-bold text-gray-800">
@if($shipment->tracking_number)
<code class="text-info">{{ $shipment->tracking_number }}</code>
<br>
<a href="{{ route('public.tracking') }}?tracking_number={{ $shipment->tracking_number }}"
target="_blank" class="text-muted small">
<i class="fas fa-external-link-alt"></i> Verfolgen
</a>
@else
<span class="text-muted">Nicht verfügbar</span>
@endif
</div>
</div>
<div class="col-auto">
<i class="fas fa-search fa-2x text-gray-300"></i>
</div>
</div>
</div>
</div>
</div>
<div class="col-xl-3 col-md-6 mb-3">
<div class="card border-left-warning">
<div class="card-body">
<div class="d-flex justify-content-between">
<div>
<div class="text-xs font-weight-bold text-warning text-uppercase mb-1">Gewicht</div>
<div class="h5 mb-0 font-weight-bold text-gray-800">
{{ number_format($shipment->weight, 2) }} kg
</div>
</div>
<div class="col-auto">
<i class="fas fa-weight fa-2x text-gray-300"></i>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Action Buttons -->
@if($shipment->status != 'cancelled')
<div class="card mb-4">
<div class="card-body">
<div class="d-flex flex-wrap gap-2">
@if($shipment->label_path)
<a href="{{ route('admin.dhl.download-label', $shipment) }}"
class="btn btn-success mr-2">
<i class="fas fa-download"></i> Label herunterladen
</a>
@endif
@if($shipment->canCancel())
<button type="button"
class="btn btn-warning mr-2"
id="cancel-shipment-btn"
data-shipment-id="{{ $shipment->id }}">
<i class="fas fa-ban"></i> Sendung stornieren
</button>
@endif
@if($shipment->type == 'outbound' && !$shipment->relatedShipment)
<button type="button"
class="btn btn-info mr-2"
id="create-return-btn"
data-shipment-id="{{ $shipment->id }}">
<i class="fas fa-undo"></i> Retourenlabel erstellen
</button>
@endif
@if($shipment->tracking_number)
<button type="button"
class="btn btn-secondary mr-2"
id="update-tracking-btn"
data-shipment-id="{{ $shipment->id }}">
<i class="fas fa-sync"></i> Tracking aktualisieren
</button>
@endif
</div>
</div>
</div>
@endif
<!-- Shipment Details -->
<div class="row">
<!-- Left Column -->
<div class="col-lg-8">
<!-- Shipment Information -->
<div class="card mb-4">
<div class="card-header">
<h5 class="mb-0">
<i class="fas fa-info-circle text-primary"></i>
Sendungsinformationen
</h5>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-6">
<table class="table table-sm">
<tr>
<td class="font-weight-semibold">ID:</td>
<td>#{{ $shipment->id }}</td>
</tr>
<tr>
<td class="font-weight-semibold">Typ:</td>
<td>
@if($shipment->type == 'outbound')
<span class="badge badge-primary">
<i class="fas fa-arrow-right"></i> Ausgehend
</span>
@else
<span class="badge badge-info">
<i class="fas fa-undo"></i> Retoure
</span>
@if($shipment->relatedShipment)
<br>
<small class="text-muted">
Bezieht sich auf Sendung
<a href="{{ route('admin.dhl.show', $shipment->relatedShipment) }}">
#{{ $shipment->relatedShipment->id }}
</a>
</small>
@endif
@endif
</td>
</tr>
<tr>
<td class="font-weight-semibold">Produktcode:</td>
<td><code>{{ $shipment->product_code }}</code></td>
</tr>
<tr>
<td class="font-weight-semibold">Label-Format:</td>
<td>{{ strtoupper($shipment->label_format) }}</td>
</tr>
<tr>
<td class="font-weight-semibold">Label gedruckt:</td>
<td>
@if($shipment->label_printed)
<span class="badge badge-success">Ja</span>
@else
<span class="badge badge-secondary">Nein</span>
@endif
</td>
</tr>
</table>
</div>
<div class="col-md-6">
<table class="table table-sm">
<tr>
<td class="font-weight-semibold">Erstellt:</td>
<td>{{ $shipment->created_at->format('d.m.Y H:i:s') }}</td>
</tr>
<tr>
<td class="font-weight-semibold">Letzte Änderung:</td>
<td>{{ $shipment->updated_at->format('d.m.Y H:i:s') }}</td>
</tr>
@if($shipment->last_tracked_at)
<tr>
<td class="font-weight-semibold">Letztes Tracking:</td>
<td>{{ $shipment->last_tracked_at->format('d.m.Y H:i:s') }}</td>
</tr>
@endif
@if($shipment->length || $shipment->width || $shipment->height)
<tr>
<td class="font-weight-semibold">Abmessungen:</td>
<td>
{{ $shipment->length }}×{{ $shipment->width }}×{{ $shipment->height }} cm
</td>
</tr>
@endif
</table>
</div>
</div>
</div>
</div>
<!-- Order Information -->
@if($shipment->shoppingOrder)
<div class="card mb-4">
<div class="card-header">
<h5 class="mb-0">
<i class="fas fa-shopping-cart text-success"></i>
Bestellinformationen
</h5>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-6">
<table class="table table-sm">
<tr>
<td class="font-weight-semibold">Bestellungs-ID:</td>
<td>
<a href="{{ route('admin_sales_customers_detail', $shipment->shoppingOrder->id) }}" class="text-primary">
#{{ $shipment->shoppingOrder->id }}
</a>
</td>
</tr>
<tr>
<td class="font-weight-semibold">Kunde:</td>
<td>
@if($shipment->shoppingOrder->shopping_user)
{{ $shipment->shoppingOrder->shopping_user->billing_firstname }} {{ $shipment->shoppingOrder->shopping_user->billing_lastname }}
<br>
<small class="text-muted">{{ $shipment->shoppingOrder->shopping_user->billing_email }}</small>
@else
<span class="text-muted">Unbekannt</span>
@endif
</td>
</tr>
<tr>
<td class="font-weight-semibold">Bestelldatum:</td>
<td>{{ $shipment->shoppingOrder->created_at->format('d.m.Y H:i') }}</td>
</tr>
</table>
</div>
<div class="col-md-6">
<table class="table table-sm">
<tr>
<td class="font-weight-semibold">Bestellwert:</td>
<td><strong>{{ number_format($shipment->shoppingOrder->total, 2) }} </strong></td>
</tr>
<tr>
<td class="font-weight-semibold">Status:</td>
<td>
<span class="badge badge-{{ $shipment->shoppingOrder->status == 'completed' ? 'success' : 'warning' }}">
{{ $shipment->shoppingOrder->status }}
</span>
</td>
</tr>
<tr>
<td class="font-weight-semibold">Artikel:</td>
<td>{{ $shipment->shoppingOrder->shopping_order_items->count() ?? 0 }} Artikel</td>
</tr>
</table>
</div>
</div>
</div>
</div>
@endif
<!-- Tracking Information -->
@if($shipment->tracking_status || $shipment->tracking_number)
<div class="card mb-4">
<div class="card-header">
<h5 class="mb-0">
<i class="fas fa-route text-info"></i>
Tracking-Informationen
</h5>
</div>
<div class="card-body">
@if($shipment->tracking_status)
<div class="alert alert-info">
<h6 class="alert-heading">
<i class="fas fa-map-marker-alt"></i>
Aktueller Status: {{ $shipment->tracking_status }}
</h6>
@if($shipment->last_tracked_at)
<small class="text-muted">
Zuletzt aktualisiert: {{ $shipment->last_tracked_at->format('d.m.Y H:i') }}
</small>
@endif
</div>
@endif
@if($shipment->tracking_number)
<div class="text-center">
<p>Verfolgen Sie diese Sendung direkt bei DHL:</p>
<a href="https://www.dhl.de/de/privatkunden/pakete-empfangen/verfolgen.html?lang=de&idc={{ $shipment->tracking_number }}"
target="_blank"
class="btn btn-outline-warning">
<i class="fas fa-external-link-alt"></i>
Bei DHL verfolgen
</a>
<a href="{{ route('public.tracking') }}?tracking_number={{ $shipment->tracking_number }}"
target="_blank"
class="btn btn-outline-info ml-2">
<i class="fas fa-search"></i>
Lokales Tracking
</a>
</div>
@endif
</div>
</div>
@endif
</div>
<!-- Right Column -->
<div class="col-lg-4">
<!-- Related Shipments -->
@if($shipment->type == 'outbound' && $shipment->relatedShipments && $shipment->relatedShipments->count() > 0)
<div class="card mb-4">
<div class="card-header">
<h5 class="mb-0">
<i class="fas fa-link text-warning"></i>
Verknüpfte Retouren
</h5>
</div>
<div class="card-body">
@foreach($shipment->relatedShipments as $relatedShipment)
<div class="d-flex justify-content-between align-items-center mb-2">
<div>
<a href="{{ route('admin.dhl.show', $relatedShipment) }}" class="text-primary">
Retoure #{{ $relatedShipment->id }}
</a>
<br>
<small class="text-muted">{{ $relatedShipment->created_at->format('d.m.Y H:i') }}</small>
</div>
<span class="badge badge-{{ $relatedShipment->status == 'created' ? 'success' : 'warning' }}">
{{ $relatedShipment->status }}
</span>
</div>
@endforeach
</div>
</div>
@endif
<!-- Additional Services -->
@if($shipment->services)
<div class="card mb-4">
<div class="card-header">
<h5 class="mb-0">
<i class="fas fa-plus-circle text-success"></i>
Zusatzleistungen
</h5>
</div>
<div class="card-body">
@foreach($shipment->services as $service => $enabled)
@if($enabled)
<div class="badge badge-success mr-1 mb-1">{{ $service }}</div>
@endif
@endforeach
</div>
</div>
@endif
<!-- API Response Data -->
@if($shipment->api_response_data && auth()->user()->isSuperAdmin())
<div class="card">
<div class="card-header">
<h5 class="mb-0">
<i class="fas fa-code text-muted"></i>
API Response (Debug)
</h5>
</div>
<div class="card-body">
<pre class="small text-muted" style="max-height: 300px; overflow-y: auto;">{{ json_encode($shipment->api_response_data, JSON_PRETTY_PRINT) }}</pre>
</div>
</div>
@endif
</div>
</div>
@endsection
@section('scripts')
<script>
$(document).ready(function() {
// Cancel shipment
$('#cancel-shipment-btn').click(function() {
var shipmentId = $(this).data('shipment-id');
if (!confirm('Möchten Sie diese Sendung wirklich stornieren?\n\nDieser Vorgang kann nicht rückgängig gemacht werden.')) {
return;
}
var btn = $(this);
btn.prop('disabled', true).html('<i class="fas fa-spinner fa-spin"></i> Wird storniert...');
$.ajax({
url: `/admin/dhl/shipment/${shipmentId}/cancel`,
method: 'DELETE',
data: {
_token: '{{ csrf_token() }}'
},
success: function(response) {
if (response.success) {
showAlert('success', response.message);
setTimeout(function() {
location.reload();
}, 2000);
} else {
showAlert('error', response.message);
resetButton(btn, '<i class="fas fa-ban"></i> Sendung stornieren');
}
},
error: function(xhr) {
showAlert('error', 'Fehler beim Stornieren der Sendung.');
resetButton(btn, '<i class="fas fa-ban"></i> Sendung stornieren');
}
});
});
// Create return label
$('#create-return-btn').click(function() {
var shipmentId = $(this).data('shipment-id');
if (!confirm('Möchten Sie ein Retourenlabel für diese Sendung erstellen?')) {
return;
}
var btn = $(this);
btn.prop('disabled', true).html('<i class="fas fa-spinner fa-spin"></i> Wird erstellt...');
$.ajax({
url: `/admin/dhl/shipment/${shipmentId}/return-label`,
method: 'POST',
data: {
_token: '{{ csrf_token() }}'
},
success: function(response) {
if (response.success) {
showAlert('success', response.message);
setTimeout(function() {
location.reload();
}, 2000);
} else {
showAlert('error', response.message);
resetButton(btn, '<i class="fas fa-undo"></i> Retourenlabel erstellen');
}
},
error: function(xhr) {
showAlert('error', 'Fehler beim Erstellen des Retourenlabels.');
resetButton(btn, '<i class="fas fa-undo"></i> Retourenlabel erstellen');
}
});
});
// Update tracking
$('#update-tracking-btn').click(function() {
var shipmentId = $(this).data('shipment-id');
var btn = $(this);
btn.prop('disabled', true).html('<i class="fas fa-spinner fa-spin"></i> Wird aktualisiert...');
$.ajax({
url: `/admin/dhl/shipment/${shipmentId}/update-tracking`,
method: 'POST',
data: {
_token: '{{ csrf_token() }}'
},
success: function(response) {
if (response.success) {
showAlert('success', response.message);
setTimeout(function() {
location.reload();
}, 3000);
} else {
showAlert('error', response.message);
resetButton(btn, '<i class="fas fa-sync"></i> Tracking aktualisieren');
}
},
error: function(xhr) {
showAlert('error', 'Fehler beim Aktualisieren der Tracking-Informationen.');
resetButton(btn, '<i class="fas fa-sync"></i> Tracking aktualisieren');
}
});
});
// Helper functions
function resetButton(btn, originalText) {
btn.prop('disabled', false).html(originalText);
}
function showAlert(type, message) {
var alertClass = type === 'success' ? 'alert-success' : 'alert-danger';
var iconClass = type === 'success' ? 'fas fa-check-circle' : 'fas fa-exclamation-circle';
var alertHtml = `
<div class="alert ${alertClass} alert-dismissible fade show" role="alert">
<i class="${iconClass}"></i>
${message}
<button type="button" class="close" data-dismiss="alert">
<span aria-hidden="true">&times;</span>
</button>
</div>
`;
$('.py-2.mb-4').after(alertHtml);
// Scroll to top
$('html, body').animate({ scrollTop: 0 }, 500);
// Auto-hide success alerts after 5 seconds
if (type === 'success') {
setTimeout(function() {
$('.alert-success').alert('close');
}, 5000);
}
}
});
</script>
@endsection