Fix: Move carrier live-pricing choice onto ShippingMethod.charge_by
Reverts the earlier per-rate pricing_mode column in favor of extending Lunar's existing charge_by field (cart_total/weight) with a third "live" option, gated by a SupportsLivePricing capability check on the driver. Adds a shared ResolvesFixedPricing trait so any carrier driver can fall back to Lunar's normal price-break resolution, matching the vendor ShipBy driver's own charge_by handling instead of introducing a separate mechanism. Also fixes an incorrect Get() path in the admin form that silently hid the new "live" option.
This commit is contained in:
@@ -6,20 +6,88 @@ use Filament\Forms\Components\Component;
|
||||
use Filament\Forms\Components\Concerns\HasChildComponents;
|
||||
use Filament\Forms\Components\Select;
|
||||
use Filament\Forms\Form;
|
||||
use Filament\Forms\Get;
|
||||
use Filament\Tables\Columns\TextColumn;
|
||||
use Filament\Tables\Table;
|
||||
use Lunar\Admin\Support\Extending\ResourceExtension;
|
||||
use Lunar\Shipping\Facades\Shipping;
|
||||
use Modules\Core\Shipping\Contracts\SupportsLivePricing;
|
||||
|
||||
class ShippingMethodResourceExtension extends ResourceExtension
|
||||
{
|
||||
public function extendForm(Form $form): Form
|
||||
{
|
||||
return $form->schema(
|
||||
$this->replaceDriverField($form->getComponents())
|
||||
$this->replaceChargeByField(
|
||||
$this->replaceDriverField($form->getComponents())
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extend the vendor's cart_total/weight charge_by Select with a third
|
||||
* "live" option — only offered when the currently selected driver
|
||||
* supports live pricing (see SupportsLivePricing). Picking it is what
|
||||
* tells the driver to call its carrier API instead of resolving a
|
||||
* price break.
|
||||
*/
|
||||
private function replaceChargeByField(array $components): array
|
||||
{
|
||||
return array_map(function (Component $component) {
|
||||
if (method_exists($component, 'getName') && $component->getName() === 'charge_by') {
|
||||
return $this->chargeBySelect();
|
||||
}
|
||||
|
||||
if (in_array(HasChildComponents::class, class_uses_recursive($component), true)) {
|
||||
$component->schema(
|
||||
$this->replaceChargeByField($component->getChildComponents())
|
||||
);
|
||||
}
|
||||
|
||||
return $component;
|
||||
}, $components);
|
||||
}
|
||||
|
||||
private function chargeBySelect(): Select
|
||||
{
|
||||
return Select::make('charge_by')
|
||||
->label('Charge by')
|
||||
->options(function (Get $get) {
|
||||
$options = [
|
||||
'cart_total' => 'Cart Total',
|
||||
'weight' => 'Weight',
|
||||
];
|
||||
|
||||
// "charge_by" is nested inside a Group with
|
||||
// ->statePath('data'), while "driver" sits one level up, at
|
||||
// the form root. Note: an *absolute* path here would need to
|
||||
// additionally account for the page's own form wrapper
|
||||
// (EditRecord::getFormStatePath() === 'data'), which relative
|
||||
// paths never cross — so "../driver" (relative) is the
|
||||
// correct, page-independent way to reach it, not an
|
||||
// absolute 'driver' string.
|
||||
if ($this->driverSupportsLivePricing($get('../driver'))) {
|
||||
$options['live'] = 'Live API pricing';
|
||||
}
|
||||
|
||||
return $options;
|
||||
})
|
||||
->live();
|
||||
}
|
||||
|
||||
private function driverSupportsLivePricing(?string $driver): bool
|
||||
{
|
||||
if (! $driver) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
return Shipping::driver($driver) instanceof SupportsLivePricing;
|
||||
} catch (\InvalidArgumentException) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function extendTable(Table $table): Table
|
||||
{
|
||||
return $table->columns(
|
||||
@@ -78,6 +146,7 @@ class ShippingMethodResourceExtension extends ResourceExtension
|
||||
->label('Type')
|
||||
->options(fn () => collect(Shipping::getSupportedDrivers())
|
||||
->mapWithKeys(fn ($driver, $key) => [$key => $driver->name()]))
|
||||
->default('flat-rate');
|
||||
->default('flat-rate')
|
||||
->live();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user