Feature: Order Updates, Events, Order Flows, Shipment And COD support
This commit is contained in:
@@ -0,0 +1,153 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Core\Shipping\Filament\Resources;
|
||||
|
||||
use Filament\Actions\Action;
|
||||
use Filament\Actions\BulkAction;
|
||||
use Filament\Notifications\Notification;
|
||||
use Filament\Resources\Resource;
|
||||
use Filament\Tables\Columns\TextColumn;
|
||||
use Filament\Tables\Table;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Collection;
|
||||
use Modules\Core\Shipping\Contracts\CarrierFulfillmentInterface;
|
||||
use Modules\Core\Shipping\Contracts\SupportsManifestBatching;
|
||||
use Modules\Core\Shipping\Filament\Resources\ShipmentResource\Pages\ListShipments;
|
||||
use Modules\Core\Shipping\Models\Shipment;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* Replaces the standalone Modules\Core\Shipping\Filament\Pages\
|
||||
* ManagePickupManifests page — a bare Page has no access to Filament's
|
||||
* resource-level pill-tab UI (Filament\Resources\Concerns\HasTabs is
|
||||
* scoped to ListRecords), so carrier-by-carrier separation
|
||||
* (ListShipments::getTabs(), one tab per SupportsManifestBatching
|
||||
* implementer) needed a real Resource to attach to.
|
||||
*
|
||||
* Shows only shipments NOT yet on an issued manifest — see
|
||||
* Modules\Core\Shipping\Filament\Resources\ManifestResource for
|
||||
* shipments that already are.
|
||||
*/
|
||||
class ShipmentResource extends Resource
|
||||
{
|
||||
protected static ?string $model = Shipment::class;
|
||||
|
||||
protected static string | \BackedEnum | null $navigationIcon = 'heroicon-o-truck';
|
||||
|
||||
protected static string | \UnitEnum | null $navigationGroup = 'Sales';
|
||||
|
||||
protected static ?string $navigationLabel = 'Pending Vouchers';
|
||||
|
||||
protected static ?string $modelLabel = 'Shipment';
|
||||
|
||||
protected static ?int $navigationSort = 100;
|
||||
|
||||
public static function getEloquentQuery(): Builder
|
||||
{
|
||||
return parent::getEloquentQuery()
|
||||
->whereNull('manifest_id')
|
||||
->whereNull('cancelled_at');
|
||||
}
|
||||
|
||||
public static function table(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->columns([
|
||||
TextColumn::make('carrier')->badge(),
|
||||
TextColumn::make('tracking_reference')->label('Tracking #'),
|
||||
TextColumn::make('order.reference')->label('Order'),
|
||||
TextColumn::make('label_printed_at')->label('Printed')->dateTime()->placeholder('Not printed'),
|
||||
])
|
||||
->recordActions([
|
||||
Action::make('print')
|
||||
->label('Print')
|
||||
->icon('heroicon-o-printer')
|
||||
->action(fn (Shipment $record) => self::printShipment($record)),
|
||||
])
|
||||
->toolbarActions([
|
||||
BulkAction::make('print_selected')
|
||||
->label('Print selected')
|
||||
->icon('heroicon-o-printer')
|
||||
->action(fn (Collection $records) => $records->each(fn (Shipment $shipment) => self::printShipment($shipment))),
|
||||
BulkAction::make('issue_manifest')
|
||||
->label('Issue Manifest')
|
||||
->icon('heroicon-o-check-circle')
|
||||
->action(fn (Collection $records) => self::issueManifest($records)),
|
||||
]);
|
||||
}
|
||||
|
||||
public static function printShipment(Shipment $shipment): void
|
||||
{
|
||||
$service = self::fulfillmentService($shipment->carrier);
|
||||
|
||||
if (! $service) {
|
||||
Notification::make()
|
||||
->title("No fulfillment integration configured for {$shipment->carrier}.")
|
||||
->danger()
|
||||
->send();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$service->printLabel($shipment);
|
||||
} catch (Throwable $e) {
|
||||
report($e);
|
||||
|
||||
Notification::make()
|
||||
->title("Failed to print label for {$shipment->tracking_reference}: {$e->getMessage()}")
|
||||
->danger()
|
||||
->send();
|
||||
}
|
||||
}
|
||||
|
||||
public static function issueManifest(Collection $shipments): void
|
||||
{
|
||||
$shipments->groupBy('carrier')->each(function (Collection $group, string $carrier) {
|
||||
$service = self::fulfillmentService($carrier);
|
||||
|
||||
if (! $service instanceof SupportsManifestBatching) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$result = $service->issueManifest($group);
|
||||
} catch (Throwable $e) {
|
||||
report($e);
|
||||
|
||||
Notification::make()
|
||||
->title("Failed to issue manifest for {$carrier}: {$e->getMessage()}")
|
||||
->danger()
|
||||
->send();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (! $result->success) {
|
||||
Notification::make()
|
||||
->title("Manifest blocked for {$carrier}: {$result->reason}")
|
||||
->danger()
|
||||
->send();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Notification::make()
|
||||
->title("Manifest issued for {$carrier}: {$result->reference}")
|
||||
->success()
|
||||
->send();
|
||||
});
|
||||
}
|
||||
|
||||
public static function fulfillmentService(string $carrier): ?CarrierFulfillmentInterface
|
||||
{
|
||||
return app(CarrierFulfillmentInterface::class, ['carrier' => $carrier]);
|
||||
}
|
||||
|
||||
public static function getPages(): array
|
||||
{
|
||||
return [
|
||||
'index' => ListShipments::route('/'),
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user