Feature: Shipping Carrier Additions, Creating a voucher without an order, verifying order details before creating voucher, ELTA Courier voucher print updates
This commit is contained in:
@@ -76,11 +76,24 @@ class CarrierVoucherResource extends Resource
|
||||
|
||||
public static function getEloquentQuery(): Builder
|
||||
{
|
||||
return parent::getEloquentQuery()
|
||||
->whereNotNull('tracking_reference')
|
||||
return self::vouchers(parent::getEloquentQuery())
|
||||
->with(['order.shippingAddress', 'shipmentInfo']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Vouchers with a number, plus ours still waiting for one (an ELTA
|
||||
* voucher gets its number when printed) so they can be printed from
|
||||
* here too.
|
||||
*/
|
||||
public static function vouchers(Builder $query): Builder
|
||||
{
|
||||
return $query->where(fn (Builder $q) => $q
|
||||
->whereNotNull('tracking_reference')
|
||||
->orWhere(fn (Builder $pending) => $pending
|
||||
->where('source', Shipment::SOURCE_CREATED)
|
||||
->whereNull('cancelled_at')));
|
||||
}
|
||||
|
||||
public static function table(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
@@ -88,8 +101,12 @@ class CarrierVoucherResource extends Resource
|
||||
->columns([
|
||||
TextColumn::make('tracking_reference')
|
||||
->label('Tracking number')
|
||||
->placeholder('Not issued yet')
|
||||
->description(fn (Shipment $record) => $record->parcelDescription())
|
||||
->copyable(),
|
||||
TextColumn::make('carrier')
|
||||
->label('Carrier')
|
||||
->formatStateUsing(fn (Shipment $record) => $record->carrierLabel()),
|
||||
TextColumn::make('source')
|
||||
->label('Source')
|
||||
->badge()
|
||||
@@ -98,12 +115,12 @@ class CarrierVoucherResource extends Resource
|
||||
TextColumn::make('status')
|
||||
->label('Status')
|
||||
->state(fn (Shipment $record) => self::status($record))
|
||||
->placeholder('No updates yet')
|
||||
->placeholder('None yet')
|
||||
->badge()
|
||||
->color(fn (Shipment $record) => self::statusColor($record)),
|
||||
TextColumn::make('order.reference')
|
||||
->label('Order')
|
||||
->placeholder('Not linked'),
|
||||
->placeholder('None'),
|
||||
TextColumn::make('recipient')
|
||||
->label('Recipient')
|
||||
->state(fn (Shipment $record) => self::recipient($record))
|
||||
@@ -114,6 +131,9 @@ class CarrierVoucherResource extends Resource
|
||||
->where('tracking_reference', 'ilike', "%{$search}%")
|
||||
->orWhere('meta->recipient_name', 'ilike', "%{$search}%")
|
||||
->orWhere('meta->phone', 'ilike', "%{$search}%")
|
||||
->orWhere('meta->recipient->name', 'ilike', "%{$search}%")
|
||||
->orWhere('meta->recipient->phone', 'ilike', "%{$search}%")
|
||||
->orWhere('meta->recipient->mobile', 'ilike', "%{$search}%")
|
||||
->orWhereHas('order', fn (Builder $order) => $order
|
||||
->where('reference', 'ilike', "%{$search}%")
|
||||
->orWhereHas('shippingAddress', fn (Builder $address) => $address
|
||||
@@ -131,6 +151,7 @@ class CarrierVoucherResource extends Resource
|
||||
SelectFilter::make('source')->options(self::SOURCES),
|
||||
])
|
||||
->recordActions([
|
||||
self::printAction(),
|
||||
ViewAction::make(),
|
||||
]);
|
||||
}
|
||||
@@ -145,6 +166,7 @@ class CarrierVoucherResource extends Resource
|
||||
->formatStateUsing(fn (Shipment $record) => $record->carrierLabel()),
|
||||
TextEntry::make('tracking_reference')
|
||||
->label('Voucher')
|
||||
->placeholder('Not issued yet — printing issues it')
|
||||
->helperText(fn (Shipment $record) => $record->parcelDescription())
|
||||
->copyable(),
|
||||
TextEntry::make('source')
|
||||
@@ -188,12 +210,30 @@ class CarrierVoucherResource extends Resource
|
||||
->state(fn (Shipment $record) => self::recipient($record))
|
||||
->placeholder('—'),
|
||||
TextEntry::make('postcode')
|
||||
->state(fn (Shipment $record) => $record->meta['postcode'] ?? $record->order?->shippingAddress?->postcode)
|
||||
->state(fn (Shipment $record) => self::postcode($record))
|
||||
->placeholder('—'),
|
||||
TextEntry::make('phone')
|
||||
->state(fn (Shipment $record) => self::phone($record))
|
||||
->placeholder('—'),
|
||||
]),
|
||||
// What the carrier's tracking reports beyond the checkpoints
|
||||
// (ELTA's pel_rec) — filled in by the tracking polls.
|
||||
Section::make('Delivery')
|
||||
->columns(3)
|
||||
->schema([
|
||||
TextEntry::make('meta.delivered_to')->label('Received by')->placeholder('—'),
|
||||
TextEntry::make('meta.delivered_at')->label('Received at')->placeholder('—'),
|
||||
TextEntry::make('cod_remitted')
|
||||
->label('COD paid back')
|
||||
->state(fn (Shipment $record) => ($amount = $record->meta['cod_remitted'] ?? null)
|
||||
? trim('€'.number_format((float) $amount, 2).' '.($record->meta['cod_remittance'] ?? ''))
|
||||
: null)
|
||||
->placeholder('—'),
|
||||
TextEntry::make('meta.return_vg')->label('Return voucher')->placeholder('—'),
|
||||
])
|
||||
->visible(fn (Shipment $record) => filled($record->meta['delivered_to'] ?? null)
|
||||
|| filled($record->meta['cod_remitted'] ?? null)
|
||||
|| filled($record->meta['return_vg'] ?? null)),
|
||||
Section::make('Order')
|
||||
->schema([
|
||||
TextEntry::make('order.reference')
|
||||
@@ -241,6 +281,21 @@ class CarrierVoucherResource extends Resource
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the voucher's label (the same signed link as the order page and
|
||||
* Pending Vouchers) — for vouchers created here, from an order or with
|
||||
* "Create voucher". Carrier-reported and typed-in vouchers have no label
|
||||
* of ours to print.
|
||||
*/
|
||||
public static function printAction(): Action
|
||||
{
|
||||
return Action::make('print')
|
||||
->label('Print')
|
||||
->icon('heroicon-o-printer')
|
||||
->url(fn (Shipment $record) => ShipmentResource::labelUrl($record), shouldOpenInNewTab: true)
|
||||
->visible(fn (Shipment $record) => $record->hasCarrierLabel());
|
||||
}
|
||||
|
||||
/**
|
||||
* Attaches an unlinked voucher to an order (suggestions first), from the
|
||||
* view page.
|
||||
@@ -328,20 +383,25 @@ class CarrierVoucherResource extends Resource
|
||||
: $record->order->reference;
|
||||
}
|
||||
|
||||
/*
|
||||
* A synced voucher's recipient is what the carrier reported
|
||||
* (meta.recipient_name / phone / postcode); our own vouchers' is the
|
||||
* one saved when they were created (Shipment::recipient()).
|
||||
*/
|
||||
|
||||
private static function phone(Shipment $record): ?string
|
||||
{
|
||||
return $record->meta['phone'] ?? $record->order?->shippingAddress?->contact_phone;
|
||||
return $record->meta['phone'] ?? ($record->recipient()?->phones() ?: null);
|
||||
}
|
||||
|
||||
private static function recipient(Shipment $record): ?string
|
||||
{
|
||||
if ($name = $record->meta['recipient_name'] ?? null) {
|
||||
return $name;
|
||||
}
|
||||
return $record->meta['recipient_name'] ?? ($record->recipient()?->name ?: null);
|
||||
}
|
||||
|
||||
$address = $record->order?->shippingAddress;
|
||||
|
||||
return $address ? trim("{$address->first_name} {$address->last_name}") : null;
|
||||
private static function postcode(Shipment $record): ?string
|
||||
{
|
||||
return $record->meta['postcode'] ?? ($record->recipient()?->postcode ?: null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user