refactor: Split shipping_address into component fields for ShipLogic API

- Create migration to add shipping_street_address, shipping_local_area, shipping_city, shipping_zone, shipping_country, shipping_postcode, shipping_type
- Update Order model fillable array with new address component fields
- Remove address parsing logic from CourierService
- Use individual address fields directly in ShipLogic API payload
- Fields match ShipLogic API requirements (street_address, local_area, city, zone, code, country, type)
- Note: Custom orders address collection can be implemented later
This commit is contained in:
twotalesanimation
2026-01-02 21:40:16 +02:00
parent 206ea2d35c
commit 124ab46507
4 changed files with 905 additions and 9 deletions
+62 -9
View File
@@ -115,26 +115,70 @@ class CourierService
}
try {
// Fetch order to get customer and shipping details
$order = Order::findOrFail($orderId);
// Validate required shipping info
if (! $order->customer_name || ! $order->shipping_street_address) {
throw new \Exception('Order missing required customer name or shipping address');
}
if (! $order->customer_email && ! $order->customer_phone) {
throw new \Exception('Order must have at least email or phone number');
}
// Build shipment payload for Shiplogic
$payload = [
'parcel' => [
'weight' => $weight,
'height' => 10, // TODO: Update when height is captured separately
'width' => $width,
'length' => $length,
'collection_address' => [
'street' => 'Two Tales Designs', // TODO: Get from AppSetting
'city' => 'Cape Town',
'postcode' => '8000',
'country' => 'ZA',
],
'destination' => [
// TODO: Get from order's shipping address
'collection_contact' => [
'email' => config('mail.from.address'),
'mobile_number' => '+27000000000', // TODO: Get from AppSetting
],
'reference' => $orderId,
'delivery_address' => [
'type' => $order->shipping_type ?? 'residential',
'street_address' => $order->shipping_street_address,
'local_area' => $order->shipping_local_area,
'city' => $order->shipping_city,
'zone' => $order->shipping_zone,
'code' => $order->shipping_postcode,
'country' => $order->shipping_country ?? 'ZA',
],
'delivery_contact' => [
'name' => $order->customer_name,
'email' => $order->customer_email,
'mobile_number' => $order->customer_phone,
],
'parcels' => [
[
'weight' => $weight,
'height' => 10, // TODO: Update when height is captured separately
'width' => $width,
'length' => $length,
],
],
'service_level_id' => $this->getServiceLevelId(), // Standard delivery
'customer_reference' => $order->order_number,
'mute_notifications' => false,
];
Log::info('Creating Shiplogic shipment', [
'order_id' => $orderId,
'order_number' => $order->order_number,
'customer' => $order->customer_name,
'delivery_address' => $street,
]);
$response = Http::withHeaders([
'Authorization' => "Bearer {$this->apiKey}",
])->post("{$this->baseUrl}/shipments", $payload);
if (! $response->successful()) {
$errorMessage = $response->json('error.message', 'Unknown error');
$errorMessage = $response->json('error.message', $response->json('message', 'Unknown error'));
throw new \Exception("Courier API error: {$errorMessage}");
}
@@ -155,6 +199,15 @@ class CourierService
}
}
/**
* Get service level ID for standard delivery
* TODO: Move to AppSetting and make configurable
*/
private function getServiceLevelId(): int
{
return 1; // Standard service level
}
/**
* Validate packing gate: order must be packed with dimensions
*/