Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 772c008949 | |||
| 77dbbd63a4 | |||
| ca5c826849 | |||
| 851bdc6031 |
@@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
$prefix = config('lunar.database.table_prefix');
|
||||||
|
|
||||||
|
Schema::table("{$prefix}shipping_rates", function (Blueprint $table) {
|
||||||
|
$table->string('pricing_mode')->default('live')->after('enabled');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
$prefix = config('lunar.database.table_prefix');
|
||||||
|
|
||||||
|
Schema::table("{$prefix}shipping_rates", function (Blueprint $table) {
|
||||||
|
$table->dropColumn('pricing_mode');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -4,17 +4,15 @@ namespace Modules\Core\Shipping\Carriers\Acs;
|
|||||||
|
|
||||||
use Lunar\DataTypes\Price;
|
use Lunar\DataTypes\Price;
|
||||||
use Lunar\DataTypes\ShippingOption;
|
use Lunar\DataTypes\ShippingOption;
|
||||||
|
use Lunar\Facades\Pricing;
|
||||||
use Lunar\Shipping\DataTransferObjects\ShippingOptionRequest;
|
use Lunar\Shipping\DataTransferObjects\ShippingOptionRequest;
|
||||||
use Lunar\Shipping\Interfaces\ShippingRateInterface;
|
use Lunar\Shipping\Interfaces\ShippingRateInterface;
|
||||||
use Lunar\Shipping\Models\ShippingRate;
|
use Lunar\Shipping\Models\ShippingRate;
|
||||||
use Modules\Core\Shipping\Carriers\Acs\Exceptions\AcsApiException;
|
use Modules\Core\Shipping\Carriers\Acs\Exceptions\AcsApiException;
|
||||||
use Modules\Core\Shipping\Concerns\ResolvesFixedPricing;
|
|
||||||
use Modules\Core\Shipping\Contracts\SupportsLivePricing;
|
use Modules\Core\Shipping\Contracts\SupportsLivePricing;
|
||||||
|
|
||||||
class AcsRateDriver implements ShippingRateInterface, SupportsLivePricing
|
class AcsRateDriver implements ShippingRateInterface, SupportsLivePricing
|
||||||
{
|
{
|
||||||
use ResolvesFixedPricing;
|
|
||||||
|
|
||||||
public ShippingRate $shippingRate;
|
public ShippingRate $shippingRate;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
@@ -38,19 +36,39 @@ class AcsRateDriver implements ShippingRateInterface, SupportsLivePricing
|
|||||||
$shippingMethod = $shippingRate->shippingMethod;
|
$shippingMethod = $shippingRate->shippingMethod;
|
||||||
$cart = $shippingOptionRequest->cart;
|
$cart = $shippingOptionRequest->cart;
|
||||||
|
|
||||||
if (($shippingMethod->data['charge_by'] ?? 'cart_total') !== 'live') {
|
|
||||||
return $this->resolveFixedPrice($shippingRate, $shippingMethod, $cart);
|
|
||||||
}
|
|
||||||
|
|
||||||
$postcode = $cart->shippingAddress?->postcode;
|
$postcode = $cart->shippingAddress?->postcode;
|
||||||
|
|
||||||
if (! $postcode) {
|
if (! $postcode) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (($shippingRate->pricing_mode ?? 'live') === 'fixed') {
|
||||||
|
return $this->resolveFixedPrice($shippingRate, $shippingMethod, $cart);
|
||||||
|
}
|
||||||
|
|
||||||
return $this->resolveLivePrice($shippingRate, $shippingMethod, $cart, $postcode);
|
return $this->resolveLivePrice($shippingRate, $shippingMethod, $cart, $postcode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function resolveFixedPrice(ShippingRate $shippingRate, $shippingMethod, $cart): ?ShippingOption
|
||||||
|
{
|
||||||
|
$subTotal = $cart->lines->sum('subTotal.value');
|
||||||
|
|
||||||
|
$pricing = Pricing::for($shippingRate)->qty($subTotal)->get();
|
||||||
|
|
||||||
|
if (! $pricing->matched) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ShippingOption(
|
||||||
|
name: $shippingMethod->name ?: $this->name(),
|
||||||
|
description: $shippingMethod->description ?: $this->description(),
|
||||||
|
identifier: $shippingRate->getIdentifier(),
|
||||||
|
price: $pricing->matched->price,
|
||||||
|
taxClass: $shippingRate->getTaxClass(),
|
||||||
|
taxReference: $shippingRate->getTaxReference(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
private function resolveLivePrice(ShippingRate $shippingRate, $shippingMethod, $cart, string $postcode): ?ShippingOption
|
private function resolveLivePrice(ShippingRate $shippingRate, $shippingMethod, $cart, string $postcode): ?ShippingOption
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -3,21 +3,19 @@
|
|||||||
namespace Modules\Core\Shipping\Carriers\BoxNow;
|
namespace Modules\Core\Shipping\Carriers\BoxNow;
|
||||||
|
|
||||||
use Lunar\DataTypes\ShippingOption;
|
use Lunar\DataTypes\ShippingOption;
|
||||||
|
use Lunar\Facades\Pricing;
|
||||||
use Lunar\Shipping\DataTransferObjects\ShippingOptionRequest;
|
use Lunar\Shipping\DataTransferObjects\ShippingOptionRequest;
|
||||||
use Lunar\Shipping\Interfaces\ShippingRateInterface;
|
use Lunar\Shipping\Interfaces\ShippingRateInterface;
|
||||||
use Lunar\Shipping\Models\ShippingRate;
|
use Lunar\Shipping\Models\ShippingRate;
|
||||||
use Modules\Core\Shipping\Concerns\ResolvesFixedPricing;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Box Now has no pricing API, so this always resolves the method's normal
|
* Box Now has no pricing API, so this always resolves the admin-configured
|
||||||
* charge_by + price-break configuration — the same mechanism the built-in
|
* price/price-breaks on the ShippingRate — the same mechanism the built-in
|
||||||
* flat-rate/ship-by drivers use. Does not implement SupportsLivePricing:
|
* flat-rate driver uses. Unlike AcsRateDriver, this does not implement
|
||||||
* there is no live option to offer.
|
* SupportsLivePricing: there is nothing to toggle between.
|
||||||
*/
|
*/
|
||||||
class BoxNowRateDriver implements ShippingRateInterface
|
class BoxNowRateDriver implements ShippingRateInterface
|
||||||
{
|
{
|
||||||
use ResolvesFixedPricing;
|
|
||||||
|
|
||||||
public ShippingRate $shippingRate;
|
public ShippingRate $shippingRate;
|
||||||
|
|
||||||
public function name(): string
|
public function name(): string
|
||||||
@@ -32,10 +30,25 @@ class BoxNowRateDriver implements ShippingRateInterface
|
|||||||
|
|
||||||
public function resolve(ShippingOptionRequest $shippingOptionRequest): ?ShippingOption
|
public function resolve(ShippingOptionRequest $shippingOptionRequest): ?ShippingOption
|
||||||
{
|
{
|
||||||
return $this->resolveFixedPrice(
|
$shippingRate = $shippingOptionRequest->shippingRate;
|
||||||
$shippingOptionRequest->shippingRate,
|
$shippingMethod = $shippingRate->shippingMethod;
|
||||||
$shippingOptionRequest->shippingRate->shippingMethod,
|
$cart = $shippingOptionRequest->cart;
|
||||||
$shippingOptionRequest->cart,
|
|
||||||
|
$subTotal = $cart->lines->sum('subTotal.value');
|
||||||
|
|
||||||
|
$pricing = Pricing::for($shippingRate)->qty($subTotal)->get();
|
||||||
|
|
||||||
|
if (! $pricing->matched) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ShippingOption(
|
||||||
|
name: $shippingMethod->name ?: $this->name(),
|
||||||
|
description: $shippingMethod->description ?: $this->description(),
|
||||||
|
identifier: $shippingRate->getIdentifier(),
|
||||||
|
price: $pricing->matched->price,
|
||||||
|
taxClass: $shippingRate->getTaxClass(),
|
||||||
|
taxReference: $shippingRate->getTaxReference(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,42 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace Modules\Core\Shipping\Concerns;
|
|
||||||
|
|
||||||
use Lunar\DataTypes\ShippingOption;
|
|
||||||
use Lunar\Facades\Pricing;
|
|
||||||
use Lunar\Shipping\Models\ShippingMethod;
|
|
||||||
use Lunar\Shipping\Models\ShippingRate;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shared by any carrier driver that also supports Lunar's own price-break
|
|
||||||
* pricing (charge_by = cart_total | weight) as a fallback to, or standalone
|
|
||||||
* alternative for, live API pricing. Mirrors the vendor ShipBy driver's
|
|
||||||
* charge_by handling exactly, so behavior is consistent with the rest of
|
|
||||||
* Lunar's shipping system rather than inventing a separate mechanism.
|
|
||||||
*/
|
|
||||||
trait ResolvesFixedPricing
|
|
||||||
{
|
|
||||||
private function resolveFixedPrice(ShippingRate $shippingRate, ShippingMethod $shippingMethod, $cart): ?ShippingOption
|
|
||||||
{
|
|
||||||
$chargeBy = $shippingMethod->data['charge_by'] ?? 'cart_total';
|
|
||||||
|
|
||||||
$tier = $chargeBy === 'weight'
|
|
||||||
? $cart->lines->load('purchasable')->sum(fn ($line) => ($line->purchasable->weight_value ?? 0) * $line->quantity)
|
|
||||||
: $cart->lines->sum('subTotal.value');
|
|
||||||
|
|
||||||
$pricing = Pricing::for($shippingRate)->qty($tier)->get();
|
|
||||||
|
|
||||||
if (! $pricing->matched) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ShippingOption(
|
|
||||||
name: $shippingMethod->name ?: $this->name(),
|
|
||||||
description: $shippingMethod->description ?: $this->description(),
|
|
||||||
identifier: $shippingRate->getIdentifier(),
|
|
||||||
price: $pricing->matched->price,
|
|
||||||
taxClass: $shippingRate->getTaxClass(),
|
|
||||||
taxReference: $shippingRate->getTaxReference(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -6,88 +6,20 @@ use Filament\Forms\Components\Component;
|
|||||||
use Filament\Forms\Components\Concerns\HasChildComponents;
|
use Filament\Forms\Components\Concerns\HasChildComponents;
|
||||||
use Filament\Forms\Components\Select;
|
use Filament\Forms\Components\Select;
|
||||||
use Filament\Forms\Form;
|
use Filament\Forms\Form;
|
||||||
use Filament\Forms\Get;
|
|
||||||
use Filament\Tables\Columns\TextColumn;
|
use Filament\Tables\Columns\TextColumn;
|
||||||
use Filament\Tables\Table;
|
use Filament\Tables\Table;
|
||||||
use Lunar\Admin\Support\Extending\ResourceExtension;
|
use Lunar\Admin\Support\Extending\ResourceExtension;
|
||||||
use Lunar\Shipping\Facades\Shipping;
|
use Lunar\Shipping\Facades\Shipping;
|
||||||
use Modules\Core\Shipping\Contracts\SupportsLivePricing;
|
|
||||||
|
|
||||||
class ShippingMethodResourceExtension extends ResourceExtension
|
class ShippingMethodResourceExtension extends ResourceExtension
|
||||||
{
|
{
|
||||||
public function extendForm(Form $form): Form
|
public function extendForm(Form $form): Form
|
||||||
{
|
{
|
||||||
return $form->schema(
|
return $form->schema(
|
||||||
$this->replaceChargeByField(
|
$this->replaceDriverField($form->getComponents())
|
||||||
$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
|
public function extendTable(Table $table): Table
|
||||||
{
|
{
|
||||||
return $table->columns(
|
return $table->columns(
|
||||||
@@ -146,7 +78,6 @@ class ShippingMethodResourceExtension extends ResourceExtension
|
|||||||
->label('Type')
|
->label('Type')
|
||||||
->options(fn () => collect(Shipping::getSupportedDrivers())
|
->options(fn () => collect(Shipping::getSupportedDrivers())
|
||||||
->mapWithKeys(fn ($driver, $key) => [$key => $driver->name()]))
|
->mapWithKeys(fn ($driver, $key) => [$key => $driver->name()]))
|
||||||
->default('flat-rate')
|
->default('flat-rate');
|
||||||
->live();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,13 +2,16 @@
|
|||||||
|
|
||||||
namespace Modules\Core\Shipping\Filament\Pages;
|
namespace Modules\Core\Shipping\Filament\Pages;
|
||||||
|
|
||||||
|
use Filament\Forms\Components\Select;
|
||||||
use Filament\Forms\Form;
|
use Filament\Forms\Form;
|
||||||
use Filament\Forms\Get;
|
use Filament\Forms\Get;
|
||||||
use Filament\Tables\Columns\TextColumn;
|
use Filament\Tables\Columns\TextColumn;
|
||||||
use Filament\Tables\Table;
|
use Filament\Tables\Table;
|
||||||
use Lunar\Shipping\Filament\Resources\ShippingZoneResource\Pages\ManageShippingRates as BaseManageShippingRates;
|
use Lunar\Shipping\Facades\Shipping;
|
||||||
use Lunar\Shipping\Models\ShippingMethod;
|
use Lunar\Shipping\Models\ShippingMethod;
|
||||||
use Lunar\Shipping\Models\ShippingRate;
|
use Lunar\Shipping\Models\ShippingRate;
|
||||||
|
use Lunar\Shipping\Filament\Resources\ShippingZoneResource\Pages\ManageShippingRates as BaseManageShippingRates;
|
||||||
|
use Modules\Core\Shipping\Contracts\SupportsLivePricing;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bound in place of the vendor ManageShippingRates page via the container
|
* Bound in place of the vendor ManageShippingRates page via the container
|
||||||
@@ -17,13 +20,11 @@ use Lunar\Shipping\Models\ShippingRate;
|
|||||||
* ShippingZoneResource::getPages() — is untouched; the container simply
|
* ShippingZoneResource::getPages() — is untouched; the container simply
|
||||||
* hands back this subclass whenever the vendor class is resolved.
|
* hands back this subclass whenever the vendor class is resolved.
|
||||||
*
|
*
|
||||||
* Hides the price / price-break fields for a rate whose method has
|
* Adds a per-rate "Pricing" toggle (live API vs. fixed price) for methods
|
||||||
* charge_by = "live" (see ShippingMethodResourceExtension, which adds that
|
* whose driver supports live pricing (see SupportsLivePricing). Rates on
|
||||||
* option to methods whose driver supports live pricing) — those fields
|
* methods without live pricing behave exactly as the vendor page always did
|
||||||
* would otherwise be dead configuration the driver never reads. Pricing
|
* — no toggle shown, price fields always required, vendor save logic used
|
||||||
* strategy (cart_total / weight / live) stays entirely on the Shipping
|
* as-is.
|
||||||
* Method, matching Lunar's own existing charge_by convention; nothing new
|
|
||||||
* is stored on the rate itself.
|
|
||||||
*/
|
*/
|
||||||
class ManageShippingRates extends BaseManageShippingRates
|
class ManageShippingRates extends BaseManageShippingRates
|
||||||
{
|
{
|
||||||
@@ -32,13 +33,56 @@ class ManageShippingRates extends BaseManageShippingRates
|
|||||||
$form = parent::form($form);
|
$form = parent::form($form);
|
||||||
|
|
||||||
return $form->schema(
|
return $form->schema(
|
||||||
$this->hidePriceFieldsWhenLive($form->getComponents())
|
$this->insertPricingModeFieldAfterShippingMethod(
|
||||||
|
$this->hidePriceFieldsWhenLive($form->getComponents())
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insert the "Pricing" field immediately after "shipping_method_id" so
|
||||||
|
* it reads as a pair, rather than appending it elsewhere in the form.
|
||||||
|
*/
|
||||||
|
private function insertPricingModeFieldAfterShippingMethod(array $components): array
|
||||||
|
{
|
||||||
|
$result = [];
|
||||||
|
|
||||||
|
foreach ($components as $component) {
|
||||||
|
$result[] = $component;
|
||||||
|
|
||||||
|
if (method_exists($component, 'getName') && $component->getName() === 'shipping_method_id') {
|
||||||
|
$result[] = $this->pricingModeField();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function pricingModeField(): Select
|
||||||
|
{
|
||||||
|
return Select::make('pricing_mode')
|
||||||
|
->label('Pricing')
|
||||||
|
->options([
|
||||||
|
'live' => 'Use live API pricing',
|
||||||
|
'fixed' => 'Use a fixed price',
|
||||||
|
])
|
||||||
|
->default('live')
|
||||||
|
->live()
|
||||||
|
->visible(fn (Get $get) => static::methodHasLivePricing($get('shipping_method_id')))
|
||||||
|
->columnSpan(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hide the vendor's price / price-break fields whenever this rate is
|
||||||
|
* set to live pricing — they'd otherwise be dead configuration,
|
||||||
|
* silently ignored by the driver. Only the base "price" field was ever
|
||||||
|
* required by the vendor form; the "prices" repeater (price breaks) is
|
||||||
|
* always optional, so its required() state is left untouched.
|
||||||
|
*/
|
||||||
private function hidePriceFieldsWhenLive(array $components): array
|
private function hidePriceFieldsWhenLive(array $components): array
|
||||||
{
|
{
|
||||||
$isNotLive = fn (Get $get) => static::methodChargeBy($get('shipping_method_id')) !== 'live';
|
$isFixedOrNotLiveCapable = fn (Get $get) => ! static::methodHasLivePricing($get('shipping_method_id'))
|
||||||
|
|| $get('pricing_mode') === 'fixed';
|
||||||
|
|
||||||
foreach ($components as $component) {
|
foreach ($components as $component) {
|
||||||
if (! method_exists($component, 'getName')) {
|
if (! method_exists($component, 'getName')) {
|
||||||
@@ -46,11 +90,14 @@ class ManageShippingRates extends BaseManageShippingRates
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($component->getName() === 'price') {
|
if ($component->getName() === 'price') {
|
||||||
$component->visible($isNotLive)->required($isNotLive)->dehydrated(true);
|
$component->visible($isFixedOrNotLiveCapable)
|
||||||
|
->required($isFixedOrNotLiveCapable)
|
||||||
|
->dehydrated(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($component->getName() === 'prices') {
|
if ($component->getName() === 'prices') {
|
||||||
$component->visible($isNotLive)->dehydrated(true);
|
$component->visible($isFixedOrNotLiveCapable)
|
||||||
|
->dehydrated(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,7 +114,7 @@ class ManageShippingRates extends BaseManageShippingRates
|
|||||||
return TextColumn::make('basePrices.0')
|
return TextColumn::make('basePrices.0')
|
||||||
->label(__('lunarpanel.shipping::relationmanagers.shipping_rates.table.price.label'))
|
->label(__('lunarpanel.shipping::relationmanagers.shipping_rates.table.price.label'))
|
||||||
->formatStateUsing(function ($state, ShippingRate $record) {
|
->formatStateUsing(function ($state, ShippingRate $record) {
|
||||||
if (static::methodChargeBy($record->shipping_method_id) === 'live') {
|
if (static::methodHasLivePricing($record->shipping_method_id) && $record->pricing_mode === 'live') {
|
||||||
return 'Live API pricing';
|
return 'Live API pricing';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,23 +129,37 @@ class ManageShippingRates extends BaseManageShippingRates
|
|||||||
|
|
||||||
protected static function saveShippingRate(?ShippingRate $shippingRate = null, array $data = []): void
|
protected static function saveShippingRate(?ShippingRate $shippingRate = null, array $data = []): void
|
||||||
{
|
{
|
||||||
if (static::methodChargeBy($data['shipping_method_id'] ?? $shippingRate?->shipping_method_id) === 'live') {
|
$isLive = static::methodHasLivePricing($data['shipping_method_id'] ?? $shippingRate?->shipping_method_id)
|
||||||
|
&& ($data['pricing_mode'] ?? 'live') === 'live';
|
||||||
|
|
||||||
|
$shippingRate->pricing_mode = $isLive ? 'live' : 'fixed';
|
||||||
|
$shippingRate->save();
|
||||||
|
|
||||||
|
if ($isLive) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
parent::saveShippingRate($shippingRate, $data);
|
parent::saveShippingRate($shippingRate, $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static function methodChargeBy(ShippingMethod|int|string|null $method): ?string
|
protected static function methodHasLivePricing(ShippingMethod|int|string|null $method): bool
|
||||||
{
|
{
|
||||||
if (blank($method)) {
|
if (blank($method)) {
|
||||||
return null;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! $method instanceof ShippingMethod) {
|
if (! $method instanceof ShippingMethod) {
|
||||||
$method = ShippingMethod::find($method);
|
$method = ShippingMethod::find($method);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $method?->data['charge_by'] ?? null;
|
if (! $method) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return Shipping::driver($method->driver) instanceof SupportsLivePricing;
|
||||||
|
} catch (\InvalidArgumentException) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user