Feature: Adding Caches and Fallbacks to Live Pricing Requests

This commit is contained in:
2026-08-29 10:31:58 +03:00
parent 6671c5e9d1
commit f85fb51ecd
5 changed files with 182 additions and 44 deletions
@@ -2,10 +2,12 @@
namespace Modules\Core\Shipping\Filament\Pages;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Form;
use Filament\Forms\Get;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Model;
use Lunar\Shipping\Filament\Resources\ShippingZoneResource\Pages\ManageShippingRates as BaseManageShippingRates;
use Lunar\Shipping\Models\ShippingMethod;
use Lunar\Shipping\Models\ShippingRate;
@@ -17,13 +19,20 @@ use Lunar\Shipping\Models\ShippingRate;
* ShippingZoneResource::getPages() — is untouched; the container simply
* hands back this subclass whenever the vendor class is resolved.
*
* Hides the price / price-break fields for a rate whose method has
* Relabels the price / price-break fields for a rate whose method has
* charge_by = "live" (see ShippingMethodResourceExtension, which adds that
* option to methods whose driver supports live pricing) — those fields
* would otherwise be dead configuration the driver never reads. Pricing
* strategy (cart_total / weight / live) stays entirely on the Shipping
* Method, matching Lunar's own existing charge_by convention; nothing new
* is stored on the rate itself.
* option to methods whose driver supports live pricing) — they stay
* visible and editable, but as the fallback price used when the live API
* call fails (see AcsRateDriver::resolveLivePrice()), not the primary
* price. Pricing strategy (cart_total / weight / live) stays entirely on
* the Shipping Method, matching Lunar's own existing charge_by convention;
* nothing new is stored on the rate itself.
*
* Also re-binds the vendor price field's afterStateHydrated(): the vendor
* callback reads $record->basePrices->first()->price->decimal with no
* null-guard, which crashes on any rate with no basePrices row — routine
* for a live rate that has never had a fallback price configured. Same
* logic, just null-safe.
*/
class ManageShippingRates extends BaseManageShippingRates
{
@@ -32,13 +41,13 @@ class ManageShippingRates extends BaseManageShippingRates
$form = parent::form($form);
return $form->schema(
$this->hidePriceFieldsWhenLive($form->getComponents())
$this->labelPriceFieldsAsFallbackWhenLive($form->getComponents())
);
}
private function hidePriceFieldsWhenLive(array $components): array
private function labelPriceFieldsAsFallbackWhenLive(array $components): array
{
$isNotLive = fn (Get $get) => static::methodChargeBy($get('shipping_method_id')) !== 'live';
$isLive = fn (Get $get) => static::methodChargeBy($get('shipping_method_id')) === 'live';
foreach ($components as $component) {
if (! method_exists($component, 'getName')) {
@@ -46,11 +55,25 @@ class ManageShippingRates extends BaseManageShippingRates
}
if ($component->getName() === 'price') {
$component->visible($isNotLive)->required($isNotLive)->dehydrated(true);
$component->required(fn (Get $get) => ! $isLive($get))
->helperText(fn (Get $get) => $isLive($get)
? 'Used only if the live API call fails.'
: null)
->afterStateHydrated(static function (TextInput $component, ?Model $record = null): void {
if (! $record) {
return;
}
$basePrice = $record->basePrices->first();
$component->state($basePrice?->price->decimal);
});
}
if ($component->getName() === 'prices') {
$component->visible($isNotLive)->dehydrated(true);
$component->helperText(fn (Get $get) => $isLive($get)
? 'Used only if the live API call fails.'
: null);
}
}
@@ -68,7 +91,9 @@ class ManageShippingRates extends BaseManageShippingRates
->label(__('lunarpanel.shipping::relationmanagers.shipping_rates.table.price.label'))
->formatStateUsing(function ($state, ShippingRate $record) {
if (static::methodChargeBy($record->shipping_method_id) === 'live') {
return 'Live API pricing';
return $state === null
? 'Live API pricing, no fallback set'
: $state->price->formatted.' (fallback)';
}
return $state?->price->formatted;
@@ -80,15 +105,6 @@ class ManageShippingRates extends BaseManageShippingRates
);
}
protected static function saveShippingRate(?ShippingRate $shippingRate = null, array $data = []): void
{
if (static::methodChargeBy($data['shipping_method_id'] ?? $shippingRate?->shipping_method_id) === 'live') {
return;
}
parent::saveShippingRate($shippingRate, $data);
}
protected static function methodChargeBy(ShippingMethod|int|string|null $method): ?string
{
if (blank($method)) {