Introduces a complete shipment review system allowing staff to request changes to customer orders and customers to resubmit corrected orders. - Add `ReviewState` enum and `ShipmentReview` model to track review history. - Implement `ShipmentReviewService` to handle approval and change request logic. - Add `resubmit` endpoint for customers to update orders when `changes_requested` state is active. - Add `request-changes` endpoint for staff to flag orders for correction. - Update `ShipmentResource` in Filament to display review states and manage approvals. - Implement WordPress bridge support for fetching and resubmitting orders via AJAX. - Add database migrations for `shipment_reviews` table and `review_state` column on shipments. - Add `StaffApiMiddleware` to secure staff-specific API routes.
238 lines
7.4 KiB
PHP
238 lines
7.4 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Api;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Models\Shipment;
|
|
use App\Models\ShipmentReview;
|
|
use App\Services\ShipmentReviewService;
|
|
use Illuminate\Http\JsonResponse;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\Auth;
|
|
|
|
class StaffOrderController extends Controller
|
|
{
|
|
/**
|
|
* لیست سفارشات در انتظار تأیید
|
|
* GET /api/v1/staff/orders/pending-approval
|
|
*/
|
|
public function pendingApproval(Request $request): JsonResponse
|
|
{
|
|
$validated = $request->validate([
|
|
'per_page' => ['nullable', 'integer', 'min:1', 'max:100'],
|
|
]);
|
|
|
|
$shipments = Shipment::query()
|
|
->where('status', ShipmentStatus::PendingApproval)
|
|
->with(['fromCountry', 'toCountry', 'user'])
|
|
->orderBy('created_at', 'asc')
|
|
->paginate($validated['per_page'] ?? 15);
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'data' => $shipments->map(function ($shipment) {
|
|
return $this->formatShipment($shipment);
|
|
}),
|
|
'pagination' => [
|
|
'current_page' => $shipments->currentPage(),
|
|
'last_page' => $shipments->lastPage(),
|
|
'per_page' => $shipments->perPage(),
|
|
'total' => $shipments->total(),
|
|
],
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* درخواست اصلاح سفارش توسط کارمند
|
|
* POST /api/v1/staff/orders/{shipment}/request-changes
|
|
*/
|
|
public function requestChanges(
|
|
Shipment $shipment,
|
|
Request $request,
|
|
ShipmentReviewService $reviewService
|
|
): JsonResponse {
|
|
$user = Auth::user();
|
|
|
|
$validated = $request->validate([
|
|
'reason' => ['required', 'string', 'max:1000'],
|
|
'notes' => ['nullable', 'string', 'max:1000'],
|
|
]);
|
|
|
|
try {
|
|
$shipment = $reviewService->requestChanges(
|
|
$shipment,
|
|
$user,
|
|
$validated['reason'],
|
|
$validated['notes'] ?? null
|
|
);
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'message' => 'اصلاحات موردنیاز برای سفارش ثبت شد.',
|
|
'data' => $this->formatShipment(
|
|
$shipment->load(['fromCountry', 'toCountry'])
|
|
),
|
|
]);
|
|
} catch (\RuntimeException $e) {
|
|
return response()->json([
|
|
'success' => false,
|
|
'message' => $e->getMessage(),
|
|
], 400);
|
|
} catch (\Throwable $e) {
|
|
return response()->json([
|
|
'success' => false,
|
|
'message' => 'خطا در ثبت درخواست اصلاح سفارش.',
|
|
], 500);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* تأیید سفارش توسط کارمند
|
|
* POST /api/v1/staff/orders/{shipment}/approve
|
|
*/
|
|
public function approve(
|
|
Shipment $shipment,
|
|
Request $request,
|
|
ShipmentReviewService $reviewService
|
|
): JsonResponse {
|
|
$user = Auth::user();
|
|
|
|
$validated = $request->validate([
|
|
'notes' => ['nullable', 'string', 'max:1000'],
|
|
]);
|
|
|
|
try {
|
|
$shipment = $reviewService->approve(
|
|
$shipment,
|
|
$user,
|
|
$validated['notes'] ?? null
|
|
);
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'message' => 'سفارش با موفقیت تأیید شد. مشتری میتواند پرداخت را انجام دهد.',
|
|
'data' => $this->formatShipment(
|
|
$shipment->load(['fromCountry', 'toCountry'])
|
|
),
|
|
]);
|
|
} catch (\RuntimeException $e) {
|
|
return response()->json([
|
|
'success' => false,
|
|
'message' => $e->getMessage(),
|
|
], 400);
|
|
} catch (\Throwable $e) {
|
|
return response()->json([
|
|
'success' => false,
|
|
'message' => 'خطا در تأیید سفارش.',
|
|
], 500);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* رد سفارش توسط کارمند
|
|
* POST /api/v1/staff/orders/{shipment}/reject
|
|
*/
|
|
public function reject(
|
|
Shipment $shipment,
|
|
Request $request,
|
|
ShipmentReviewService $reviewService
|
|
): JsonResponse {
|
|
$user = Auth::user();
|
|
|
|
$validated = $request->validate([
|
|
'reason' => ['required', 'string', 'max:1000'],
|
|
]);
|
|
|
|
try {
|
|
$shipment = $reviewService->reject(
|
|
$shipment,
|
|
$user,
|
|
$validated['reason']
|
|
);
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'message' => 'سفارش رد شد.',
|
|
'data' => $this->formatShipment(
|
|
$shipment->load(['fromCountry', 'toCountry'])
|
|
),
|
|
]);
|
|
} catch (\RuntimeException $e) {
|
|
return response()->json([
|
|
'success' => false,
|
|
'message' => $e->getMessage(),
|
|
], 400);
|
|
} catch (\Throwable $e) {
|
|
return response()->json([
|
|
'success' => false,
|
|
'message' => 'خطا در رد سفارش.',
|
|
], 500);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* فرمت کردن Shipment برای خروجی API
|
|
*/
|
|
private function formatShipment(Shipment $shipment): array
|
|
{
|
|
return [
|
|
'id' => $shipment->id,
|
|
'awb_no' => $shipment->awb_no,
|
|
'direction' => $shipment->direction?->value,
|
|
'type' => $shipment->type?->value,
|
|
|
|
'status' => [
|
|
'value' => $shipment->status?->value,
|
|
'label' => $shipment->status?->label(),
|
|
'color' => $shipment->status?->color(),
|
|
],
|
|
|
|
'review' => [
|
|
'state' => $shipment->review_state?->value,
|
|
'label' => $shipment->review_state?->label(),
|
|
'color' => $shipment->review_state?->color(),
|
|
],
|
|
|
|
'from_country' => $shipment->fromCountry ? [
|
|
'id' => $shipment->fromCountry->id,
|
|
'name' => $shipment->fromCountry->name,
|
|
'iso_code' => $shipment->fromCountry->iso_code,
|
|
] : null,
|
|
|
|
'to_country' => $shipment->toCountry ? [
|
|
'id' => $shipment->toCountry->id,
|
|
'name' => $shipment->toCountry->name,
|
|
'iso_code' => $shipment->toCountry->iso_code,
|
|
] : null,
|
|
|
|
'user' => $shipment->user ? [
|
|
'id' => $shipment->user->id,
|
|
'name' => $shipment->user->name,
|
|
'email' => $shipment->user->email,
|
|
] : null,
|
|
|
|
'weight' => $shipment->weight,
|
|
'chargeable_weight' => $shipment->chargeable_weight,
|
|
'total_fee' => $shipment->total_fee,
|
|
'created_at' => $shipment->created_at->toIso8601String(),
|
|
'created_at_jalali' => $this->toJalali($shipment->created_at),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* تبدیل تاریخ به شمسی
|
|
*/
|
|
private function toJalali($date): string
|
|
{
|
|
if (!$date) {
|
|
return '—';
|
|
}
|
|
|
|
try {
|
|
return \Morilog\Jalali\Jalalian::fromCarbon($date)->format('Y/m/d H:i');
|
|
} catch (\Exception $e) {
|
|
return $date->format('Y-m-d H:i');
|
|
}
|
|
}
|
|
} |