validate([ 'direction' => ['required', 'string', 'in:Outbound,Inbound,export,import'], 'type' => ['required', 'string', 'in:DOC_NORMAL,DOC_ECONOMY,PARCEL,DOCUMENT,NON DOC'], 'country_iso' => ['required', 'string', 'size:2'], 'weight' => ['required', 'numeric', 'min:0'], 'volumetric_weight' => ['required', 'numeric', 'min:0'], 'extra_service' => ['nullable', 'numeric', 'min:0'], 'packing_cost' => ['nullable', 'numeric', 'min:0'], 'domestic_pickup' => ['nullable', 'numeric', 'min:0'], 'domestic_delivery' => ['nullable', 'numeric', 'min:0'], 'warehousing_cost' => ['nullable', 'numeric', 'min:0'], 'discount_code' => ['nullable', 'string', 'max:50'], ]); } catch (ValidationException $e) { return response()->json([ 'success' => false, 'message' => 'Validation failed', 'errors' => $e->errors(), ], 422); } try { $result = $this->calculator->calculate($validated); return response()->json($result); } catch (\InvalidArgumentException $e) { return response()->json([ 'success' => false, 'message' => $e->getMessage(), ], 422); } catch (\RuntimeException $e) { // خطاهای «زون یافت نشد» یا «نرخ یافت نشد» — خطای کسب‌وکار، نه سرور return response()->json([ 'success' => false, 'message' => $e->getMessage(), ], 400); } catch (\Throwable $e) { report($e); return response()->json([ 'success' => false, 'message' => 'خطای داخلی سرور هنگام محاسبه قیمت.', ], 500); } } }