2026-07-19 00:52:01 +03:00
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
namespace Modules\Core\Shipping\Extensions;
|
|
|
|
|
|
2026-08-31 13:16:13 +03:00
|
|
|
use Filament\Actions\Action;
|
|
|
|
|
use Filament\Forms\Components\TextInput;
|
|
|
|
|
use Filament\Forms\Components\Toggle;
|
|
|
|
|
use Closure;
|
|
|
|
|
use Throwable;
|
2026-07-19 00:52:01 +03:00
|
|
|
use Filament\Actions;
|
|
|
|
|
use Filament\Forms;
|
|
|
|
|
use Filament\Notifications\Notification;
|
|
|
|
|
use Lunar\Admin\Support\Extending\ViewPageExtension;
|
|
|
|
|
use Lunar\Models\Order;
|
|
|
|
|
use Lunar\Shipping\Models\ShippingMethod;
|
|
|
|
|
use Modules\Core\Shipping\Contracts\CarrierFulfillmentInterface;
|
2026-09-03 15:58:51 +03:00
|
|
|
use Modules\Core\Shipping\DTOs\ShipmentRequest;
|
2026-07-19 00:52:01 +03:00
|
|
|
|
|
|
|
|
class OrderViewExtension extends ViewPageExtension
|
|
|
|
|
{
|
|
|
|
|
public function headerActions(array $actions): array
|
|
|
|
|
{
|
|
|
|
|
$actions[] = $this->createShipmentAction();
|
|
|
|
|
|
|
|
|
|
return $actions;
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-31 13:16:13 +03:00
|
|
|
private function createShipmentAction(): Action
|
2026-07-19 00:52:01 +03:00
|
|
|
{
|
2026-08-31 13:16:13 +03:00
|
|
|
return Action::make('create_shipment')
|
2026-07-19 00:52:01 +03:00
|
|
|
->label('Create Shipment')
|
|
|
|
|
->icon('heroicon-o-truck')
|
|
|
|
|
->modalSubmitActionLabel('Create Shipment')
|
2026-08-31 13:16:13 +03:00
|
|
|
->schema([
|
|
|
|
|
TextInput::make('weight')
|
2026-07-19 18:27:24 +03:00
|
|
|
->label('Package weight (kg)')
|
|
|
|
|
->numeric()
|
|
|
|
|
->minValue(0)
|
|
|
|
|
->helperText('Leave blank to use the carrier\'s default.'),
|
2026-08-31 13:16:13 +03:00
|
|
|
TextInput::make('destination_location_id')
|
2026-07-19 18:27:24 +03:00
|
|
|
->label('Box Now locker ID')
|
|
|
|
|
->helperText('Only required for Box Now shipments.')
|
|
|
|
|
->default(fn (Order $record) => $record->shippingAddress?->meta['box_now_locker']['locationId'] ?? null),
|
2026-08-31 13:16:13 +03:00
|
|
|
Toggle::make('confirm')
|
2026-07-19 00:52:01 +03:00
|
|
|
->label('Confirm')
|
|
|
|
|
->helperText('This will create a real shipment with the carrier.')
|
|
|
|
|
->rules([
|
|
|
|
|
function () {
|
2026-08-31 13:16:13 +03:00
|
|
|
return function (string $attribute, $value, Closure $fail) {
|
2026-07-19 00:52:01 +03:00
|
|
|
if ($value !== true) {
|
|
|
|
|
$fail('Please confirm before creating the shipment.');
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
},
|
|
|
|
|
]),
|
|
|
|
|
])
|
2026-08-31 13:16:13 +03:00
|
|
|
->action(function (Order $record, array $data, Action $action) {
|
2026-07-19 00:52:01 +03:00
|
|
|
$service = $this->resolveFulfillmentService($record);
|
|
|
|
|
|
|
|
|
|
if (! $service) {
|
|
|
|
|
Notification::make()
|
|
|
|
|
->title('No carrier fulfillment integration is configured for this order.')
|
|
|
|
|
->danger()
|
|
|
|
|
->send();
|
|
|
|
|
|
|
|
|
|
$action->halt();
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-19 18:27:24 +03:00
|
|
|
$request = new ShipmentRequest(
|
|
|
|
|
weight: filled($data['weight'] ?? null) ? (float) $data['weight'] : null,
|
|
|
|
|
destinationLocationId: $data['destination_location_id'] ?? null,
|
|
|
|
|
);
|
|
|
|
|
|
2026-07-19 00:52:01 +03:00
|
|
|
try {
|
2026-07-19 18:27:24 +03:00
|
|
|
$service->createShipment($record, $request);
|
2026-08-31 13:16:13 +03:00
|
|
|
} catch (Throwable $e) {
|
2026-07-19 00:52:01 +03:00
|
|
|
report($e);
|
|
|
|
|
|
|
|
|
|
Notification::make()
|
|
|
|
|
->title('Failed to create shipment: '.$e->getMessage())
|
|
|
|
|
->danger()
|
|
|
|
|
->send();
|
|
|
|
|
|
|
|
|
|
$action->halt();
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Notification::make()
|
|
|
|
|
->title('Shipment created.')
|
|
|
|
|
->success()
|
|
|
|
|
->send();
|
|
|
|
|
})
|
|
|
|
|
->visible(fn (Order $record) => $record->shipments()->exists() === false
|
|
|
|
|
&& $this->resolveFulfillmentService($record) !== null);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private function resolveCarrier(Order $record): ?string
|
|
|
|
|
{
|
|
|
|
|
$code = $record->shippingAddress?->shipping_option;
|
|
|
|
|
|
|
|
|
|
if (! $code) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ShippingMethod::where('code', $code)->value('driver');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private function resolveFulfillmentService(Order $record): ?CarrierFulfillmentInterface
|
|
|
|
|
{
|
|
|
|
|
$carrier = $this->resolveCarrier($record);
|
|
|
|
|
|
|
|
|
|
if (! $carrier) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return app(CarrierFulfillmentInterface::class, ['carrier' => $carrier]);
|
|
|
|
|
}
|
|
|
|
|
}
|