Files
core/src/Shipping/Extensions/OrderViewExtension.php
T

122 lines
4.1 KiB
PHP
Raw Normal View History

<?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;
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-07-19 18:27:24 +03:00
use Modules\Core\Shipping\DataTransferObjects\ShipmentRequest;
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-08-31 13:16:13 +03:00
return Action::make('create_shipment')
->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')
->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) {
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) {
$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,
);
try {
2026-07-19 18:27:24 +03:00
$service->createShipment($record, $request);
2026-08-31 13:16:13 +03:00
} catch (Throwable $e) {
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]);
}
}