Introduce a comprehensive set of commercial features including a multi-step order approval workflow, customer credit management, and specialized import service invoicing. Key changes: - Implement `pending_approval` and `approved` shipment statuses to allow staff verification before customer payment. - Add a credit system to `User` model with `credit_limit` and `credit_used` to manage customer balances and debts. - Develop a new `importInvoice` PDF generation service following the "Sheet ENG Invoice" specification for import services. - Add Filament resources for managing Audit Logs, Commitment Forms, Customer Credits, and Shipment Checklists. - Implement staff-specific APIs for order approval/rejection and customer financial status monitoring. - Integrate Kavenegar SMS service for mobile verification and notifications. - Add bulk tracking import functionality via CSV/Excel. - Update WordPress bridge assets (CSS/JS) to support the new multi-step order form UI and updated redirection logic. - Update deployment configurations and documentation to reflect new production domains and feature sets.
202 lines
7.0 KiB
PHP
202 lines
7.0 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Api;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Models\Shipment;
|
|
use App\Models\ShipmentStatusHistory;
|
|
use App\Enums\ShipmentStatus;
|
|
use Illuminate\Http\JsonResponse;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\Auth;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
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}/approve
|
|
*/
|
|
public function approve(Shipment $shipment, Request $request): JsonResponse
|
|
{
|
|
$user = Auth::user();
|
|
|
|
// بررسی وضعیت
|
|
if ($shipment->status !== ShipmentStatus::PendingApproval) {
|
|
return response()->json([
|
|
'success' => false,
|
|
'message' => 'این سفارش در وضعیت قابل تأیید نیست.',
|
|
], 400);
|
|
}
|
|
|
|
$validated = $request->validate([
|
|
'notes' => ['nullable', 'string', 'max:1000'],
|
|
]);
|
|
|
|
try {
|
|
DB::transaction(function () use ($shipment, $user, $validated) {
|
|
// تغییر وضعیت به Approved
|
|
$oldStatus = $shipment->status;
|
|
$shipment->update([
|
|
'status' => ShipmentStatus::Approved,
|
|
]);
|
|
|
|
// ثبت در تاریخچه تغییرات
|
|
ShipmentStatusHistory::create([
|
|
'shipment_id' => $shipment->id,
|
|
'old_status' => $oldStatus->value,
|
|
'new_status' => ShipmentStatus::Approved->value,
|
|
'changed_by' => $user->id,
|
|
'notes' => $validated['notes'] ?? 'تأیید توسط کارمند',
|
|
]);
|
|
});
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'message' => 'سفارش با موفقیت تأیید شد. مشتری میتواند پرداخت را انجام دهد.',
|
|
'data' => $this->formatShipment($shipment->fresh()->load(['fromCountry', 'toCountry'])),
|
|
]);
|
|
|
|
} catch (\Exception $e) {
|
|
return response()->json([
|
|
'success' => false,
|
|
'message' => 'خطا در تأیید سفارش: ' . $e->getMessage(),
|
|
], 500);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* رد سفارش توسط کارمند
|
|
* POST /api/v1/staff/orders/{shipment}/reject
|
|
*/
|
|
public function reject(Shipment $shipment, Request $request): JsonResponse
|
|
{
|
|
$user = Auth::user();
|
|
|
|
// بررسی وضعیت
|
|
if ($shipment->status !== ShipmentStatus::PendingApproval) {
|
|
return response()->json([
|
|
'success' => false,
|
|
'message' => 'این سفارش در وضعیت قابل رد نیست.',
|
|
], 400);
|
|
}
|
|
|
|
$validated = $request->validate([
|
|
'reason' => ['required', 'string', 'max:1000'],
|
|
]);
|
|
|
|
try {
|
|
DB::transaction(function () use ($shipment, $user, $validated) {
|
|
// تغییر وضعیت به Cancelled
|
|
$oldStatus = $shipment->status;
|
|
$shipment->update([
|
|
'status' => ShipmentStatus::Cancelled,
|
|
]);
|
|
|
|
// ثبت در تاریخچه تغییرات
|
|
ShipmentStatusHistory::create([
|
|
'shipment_id' => $shipment->id,
|
|
'old_status' => $oldStatus->value,
|
|
'new_status' => ShipmentStatus::Cancelled->value,
|
|
'changed_by' => $user->id,
|
|
'notes' => 'رد شده: ' . $validated['reason'],
|
|
]);
|
|
});
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'message' => 'سفارش رد شد.',
|
|
'data' => $this->formatShipment($shipment->fresh()->load(['fromCountry', 'toCountry'])),
|
|
]);
|
|
|
|
} catch (\Exception $e) {
|
|
return response()->json([
|
|
'success' => false,
|
|
'message' => 'خطا در رد سفارش: ' . $e->getMessage(),
|
|
], 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(),
|
|
],
|
|
'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');
|
|
}
|
|
}
|
|
}
|