Implement additional address and identification fields for both sender and receiver across the WordPress plugin and Laravel API. This includes state, postal code, and national ID/passport information. Key changes: - Added database migration to include postal and national ID fields in the shipments table. - Updated WordPress order form shortcodes and JavaScript to capture new address fields. - Refactored Laravel `CustomerOrderController` validation and storage to support expanded shipment data. - Implemented tiered data visibility in `TrackController` to protect PII, providing masked data to anonymous users and full data to owners/admins. - Fixed weight-based rate lookup logic in `PriceCalculatorService` to correctly select the appropriate shipping tier.
131 lines
5.5 KiB
PHP
131 lines
5.5 KiB
PHP
<?php
|
||
|
||
namespace App\Http\Controllers\Api;
|
||
|
||
use App\Http\Controllers\Controller;
|
||
use App\Models\Shipment;
|
||
use Illuminate\Http\JsonResponse;
|
||
use Illuminate\Http\Request;
|
||
|
||
/**
|
||
* API ترکینگ مرسولات — فاز ۰
|
||
*
|
||
* GET /api/v1/track/{awb_no}
|
||
*
|
||
* خروجی: تایملاین کامل رویدادهای ترکینگ + اطلاعات پایه مرسوله + نگاشتهای شرکت حمل
|
||
*
|
||
* امنیت: نمایش لایهبندیشده (Tiered Display)
|
||
* - کاربر ناشناس: فقط وضعیت فعلی و موقعیت
|
||
* - کاربر لاگینشده (مالک): اطلاعات کامل فرستنده/گیرنده (مخففشده)
|
||
* - ادمین: اطلاعات کامل
|
||
*/
|
||
class TrackController extends Controller
|
||
{
|
||
/**
|
||
* دریافت تایملاین ترکینگ یک مرسوله
|
||
*/
|
||
public function show(string $awb_no, Request $request): JsonResponse
|
||
{
|
||
$shipment = Shipment::where('awb_no', $awb_no)
|
||
->with([
|
||
'fromCountry:id,name,iso_code',
|
||
'toCountry:id,name,iso_code',
|
||
'carrierMappings:id,shipment_id,carrier_code,carrier_tracking_number,booking_number,direction,delivery_status,notes',
|
||
'trackingEvents' => fn ($query) => $query->orderBy('event_date', 'desc')->orderBy('event_time', 'desc'),
|
||
])
|
||
->first();
|
||
|
||
if (!$shipment) {
|
||
return response()->json([
|
||
'success' => false,
|
||
'message' => 'مرسولهای با این کد یافت نشد',
|
||
'awb_no' => $awb_no,
|
||
], 404);
|
||
}
|
||
|
||
// بررسی سطح دسترسی کاربر
|
||
$user = $request->user();
|
||
$isOwner = $user && $shipment->user_id === $user->id;
|
||
$isAdmin = $user && $user->hasRole('super_admin');
|
||
|
||
// لایه ۱: اطلاعات عمومی (همیشه نمایش داده میشود)
|
||
$publicData = [
|
||
'shipment' => [
|
||
'awb_no' => $shipment->awb_no,
|
||
'direction' => $shipment->direction?->value,
|
||
'type' => $shipment->type?->value,
|
||
'status' => $shipment->status?->value,
|
||
'status_label' => $shipment->status?->label(),
|
||
'from_country' => $shipment->fromCountry?->name,
|
||
'to_country' => $shipment->toCountry?->name,
|
||
'weight' => $shipment->weight,
|
||
'created_at' => $shipment->created_at?->toIso8601String(),
|
||
],
|
||
'carrier_mappings' => $shipment->carrierMappings->map(fn ($mapping) => [
|
||
'carrier_code' => $mapping->carrier_code,
|
||
'carrier_tracking_number' => $mapping->carrier_tracking_number,
|
||
'booking_number' => $mapping->booking_number,
|
||
'delivery_status' => $mapping->delivery_status,
|
||
'notes' => $mapping->notes,
|
||
]),
|
||
'tracking_events' => $shipment->trackingEvents->map(fn ($event) => [
|
||
'date' => $event->event_date?->toDateString(),
|
||
'time' => $event->event_time ? ($event->event_time instanceof \Carbon\Carbon ? $event->event_time->format('H:i') : $event->event_time) : null,
|
||
'location' => $event->location,
|
||
'description' => $event->event_description,
|
||
'status' => $event->delivery_status,
|
||
'source' => $event->source,
|
||
]),
|
||
];
|
||
|
||
// لایه ۲: اطلاعات مالک (فقط اگه کاربر لاگین کرده و مالک مرسوله باشه)
|
||
if ($isOwner || $isAdmin) {
|
||
$publicData['shipment']['sender_name'] = $shipment->sender_name;
|
||
$publicData['shipment']['receiver_name'] = $shipment->receiver_name;
|
||
$publicData['shipment']['sender_phone'] = $shipment->sender_phone;
|
||
$publicData['shipment']['receiver_phone'] = $shipment->receiver_phone;
|
||
$publicData['shipment']['sender_address'] = $shipment->sender_address;
|
||
$publicData['shipment']['receiver_address'] = $shipment->receiver_address;
|
||
} else {
|
||
// برای کاربر ناشناس، فقط نام مخففشده رو نشون بده
|
||
$publicData['shipment']['sender_name'] = $this->maskName($shipment->sender_name);
|
||
$publicData['shipment']['receiver_name'] = $this->maskName($shipment->receiver_name);
|
||
$publicData['shipment']['sender_phone'] = null;
|
||
$publicData['shipment']['receiver_phone'] = null;
|
||
$publicData['shipment']['sender_address'] = null;
|
||
$publicData['shipment']['receiver_address'] = null;
|
||
$publicData['shipment']['is_anonymous'] = true;
|
||
}
|
||
|
||
return response()->json([
|
||
'success' => true,
|
||
'data' => $publicData,
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* مخفیسازی بخشی از نام برای کاربران ناشناس
|
||
* مثال: "Akbar Salmanizadeh" → "A. Sal***zadeh"
|
||
*/
|
||
private function maskName(?string $name): ?string
|
||
{
|
||
if (!$name) {
|
||
return null;
|
||
}
|
||
|
||
$parts = explode(' ', $name);
|
||
$first = substr($parts[0], 0, 1) . '.';
|
||
|
||
if (count($parts) > 1) {
|
||
$last = $parts[1];
|
||
if (strlen($last) > 4) {
|
||
$last = substr($last, 0, 3) . '***' . substr($last, -3);
|
||
} else {
|
||
$last = substr($last, 0, 1) . '***';
|
||
}
|
||
return $first . ' ' . $last;
|
||
}
|
||
|
||
return $first;
|
||
}
|
||
} |