DHL Modul v0.5 Shipping Label ok
This commit is contained in:
parent
480fdc65ed
commit
8fdaa0ba1d
122 changed files with 17938 additions and 2239 deletions
662
app/Http/Controllers/DhlShipmentController.php
Normal file
662
app/Http/Controllers/DhlShipmentController.php
Normal file
|
|
@ -0,0 +1,662 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Jobs\CancelShipmentJob;
|
||||
use App\Jobs\CreateReturnLabelJob;
|
||||
use App\Jobs\TrackShipmentJob;
|
||||
// Old DHL model replaced with new package model
|
||||
use Acme\Dhl\Models\DhlShipment;
|
||||
use App\Models\ShoppingOrder;
|
||||
use App\Services\DhlModalService;
|
||||
use App\Services\DhlShipmentService;
|
||||
use Exception;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\View\View;
|
||||
use Illuminate\Support\Facades\Redirect;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
use Yajra\DataTables\Facades\DataTables;
|
||||
|
||||
// Import new DHL package and SettingController
|
||||
use Acme\Dhl\DhlManager;
|
||||
|
||||
/**
|
||||
* DHL Shipment Controller
|
||||
*
|
||||
* Handles all DHL shipment operations including creation, cancellation,
|
||||
* tracking, and return labels. Provides both web interface and AJAX endpoints.
|
||||
*/
|
||||
class DhlShipmentController extends Controller
|
||||
{
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('auth');
|
||||
$this->middleware('admin')->except(['show', 'track']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the DHL API login credentials and return a JSON response.
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function testLogin()
|
||||
{
|
||||
try {
|
||||
// Get DHL configuration with admin settings
|
||||
$settingController = new \App\Http\Controllers\SettingController();
|
||||
$dhlConfig = $settingController->getDhlConfig();
|
||||
|
||||
// Create DhlClient with merged configuration
|
||||
$dhlClient = new \Acme\Dhl\Support\DhlClient(
|
||||
$dhlConfig['base_url'],
|
||||
$dhlConfig['api_key'],
|
||||
$dhlConfig['username'],
|
||||
$dhlConfig['password']
|
||||
);
|
||||
|
||||
// Test the connection
|
||||
$connectionTest = $dhlClient->testConnection();
|
||||
|
||||
if ($connectionTest) {
|
||||
$result = [
|
||||
'success' => true,
|
||||
'message' => 'DHL API Verbindung erfolgreich getestet!',
|
||||
'details' => [
|
||||
'base_url' => $dhlConfig['base_url'],
|
||||
'using_admin_config' => !empty($dhlConfig['api_key'])
|
||||
]
|
||||
];
|
||||
} else {
|
||||
$result = [
|
||||
'success' => false,
|
||||
'message' => 'DHL API Verbindung fehlgeschlagen. Prüfen Sie Ihre Zugangsdaten.'
|
||||
];
|
||||
}
|
||||
|
||||
return response()->json($result);
|
||||
} catch (Exception $e) {
|
||||
Log::error('[DHL Controller] Test login failed', [
|
||||
'error' => $e->getMessage()
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'DHL API Test fehlgeschlagen: ' . $e->getMessage()
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the DHL Cockpit (main overview)
|
||||
*
|
||||
* @param Request $request
|
||||
* @return View
|
||||
*/
|
||||
public function index(Request $request): View
|
||||
{
|
||||
// Statistics for dashboard widgets
|
||||
$stats = [
|
||||
'total_shipments' => DhlShipment::count(),
|
||||
'pending_shipments' => DhlShipment::where('status', 'pending')->count(),
|
||||
'shipped_today' => DhlShipment::whereDate('created_at', today())->count(),
|
||||
'returns_count' => DhlShipment::where('type', 'return')->count(),
|
||||
];
|
||||
|
||||
return view('admin.dhl.cockpit', compact('stats'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides data for the DHL Cockpit DataTable.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function datatable(Request $request): JsonResponse
|
||||
{
|
||||
$query = DhlShipment::with(['shoppingOrder.shopping_user'])
|
||||
->select('dhl_package_shipments.*') // Explicitly select to avoid conflicts
|
||||
->orderBy('created_at', 'desc');
|
||||
|
||||
// Apply filters from the request
|
||||
if ($request->filled('type')) {
|
||||
$query->where('type', $request->get('type'));
|
||||
}
|
||||
if ($request->filled('status')) {
|
||||
$query->where('status', $request->get('status'));
|
||||
}
|
||||
if ($request->filled('date_from')) {
|
||||
$query->whereDate('created_at', '>=', $request->get('date_from'));
|
||||
}
|
||||
if ($request->filled('date_to')) {
|
||||
$query->whereDate('created_at', '<=', $request->get('date_to'));
|
||||
}
|
||||
if ($request->filled('search')) {
|
||||
$search = $request->get('search');
|
||||
$query->where(function ($q) use ($search) {
|
||||
$q->where('dhl_shipment_no', 'LIKE', "%{$search}%")
|
||||
->orWhere('id', 'LIKE', "%{$search}%")
|
||||
->orWhereHas('shoppingOrder', function ($orderQuery) use ($search) {
|
||||
$orderQuery->where('id', $search);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return DataTables::eloquent($query)
|
||||
->addColumn('checkbox', function ($shipment) {
|
||||
return '<label class="custom-control custom-checkbox mb-0"><input type="checkbox" class="custom-control-input shipment-checkbox" value="' . $shipment->id . '"><span class="custom-control-label"></span></label>';
|
||||
})
|
||||
->editColumn('id', function ($shipment) {
|
||||
return '<a href="' . route('admin.dhl.show', $shipment) . '" class="text-primary font-weight-semibold">#' . $shipment->id . '</a>';
|
||||
})
|
||||
->addColumn('type', function ($shipment) {
|
||||
if ($shipment->type == 'outbound') {
|
||||
return '<span class="badge badge-primary"><i class="fas fa-arrow-right"></i> Ausgehend</span>';
|
||||
} else {
|
||||
return '<span class="badge badge-info"><i class="fas fa-undo"></i> Retoure</span>';
|
||||
}
|
||||
})
|
||||
->addColumn('order', function ($shipment) {
|
||||
if ($shipment->order_id) {
|
||||
return '<a href="' . route('admin_sales_customers_detail', $shipment->order_id) . '" class="text-primary">#' . $shipment->order_id . '</a>';
|
||||
}
|
||||
return '<span class="text-muted">N/A</span>';
|
||||
})
|
||||
->addColumn('customer', function ($shipment) {
|
||||
if ($shipment->shoppingOrder && $shipment->shoppingOrder->shopping_user) {
|
||||
return e($shipment->shoppingOrder->shopping_user->billing_firstname) . ' ' . e($shipment->shoppingOrder->shopping_user->billing_lastname) .
|
||||
'<br><small class="text-muted">' . e($shipment->shoppingOrder->shopping_user->billing_email) . '</small>';
|
||||
}
|
||||
return '<span class="text-muted">Unbekannt</span>';
|
||||
})
|
||||
->editColumn('dhl_shipment_no', function ($shipment) {
|
||||
return $shipment->dhl_shipment_no ? '<code class="text-success">' . e($shipment->dhl_shipment_no) . '</code>' : '<span class="text-muted">-</span>';
|
||||
})
|
||||
->addColumn('status', function ($shipment) {
|
||||
$statusMap = [
|
||||
'pending' => ['class' => 'warning', 'text' => 'Wartend'],
|
||||
'created' => ['class' => 'success', 'text' => 'Erstellt'],
|
||||
'shipped' => ['class' => 'primary', 'text' => 'Versendet'],
|
||||
'delivered' => ['class' => 'info', 'text' => 'Zugestellt'],
|
||||
'cancelled' => ['class' => 'secondary', 'text' => 'Storniert'],
|
||||
'failed' => ['class' => 'danger', 'text' => 'Fehler'],
|
||||
];
|
||||
$statusInfo = $statusMap[$shipment->status] ?? ['class' => 'light', 'text' => e($shipment->status)];
|
||||
return '<span class="badge badge-' . $statusInfo['class'] . '">' . $statusInfo['text'] . '</span>';
|
||||
})
|
||||
->addColumn('tracking_status', function ($shipment) {
|
||||
if ($shipment->tracking_status) {
|
||||
return '<small class="text-muted">' . e($shipment->tracking_status) . '</small>' .
|
||||
($shipment->last_tracked_at ? '<br><small class="text-muted">' . $shipment->last_tracked_at->format('d.m.Y H:i') . '</small>' : '');
|
||||
}
|
||||
return '<span class="text-muted">-</span>';
|
||||
})
|
||||
->editColumn('weight_kg', function ($shipment) {
|
||||
return number_format($shipment->weight_kg, 2) . ' kg';
|
||||
})
|
||||
->editColumn('created_at', function ($shipment) {
|
||||
return $shipment->created_at->format('d.m.Y H:i');
|
||||
})
|
||||
->addColumn('actions', function ($shipment) {
|
||||
$buttons = '<div class="btn-group" role="group">';
|
||||
$buttons .= '<a href="' . route('admin.dhl.show', $shipment) . '" class="btn btn-sm btn-outline-primary" data-toggle="tooltip" title="Details anzeigen"><i class="fas fa-eye"></i></a>';
|
||||
if ($shipment->label_path) {
|
||||
$buttons .= '<a href="' . route('admin.dhl.download-label', $shipment) . '" class="btn btn-sm btn-outline-success" data-toggle="tooltip" title="Label herunterladen"><i class="fas fa-download"></i></a>';
|
||||
}
|
||||
if ($shipment->canCancel()) {
|
||||
$buttons .= '<button type="button" class="btn btn-sm btn-outline-warning cancel-shipment-btn" data-shipment-id="' . $shipment->id . '" data-toggle="tooltip" title="Sendung stornieren"><i class="fas fa-ban"></i></button>';
|
||||
}
|
||||
if ($shipment->type == 'outbound' && !$shipment->returns()->count()) {
|
||||
$buttons .= '<button type="button" class="btn btn-sm btn-outline-info create-return-btn" data-shipment-id="' . $shipment->id . '" data-toggle="tooltip" title="Retourenlabel erstellen"><i class="fas fa-undo"></i></button>';
|
||||
}
|
||||
$buttons .= '</div>';
|
||||
return $buttons;
|
||||
})
|
||||
->rawColumns(['checkbox', 'id', 'type', 'order', 'customer', 'dhl_shipment_no', 'status', 'tracking_status', 'actions'])
|
||||
->make(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new shipment
|
||||
*
|
||||
* @param ShoppingOrder $order
|
||||
* @return View
|
||||
*/
|
||||
public function create(ShoppingOrder $order): View|\Illuminate\Http\RedirectResponse
|
||||
{
|
||||
// Check if order already has a shipment
|
||||
$existingShipment = DhlShipment::where('shopping_order_id', $order->id)
|
||||
->where('type', 'outbound')
|
||||
->first();
|
||||
|
||||
if ($existingShipment) {
|
||||
return redirect()->route('admin.dhl.show', $existingShipment)
|
||||
->with('warning', 'Für diese Bestellung existiert bereits eine Sendung.');
|
||||
}
|
||||
|
||||
return view('admin.dhl.create', compact('order'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a new shipment (async via queue)
|
||||
*
|
||||
* @param Request $request
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function store(Request $request): JsonResponse
|
||||
{
|
||||
try {
|
||||
// Use DhlModalService for validation
|
||||
$dhlModalService = new DhlModalService();
|
||||
$validationResult = $dhlModalService->validateShipmentData($request->all());
|
||||
|
||||
if (!$validationResult['valid']) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Validierungsfehler: ' . implode(', ', $validationResult['errors'])
|
||||
], 422);
|
||||
}
|
||||
|
||||
// Basic Laravel validation as fallback
|
||||
$request->validate([
|
||||
'order_id' => 'required|exists:shopping_orders,id',
|
||||
'weight' => 'required|numeric|min:0.1|max:31.5',
|
||||
'product_code' => 'sometimes|string',
|
||||
'priority' => 'sometimes|string|in:normal,high',
|
||||
'auto_track' => 'sometimes|boolean',
|
||||
// Shipping address validation
|
||||
'shipping_firstname' => 'required|string|max:50',
|
||||
'shipping_lastname' => 'required|string|max:50',
|
||||
'shipping_company' => 'nullable|string|max:100',
|
||||
'shipping_address' => 'required|string|max:100',
|
||||
'shipping_houseNumber' => 'required|string|max:50',
|
||||
'shipping_zipcode' => 'required|string|max:10',
|
||||
'shipping_city' => 'required|string|max:50',
|
||||
'shipping_country_id' => 'required|exists:countries,id',
|
||||
'shipping_phone' => 'nullable|string|max:20',
|
||||
]);
|
||||
|
||||
$order = ShoppingOrder::findOrFail($request->order_id);
|
||||
|
||||
// Check if shipment already exists
|
||||
/* $existingShipment = DhlShipment::where('shopping_order_id', $order->id)
|
||||
->where('type', 'outbound')
|
||||
->first();
|
||||
|
||||
if ($existingShipment) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Für diese Bestellung existiert bereits eine Sendung.'
|
||||
], 422);
|
||||
}
|
||||
*/
|
||||
|
||||
// Use service to prepare address data
|
||||
$shippingAddress = $dhlModalService->prepareAddressForApi($request->all());
|
||||
|
||||
// Prepare options for shipment creation
|
||||
$options = [
|
||||
'product_code' => $request->get('product_code', 'V01PAK'),
|
||||
'priority' => $request->get('priority', 'normal'),
|
||||
'auto_track' => $request->get('auto_track', true),
|
||||
'shipping_address' => $shippingAddress,
|
||||
'services' => $request->get('services', []),
|
||||
'dimensions' => $request->only(['length', 'width', 'height'])
|
||||
];
|
||||
|
||||
// Use DhlShipmentService (handles queue/sync automatically based on config)
|
||||
$dhlShipmentService = new DhlShipmentService();
|
||||
$result = $dhlShipmentService->createShipment($order, (float) $request->weight, $options);
|
||||
|
||||
Log::info('[DHL Controller] Shipment creation processed', [
|
||||
'order_id' => $order->id,
|
||||
'weight' => $request->weight,
|
||||
'queued' => $result['queued'] ?? false,
|
||||
'success' => $result['success'] ?? false,
|
||||
]);
|
||||
|
||||
return response()->json($result);
|
||||
} catch (Exception $e) {
|
||||
Log::error('[DHL Controller] Failed to dispatch shipment creation', [
|
||||
'error' => $e->getMessage(),
|
||||
'order_id' => $request->order_id ?? 'unknown',
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Fehler beim Erstellen der Sendung: ' . $e->getMessage()
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified shipment
|
||||
*
|
||||
* @param DhlShipment $shipment
|
||||
* @return View
|
||||
*/
|
||||
public function show(DhlShipment $shipment): View
|
||||
{
|
||||
$shipment->load(['shoppingOrder.shopping_user', 'relatedShipment']);
|
||||
|
||||
return view('admin.dhl.show', compact('shipment'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel the specified shipment
|
||||
*
|
||||
* @param Request $request
|
||||
* @param DhlShipment $shipment
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function cancel(Request $request, DhlShipment $shipment): JsonResponse
|
||||
{
|
||||
try {
|
||||
// Validate cancellation is possible
|
||||
if (!$shipment->canCancel()) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Diese Sendung kann nicht mehr storniert werden.'
|
||||
], 422);
|
||||
}
|
||||
|
||||
// Dispatch cancellation job
|
||||
$options = [
|
||||
'priority' => $request->get('priority', 'normal')
|
||||
];
|
||||
|
||||
CancelShipmentJob::dispatch($shipment, $options);
|
||||
|
||||
Log::info('[DHL Controller] Shipment cancellation job dispatched', [
|
||||
'shipment_id' => $shipment->id,
|
||||
'shipment_number' => $shipment->shipment_number,
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => 'Sendung wird storniert...'
|
||||
]);
|
||||
} catch (Exception $e) {
|
||||
Log::error('[DHL Controller] Failed to dispatch shipment cancellation', [
|
||||
'error' => $e->getMessage(),
|
||||
'shipment_id' => $shipment->id,
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Fehler beim Stornieren der Sendung: ' . $e->getMessage()
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create return label for the specified shipment
|
||||
*
|
||||
* @param Request $request
|
||||
* @param DhlShipment $shipment
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function createReturnLabel(Request $request, DhlShipment $shipment): JsonResponse
|
||||
{
|
||||
try {
|
||||
// Validate return label creation is possible
|
||||
if ($shipment->type !== 'outbound') {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Retourenlabels können nur für ausgehende Sendungen erstellt werden.'
|
||||
], 422);
|
||||
}
|
||||
|
||||
// Check if return label already exists
|
||||
$existingReturn = DhlShipment::where('related_shipment_id', $shipment->id)
|
||||
->where('type', 'return')
|
||||
->first();
|
||||
|
||||
if ($existingReturn) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Für diese Sendung existiert bereits ein Retourenlabel.'
|
||||
], 422);
|
||||
}
|
||||
|
||||
// Dispatch return label creation job
|
||||
$options = [
|
||||
'auto_track' => $request->get('auto_track', false),
|
||||
'priority' => $request->get('priority', 'normal')
|
||||
];
|
||||
|
||||
CreateReturnLabelJob::dispatch($shipment, $options);
|
||||
|
||||
Log::info('[DHL Controller] Return label creation job dispatched', [
|
||||
'original_shipment_id' => $shipment->id,
|
||||
'shipment_number' => $shipment->shipment_number,
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => 'Retourenlabel wird erstellt...'
|
||||
]);
|
||||
} catch (Exception $e) {
|
||||
Log::error('[DHL Controller] Failed to dispatch return label creation', [
|
||||
'error' => $e->getMessage(),
|
||||
'shipment_id' => $shipment->id,
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Fehler beim Erstellen des Retourenlabels: ' . $e->getMessage()
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update tracking status for the specified shipment
|
||||
*
|
||||
* @param DhlShipment $shipment
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function updateTracking(DhlShipment $shipment): JsonResponse
|
||||
{
|
||||
try {
|
||||
if (!$shipment->tracking_number) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Keine Tracking-Nummer verfügbar.'
|
||||
], 422);
|
||||
}
|
||||
|
||||
// Dispatch tracking update job
|
||||
TrackShipmentJob::dispatch($shipment, ['auto_retrack' => false]);
|
||||
|
||||
Log::info('[DHL Controller] Tracking update job dispatched', [
|
||||
'shipment_id' => $shipment->id,
|
||||
'tracking_number' => $shipment->tracking_number,
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => 'Tracking-Informationen werden aktualisiert...'
|
||||
]);
|
||||
} catch (Exception $e) {
|
||||
Log::error('[DHL Controller] Failed to dispatch tracking update', [
|
||||
'error' => $e->getMessage(),
|
||||
'shipment_id' => $shipment->id,
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Fehler beim Aktualisieren der Tracking-Informationen: ' . $e->getMessage()
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Download shipping label
|
||||
*
|
||||
* @param DhlShipment $shipment
|
||||
* @return Response
|
||||
*/
|
||||
public function downloadLabel(DhlShipment $shipment): Response
|
||||
{
|
||||
try {
|
||||
if (!$shipment->label_path || !Storage::exists($shipment->label_path)) {
|
||||
abort(404, 'Versandlabel nicht gefunden.');
|
||||
}
|
||||
|
||||
$labelContent = Storage::get($shipment->label_path);
|
||||
$filename = sprintf(
|
||||
'dhl-label-%s-%s.pdf',
|
||||
$shipment->type,
|
||||
$shipment->shipment_number ?: $shipment->id
|
||||
);
|
||||
|
||||
return response($labelContent, 200)
|
||||
->header('Content-Type', 'application/pdf')
|
||||
->header('Content-Disposition', "attachment; filename=\"{$filename}\"");
|
||||
} catch (Exception $e) {
|
||||
Log::error('[DHL Controller] Failed to download label', [
|
||||
'error' => $e->getMessage(),
|
||||
'shipment_id' => $shipment->id,
|
||||
'label_path' => $shipment->label_path,
|
||||
]);
|
||||
|
||||
abort(500, 'Fehler beim Download des Versandlabels.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Batch operations (multiple shipments)
|
||||
*
|
||||
* @param Request $request
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function batchAction(Request $request): JsonResponse
|
||||
{
|
||||
try {
|
||||
$request->validate([
|
||||
'action' => 'required|in:cancel,download_labels,update_tracking',
|
||||
'shipment_ids' => 'required|array|min:1',
|
||||
'shipment_ids.*' => 'exists:dhl_package_shipments,id',
|
||||
]);
|
||||
|
||||
$shipmentIds = $request->shipment_ids;
|
||||
$action = $request->action;
|
||||
$processed = 0;
|
||||
$errors = [];
|
||||
|
||||
foreach ($shipmentIds as $shipmentId) {
|
||||
try {
|
||||
$shipment = DhlShipment::findOrFail($shipmentId);
|
||||
|
||||
switch ($action) {
|
||||
case 'cancel':
|
||||
if ($shipment->canCancel()) {
|
||||
CancelShipmentJob::dispatch($shipment);
|
||||
$processed++;
|
||||
} else {
|
||||
$errors[] = "Sendung {$shipment->shipment_number} kann nicht storniert werden.";
|
||||
}
|
||||
break;
|
||||
|
||||
case 'update_tracking':
|
||||
if ($shipment->tracking_number) {
|
||||
TrackShipmentJob::dispatch($shipment, ['auto_retrack' => false]);
|
||||
$processed++;
|
||||
} else {
|
||||
$errors[] = "Sendung {$shipment->shipment_number} hat keine Tracking-Nummer.";
|
||||
}
|
||||
break;
|
||||
|
||||
case 'download_labels':
|
||||
// This would require ZIP creation - implement if needed
|
||||
$errors[] = "Stapel-Download noch nicht implementiert.";
|
||||
break;
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$errors[] = "Fehler bei Sendung {$shipmentId}: " . $e->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
Log::info('[DHL Controller] Batch action executed', [
|
||||
'action' => $action,
|
||||
'processed' => $processed,
|
||||
'errors_count' => count($errors),
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'success' => $processed > 0,
|
||||
'message' => sprintf('%d Sendungen verarbeitet.', $processed),
|
||||
'processed' => $processed,
|
||||
'errors' => $errors,
|
||||
]);
|
||||
} catch (Exception $e) {
|
||||
Log::error('[DHL Controller] Batch action failed', [
|
||||
'error' => $e->getMessage(),
|
||||
'action' => $request->action ?? 'unknown',
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Fehler bei der Stapelverarbeitung: ' . $e->getMessage()
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Public tracking page (for customers)
|
||||
*
|
||||
* @param Request $request
|
||||
* @return View|JsonResponse
|
||||
*/
|
||||
public function track(Request $request): View|JsonResponse
|
||||
{
|
||||
if ($request->expectsJson()) {
|
||||
$request->validate([
|
||||
'tracking_number' => 'required|string|min:10',
|
||||
]);
|
||||
|
||||
try {
|
||||
$shipment = DhlShipment::where('tracking_number', $request->tracking_number)->first();
|
||||
|
||||
if (!$shipment) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Sendung nicht gefunden.'
|
||||
], 404);
|
||||
}
|
||||
|
||||
// Dispatch tracking update
|
||||
TrackShipmentJob::dispatch($shipment, ['auto_retrack' => false]);
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'data' => [
|
||||
'tracking_number' => $shipment->tracking_number,
|
||||
'status' => $shipment->status,
|
||||
'tracking_status' => $shipment->tracking_status,
|
||||
'last_tracked_at' => $shipment->last_tracked_at?->format('d.m.Y H:i'),
|
||||
]
|
||||
]);
|
||||
} catch (Exception $e) {
|
||||
Log::error('[DHL Controller] Public tracking failed', [
|
||||
'error' => $e->getMessage(),
|
||||
'tracking_number' => $request->tracking_number ?? 'unknown',
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Fehler beim Abrufen der Tracking-Informationen.'
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
|
||||
return view('public.tracking');
|
||||
}
|
||||
}
|
||||
|
|
@ -130,24 +130,23 @@ class FileController extends Controller
|
|||
if(!Storage::disk($disk)->exists($path)){
|
||||
return Response::make('Datei nicht gefunden.', 404);
|
||||
}
|
||||
|
||||
if ($do === 'download') {
|
||||
return Storage::disk($disk)->download($path, $filename);
|
||||
}
|
||||
|
||||
$file = Storage::disk($disk)->get($path);
|
||||
$mime = Storage::disk($disk)->mimeType($path);
|
||||
|
||||
if(isset($file)){
|
||||
if($do === 'download'){
|
||||
return Response::make($file, 200)
|
||||
->header("Content-Type", $mime)
|
||||
->header('Content-disposition', 'attachment; filename="'.$filename.'"');
|
||||
}
|
||||
if($do === 'stream'){
|
||||
return Response::make($file, 200)
|
||||
->header("Content-Type", $mime)
|
||||
->header('Content-disposition','inline; filename="'.$filename.'"');
|
||||
return Storage::disk($disk)->response($path, $filename);
|
||||
}
|
||||
|
||||
if($do === 'file'){
|
||||
return Response::make($file, 200)
|
||||
->header("Content-Type", $mime)
|
||||
->header("Content-Length", strlen($file))
|
||||
->header('Content-disposition', 'filename="'.$filename.'"');
|
||||
}
|
||||
if($do === 'image'){
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ use App\Models\ShoppingOrder;
|
|||
use App\Models\UserSalesVolume;
|
||||
use App\Services\BusinessPlan\TreeCalcBot;
|
||||
use App\Services\BusinessPlan\TreeCalcBotOptimized;
|
||||
use App\Services\DhlModalService;
|
||||
|
||||
class ModalController extends Controller
|
||||
{
|
||||
|
|
@ -170,6 +171,11 @@ class ModalController extends Controller
|
|||
$user_abo = UserAbo::find($data['id']);
|
||||
$ret = view("user.abo.modal_abo_show_products", compact( 'data', 'user_abo'))->render();
|
||||
}
|
||||
|
||||
if($data['action'] === 'create-dhl-shipment') {
|
||||
$id = $data['id'] ?? null;
|
||||
$ret = $this->handleDhlShipmentModal($id, $data);
|
||||
}
|
||||
|
||||
}
|
||||
return response()->json(['response' => $data, 'html'=>$ret, 'status'=>$status]);
|
||||
|
|
@ -195,6 +201,55 @@ class ModalController extends Controller
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle DHL shipment modal preparation
|
||||
*
|
||||
* @param mixed $id Order ID or 'new'
|
||||
* @param array $data Request data
|
||||
* @return string Rendered view
|
||||
*/
|
||||
private function handleDhlShipmentModal($id, array $data): string
|
||||
{
|
||||
try {
|
||||
$dhlModalService = new DhlModalService();
|
||||
$modalData = $dhlModalService->prepareModalData($id, $data);
|
||||
|
||||
// Merge the prepared data with the original request data
|
||||
$viewData = array_merge($data, $modalData, [
|
||||
'id' => $id,
|
||||
'data' => $data
|
||||
]);
|
||||
|
||||
return view("admin.dhl.modal_create_shipment", $viewData)->render();
|
||||
|
||||
} catch (\Exception $e) {
|
||||
\Log::error('[ModalController] Error in DHL shipment modal', [
|
||||
'order_id' => $id,
|
||||
'error' => $e->getMessage(),
|
||||
'trace' => $e->getTraceAsString()
|
||||
]);
|
||||
|
||||
// Return error view or fallback
|
||||
$errorData = [
|
||||
'id' => $id,
|
||||
'data' => $data,
|
||||
'order' => null,
|
||||
'orderWeight' => 1.0,
|
||||
'shippingAddress' => null,
|
||||
'availableCountries' => \App\Models\Country::where('active', 1)->get(),
|
||||
'productCodes' => [
|
||||
'V01PAK' => 'DHL Paket (National)',
|
||||
'V53WPAK' => 'DHL Paket International',
|
||||
'V54EPAK' => 'DHL Express'
|
||||
],
|
||||
'errors' => ['Fehler beim Laden der Daten: ' . $e->getMessage()],
|
||||
'warnings' => []
|
||||
];
|
||||
|
||||
return view("admin.dhl.modal_create_shipment", $errorData)->render();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -65,16 +65,16 @@ class InController extends Controller
|
|||
|
||||
$data = Request::all();
|
||||
|
||||
|
||||
$response = "";
|
||||
$status = false;
|
||||
|
||||
if(isset($data['action']) && $data['action'] === 'user-order-show-product'){
|
||||
$product = Product::find($data['id']); //current user form order
|
||||
$ret = view("admin.modal.show_product", compact('product', 'data'))->render();
|
||||
return response()->json(['response' => $data, 'html'=>$ret, 'status'=>$status]);
|
||||
|
||||
if(isset($data['action'])){
|
||||
if($data['action'] === 'user-order-show-product'){
|
||||
$product = Product::find($data['id']); //current user form order
|
||||
$ret = view("admin.modal.show_product", compact('product', 'data'))->render();
|
||||
return response()->json(['response' => $data, 'html'=>$ret, 'status'=>$status]);
|
||||
}
|
||||
}
|
||||
|
||||
$data = Request::get('data');
|
||||
$target = Request::get('target');
|
||||
if($data === "data_protection"){
|
||||
|
|
|
|||
|
|
@ -27,19 +27,92 @@ class SettingController extends Controller
|
|||
|
||||
public function store()
|
||||
{
|
||||
|
||||
$data = Request::all();
|
||||
if(isset($data['action'])){
|
||||
if(isset($data['settings'])){
|
||||
foreach ($data['settings'] as $key=>$value){
|
||||
if (isset($data['action'])) {
|
||||
if (isset($data['settings'])) {
|
||||
foreach ($data['settings'] as $key => $value) {
|
||||
$value['val'] = isset($value['val']) ? $value['val'] : false;
|
||||
Setting::setContentBySlug($key, $value['val'], $value['type']);
|
||||
}
|
||||
}
|
||||
|
||||
// DHL-spezifische Behandlung
|
||||
if ($data['action'] === 'save_dhl') {
|
||||
$this->updateDhlConfigCache();
|
||||
\Session()->flash('alert-save-dhl', 'DHL Konfiguration erfolgreich gespeichert!');
|
||||
} else {
|
||||
\Session()->flash('alert-save', '1');
|
||||
}
|
||||
}
|
||||
\Session()->flash('alert-save', '1');
|
||||
|
||||
return redirect(route('admin_settings'));
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get DHL configuration merged from database settings and .env values
|
||||
* Database settings override .env values
|
||||
*/
|
||||
public function getDhlConfig()
|
||||
{
|
||||
return [
|
||||
// API Settings
|
||||
'base_url' => Setting::getContentBySlug('dhl_base_url') ?: config('dhl.base_url'),
|
||||
'api_key' => Setting::getContentBySlug('dhl_api_key') ?: config('dhl.api_key'),
|
||||
'username' => Setting::getContentBySlug('dhl_username') ?: config('dhl.username'),
|
||||
'password' => Setting::getContentBySlug('dhl_password') ?: config('dhl.password'),
|
||||
'billing_number' => Setting::getContentBySlug('dhl_billing_number') ?: config('dhl.billing_number'),
|
||||
|
||||
// Product Settings
|
||||
'default_product' => Setting::getContentBySlug('dhl_product') ?: config('dhl.default_product'),
|
||||
'label_format' => Setting::getContentBySlug('dhl_label_format') ?: config('dhl.label_format'),
|
||||
'print_format' => Setting::getContentBySlug('dhl_print_format') ?: config('dhl.print_format'),
|
||||
'retoure_print_format' => Setting::getContentBySlug('dhl_retoure_print_format') ?: config('dhl.retoure_print_format'),
|
||||
'use_queue' => Setting::getContentBySlug('dhl_use_queue') ?: config('dhl.use_queue'),
|
||||
|
||||
// Sender Address
|
||||
'sender' => [
|
||||
'company' => Setting::getContentBySlug('dhl_sender_company') ?: config('dhl.sender.company'),
|
||||
'name' => Setting::getContentBySlug('dhl_sender_name') ?: config('dhl.sender.name'),
|
||||
'street' => Setting::getContentBySlug('dhl_sender_street') ?: config('dhl.sender.street'),
|
||||
'houseNumber' => Setting::getContentBySlug('dhl_sender_house_number') ?: config('dhl.sender.houseNumber'),
|
||||
'postalCode' => Setting::getContentBySlug('dhl_sender_postal_code') ?: config('dhl.sender.postalCode'),
|
||||
'city' => Setting::getContentBySlug('dhl_sender_city') ?: config('dhl.sender.city'),
|
||||
'country' => Setting::getContentBySlug('dhl_sender_country') ?: config('dhl.sender.country'),
|
||||
'email' => Setting::getContentBySlug('dhl_sender_email') ?: config('dhl.sender.email'),
|
||||
'phone' => Setting::getContentBySlug('dhl_sender_phone') ?: config('dhl.sender.phone'),
|
||||
],
|
||||
|
||||
// Account Numbers
|
||||
'account_numbers' => [
|
||||
'V01PAK' => Setting::getContentBySlug('dhl_account_v01pak') ?: config('dhl.account_numbers.V01PAK'),
|
||||
'V62WP' => Setting::getContentBySlug('dhl_account_v62wp') ?: config('dhl.account_numbers.V62WP'),
|
||||
'V53PAK' => Setting::getContentBySlug('dhl_account_v53pak') ?: config('dhl.account_numbers.V53PAK'),
|
||||
'V07PAK' => Setting::getContentBySlug('dhl_account_v07pak') ?: config('dhl.account_numbers.V07PAK'),
|
||||
'default' => config('dhl.account_numbers.default'),
|
||||
],
|
||||
|
||||
// Static config values (webhook, profile, legacy)
|
||||
'profile' => config('dhl.profile'),
|
||||
'webhook' => config('dhl.webhook'),
|
||||
'legacy' => config('dhl.legacy'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Update DHL configuration cache after saving settings
|
||||
*/
|
||||
private function updateDhlConfigCache()
|
||||
{
|
||||
// Clear config cache to force reload from database
|
||||
\Artisan::call('config:clear');
|
||||
|
||||
// Optional: Test DHL connection with new settings
|
||||
try {
|
||||
$dhlManager = app('Acme\Dhl\DhlManager');
|
||||
// You could add a connection test here if needed
|
||||
\Log::info('DHL configuration updated successfully');
|
||||
} catch (\Exception $e) {
|
||||
\Log::error('DHL configuration update failed: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -322,6 +322,9 @@ class UserShopController extends Controller
|
|||
return redirect()->back()->withErrors($validator)->withInput(Request::all());
|
||||
}
|
||||
\Session()->flash('shop-name-error', 'check');
|
||||
if(Request::get('user_shop_id')){
|
||||
return back()->withInput(Request::all());
|
||||
}
|
||||
return redirect(route('user_shop'))->withInput(Request::all());
|
||||
}
|
||||
|
||||
|
|
@ -329,6 +332,8 @@ class UserShopController extends Controller
|
|||
|
||||
$rules = array(
|
||||
'user_shop_name' => ' required|alpha_dash|unique:user_shops,name|min:4|max:20|full_word_check',
|
||||
'user_shop_active' => 'accepted',
|
||||
|
||||
);
|
||||
Validator::extend('full_word_check', function ($attribute, $value, $parameters, $validator) {
|
||||
if(in_array($value, config('profanity.full_word_check'))){
|
||||
|
|
@ -337,41 +342,43 @@ class UserShopController extends Controller
|
|||
return true;
|
||||
});
|
||||
$validator = Validator::make(Request::all(), $rules);
|
||||
|
||||
if ($validator->fails()) {
|
||||
\Session()->flash('shop-name-error', 'error');
|
||||
}else{
|
||||
\Session()->flash('shop-name-error', 'check');
|
||||
|
||||
}
|
||||
|
||||
$rules = array(
|
||||
'user_shop_active' => 'accepted',
|
||||
);
|
||||
$validator = Validator::make(Request::all(), $rules);
|
||||
if ($validator->fails()) {
|
||||
\Session()->flash('shop-name-error', 'error');
|
||||
return redirect()->back()->withErrors($validator)->withInput(Request::all());
|
||||
}
|
||||
\Session()->flash('shop-name-error', 'check');
|
||||
|
||||
//all is right - save
|
||||
$user = Auth::user();
|
||||
$data = Request::all();
|
||||
$slug = SlugService::createSlug(UserShop::class, 'slug', $data['user_shop_name']);
|
||||
$user_shop = UserShop::create([
|
||||
'user_id' => $user->id,
|
||||
'name' => $slug,
|
||||
'active' => true,
|
||||
'active_date' => now(),
|
||||
]
|
||||
);
|
||||
|
||||
$ret = $this->userShopRegisterSubDomain($user_shop->slug);
|
||||
if(isset($data['user_shop_id'])){
|
||||
$user_shop = UserShop::find($data['user_shop_id']);
|
||||
if($user_shop->user_id != $user->id){
|
||||
abort(404);
|
||||
}
|
||||
$user_shop->name = $slug;
|
||||
$user_shop->slug = $slug;
|
||||
$user_shop->save();
|
||||
}else{
|
||||
$user_shop = UserShop::create([
|
||||
'user_id' => $user->id,
|
||||
'name' => $slug,
|
||||
'active' => true,
|
||||
'active_date' => now(),
|
||||
]
|
||||
);
|
||||
}
|
||||
\Session()->flash('alert-save', true);
|
||||
return redirect(route('user_shop'));
|
||||
/*$ret = $this->userShopRegisterSubDomain($user_shop->slug);
|
||||
if($ret['success'] === true){
|
||||
\Session()->flash('alert-save', true);
|
||||
}else{
|
||||
$user_shop->forceDelete();
|
||||
\Session()->flash('alert-error', $ret['error']);
|
||||
}
|
||||
return redirect(route('user_shop'));
|
||||
return redirect(route('user_shop'));*/
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -444,4 +451,19 @@ class UserShopController extends Controller
|
|||
));
|
||||
}
|
||||
|
||||
public function editName(){
|
||||
$user = Auth::user();
|
||||
$user_shop = $user->shop;
|
||||
if(!$user_shop){
|
||||
abort(404);
|
||||
}
|
||||
$user_shop_domain = $user_shop->getSubdomain(false);
|
||||
$data = [
|
||||
'user' => $user,
|
||||
'user_shop_id' => $user_shop->id,
|
||||
'user_shop_domain' => $user_shop_domain,
|
||||
];
|
||||
return view('user.shop_edit_name', $data);
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue