Feat: Updating Shipping Method with new variables, for correct box env vars
This commit is contained in:
@@ -13,12 +13,25 @@
|
|||||||
|
|
|
|
||||||
| Set these via environment variables — never commit real values.
|
| Set these via environment variables — never commit real values.
|
||||||
|
|
|
|
||||||
|
| Box Now has two environments (see their Partner API manual, section 2):
|
||||||
|
| Stage/Sandbox for testing, Production once live. Each has its own
|
||||||
|
| client_id/client_secret pair and its own base_url/location_api_url —
|
||||||
|
| there is no shared "switch an env var" flag, since stage credentials
|
||||||
|
| don't work against the production host or vice versa.
|
||||||
|
|
|
||||||
| BOXNOW_BASE_URL Root REST endpoint for delivery-requests/parcels.
|
| BOXNOW_BASE_URL Root REST endpoint for delivery-requests/parcels.
|
||||||
| BOXNOW_LOCATION_API_URL Separate, faster endpoint for origins/destinations
|
| BOXNOW_LOCATION_API_URL Separate, faster endpoint for origins/destinations
|
||||||
| lookups (Box Now recommends this over the main
|
| lookups (Box Now recommends this over the main
|
||||||
| base URL for those two calls specifically).
|
| base URL for those two calls specifically).
|
||||||
| BOXNOW_CLIENT_ID OAuth2 client id.
|
| BOXNOW_CLIENT_ID OAuth2 client id.
|
||||||
| BOXNOW_CLIENT_SECRET OAuth2 client secret.
|
| BOXNOW_CLIENT_SECRET OAuth2 client secret.
|
||||||
|
| BOXNOW_PARTNER_ID Numeric partnerId Box Now issues alongside your
|
||||||
|
| credentials. NOT used for REST API authentication
|
||||||
|
| (BoxNowClient authenticates with client_id/
|
||||||
|
| client_secret alone) — this is only consumed by
|
||||||
|
| the client-side Destination Map widget config
|
||||||
|
| (_bn_map_widget_config.partnerId), confirmed
|
||||||
|
| against Box Now's own WooCommerce plugin source.
|
||||||
| BOXNOW_ORIGIN_LOCATION_ID Your warehouse's Box Now locationId, used as
|
| BOXNOW_ORIGIN_LOCATION_ID Your warehouse's Box Now locationId, used as
|
||||||
| the pickup origin on every delivery request.
|
| the pickup origin on every delivery request.
|
||||||
| BOXNOW_SENDER_* Static sender contact details reused on every
|
| BOXNOW_SENDER_* Static sender contact details reused on every
|
||||||
@@ -33,6 +46,7 @@ return [
|
|||||||
|
|
||||||
'client_id' => env('BOXNOW_CLIENT_ID'),
|
'client_id' => env('BOXNOW_CLIENT_ID'),
|
||||||
'client_secret' => env('BOXNOW_CLIENT_SECRET'),
|
'client_secret' => env('BOXNOW_CLIENT_SECRET'),
|
||||||
|
'partner_id' => env('BOXNOW_PARTNER_ID'),
|
||||||
|
|
||||||
'origin_location_id' => env('BOXNOW_ORIGIN_LOCATION_ID'),
|
'origin_location_id' => env('BOXNOW_ORIGIN_LOCATION_ID'),
|
||||||
|
|
||||||
|
|||||||
@@ -12,11 +12,15 @@ use Lunar\Shipping\Filament\Resources\ShippingMethodResource;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* ListShippingMethod::getDefaultHeaderActions() builds its CreateAction's
|
* ListShippingMethod::getDefaultHeaderActions() builds its CreateAction's
|
||||||
* form inline (calling ShippingMethodResource::getDriverFormComponent()
|
* form inline (calling ShippingMethodResource::getDriverFormComponent()/
|
||||||
* directly, a hardcoded 2-option Select) rather than through the resource's
|
* getNameFormComponent() directly, hardcoded vendor components) rather
|
||||||
* own extendForm() pipeline, so ShippingMethodResourceExtension's driver
|
* than through the resource's own extendForm() pipeline, so neither
|
||||||
* fix never reaches it. Re-declares the same create-action form with a
|
* ShippingMethodResourceExtension's driver Select nor its translated
|
||||||
* dynamic driver Select instead.
|
* `name` field ever reached this action — `name`'s plain-string TextInput
|
||||||
|
* in particular used to insert a raw string into the now-JSON `name`
|
||||||
|
* column, crashing with a Postgres "invalid input syntax for type json"
|
||||||
|
* error on every create. Re-declares the same create-action form with
|
||||||
|
* both fixes reapplied instead.
|
||||||
*/
|
*/
|
||||||
class ShippingMethodListExtension extends BaseExtension
|
class ShippingMethodListExtension extends BaseExtension
|
||||||
{
|
{
|
||||||
@@ -25,7 +29,7 @@ class ShippingMethodListExtension extends BaseExtension
|
|||||||
foreach ($actions as $action) {
|
foreach ($actions as $action) {
|
||||||
if ($action instanceof CreateAction) {
|
if ($action instanceof CreateAction) {
|
||||||
$action->schema([
|
$action->schema([
|
||||||
ShippingMethodResource::getNameFormComponent(),
|
ShippingMethodResourceExtension::translatedNameField(),
|
||||||
Group::make([
|
Group::make([
|
||||||
ShippingMethodResource::getCodeFormComponent(),
|
ShippingMethodResource::getCodeFormComponent(),
|
||||||
$this->driverSelect(),
|
$this->driverSelect(),
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ class ShippingMethodResourceExtension extends ResourceExtension
|
|||||||
{
|
{
|
||||||
return array_map(function (Component $component) {
|
return array_map(function (Component $component) {
|
||||||
if (method_exists($component, 'getName') && $component->getName() === 'name') {
|
if (method_exists($component, 'getName') && $component->getName() === 'name') {
|
||||||
return $this->translatedNameField();
|
return self::translatedNameField();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (in_array(HasChildComponents::class, class_uses_recursive($component), true)) {
|
if (in_array(HasChildComponents::class, class_uses_recursive($component), true)) {
|
||||||
@@ -68,14 +68,28 @@ class ShippingMethodResourceExtension extends ResourceExtension
|
|||||||
* the model attribute is a string on the way in and out, only ever
|
* the model attribute is a string on the way in and out, only ever
|
||||||
* an array while Filament's schema state holds it.
|
* an array while Filament's schema state holds it.
|
||||||
*/
|
*/
|
||||||
private function translatedNameField(): TranslatedText
|
/**
|
||||||
|
* Also called directly by Modules\Core\Shipping\Extensions\
|
||||||
|
* ShippingMethodListExtension — the create action's form is built
|
||||||
|
* inline by the vendor's ListShippingMethod page rather than through
|
||||||
|
* this class's own extendForm() pipeline, so it needs the same
|
||||||
|
* translated field wired in separately.
|
||||||
|
*/
|
||||||
|
public static function translatedNameField(): TranslatedText
|
||||||
{
|
{
|
||||||
$field = TranslatedText::make('name')
|
$field = TranslatedText::make('name')
|
||||||
->label('Name')
|
->label('Name')
|
||||||
->required()
|
->required()
|
||||||
->afterStateHydrated(function (TranslatedText $component, $state) {
|
->afterStateHydrated(function (TranslatedText $component, $state) {
|
||||||
$decoded = json_decode((string) $state, true);
|
// On create there is no record yet, so Filament hydrates
|
||||||
$component->state(is_array($decoded) ? $decoded : []);
|
// this from the field's own default/current state — already
|
||||||
|
// an array (or null), never the raw JSON string edit gets
|
||||||
|
// from the model attribute. Only decode when it's a string.
|
||||||
|
if (is_string($state)) {
|
||||||
|
$state = json_decode($state, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
$component->state(is_array($state) ? $state : []);
|
||||||
})
|
})
|
||||||
->dehydrateStateUsing(fn ($state) => json_encode(is_array($state) ? $state : []));
|
->dehydrateStateUsing(fn ($state) => json_encode(is_array($state) ? $state : []));
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ namespace Modules\Core\Shipping\Filament\Pages;
|
|||||||
|
|
||||||
use Filament\Schemas\Schema;
|
use Filament\Schemas\Schema;
|
||||||
use Filament\Schemas\Components\Utilities\Get;
|
use Filament\Schemas\Components\Utilities\Get;
|
||||||
|
use Filament\Forms\Components\Select;
|
||||||
use Filament\Forms\Components\TextInput;
|
use Filament\Forms\Components\TextInput;
|
||||||
use Filament\Tables\Columns\TextColumn;
|
use Filament\Tables\Columns\TextColumn;
|
||||||
use Filament\Tables\Table;
|
use Filament\Tables\Table;
|
||||||
@@ -11,6 +12,7 @@ use Illuminate\Database\Eloquent\Model;
|
|||||||
use Lunar\Shipping\Filament\Resources\ShippingZoneResource\Pages\ManageShippingRates as BaseManageShippingRates;
|
use Lunar\Shipping\Filament\Resources\ShippingZoneResource\Pages\ManageShippingRates as BaseManageShippingRates;
|
||||||
use Lunar\Shipping\Models\ShippingMethod;
|
use Lunar\Shipping\Models\ShippingMethod;
|
||||||
use Lunar\Shipping\Models\ShippingRate;
|
use Lunar\Shipping\Models\ShippingRate;
|
||||||
|
use Modules\Core\Shipping\Support\ShippingMethodName;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bound in place of the vendor ManageShippingRates page via the container
|
* Bound in place of the vendor ManageShippingRates page via the container
|
||||||
@@ -33,6 +35,16 @@ use Lunar\Shipping\Models\ShippingRate;
|
|||||||
* null-guard, which crashes on any rate with no basePrices row — routine
|
* 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
|
* for a live rate that has never had a fallback price configured. Same
|
||||||
* logic, just null-safe.
|
* logic, just null-safe.
|
||||||
|
*
|
||||||
|
* Also replaces the vendor's `shipping_method_id` Select, which uses
|
||||||
|
* ->relationship(titleAttribute: 'name') — Filament builds that option
|
||||||
|
* list with `orderBy('name')`/`pluck('name', ...)` against the DB, but
|
||||||
|
* ShippingMethod.name is now a locale-keyed JSON column (see database/
|
||||||
|
* migrations/..._make_shipping_methods_name_translatable.php) that
|
||||||
|
* Postgres has no default ordering operator for, crashing with
|
||||||
|
* "could not identify an ordering operator for type json" the moment
|
||||||
|
* this page loads. Resolved app-side instead via ShippingMethodName,
|
||||||
|
* same as every other read site for this column.
|
||||||
*/
|
*/
|
||||||
class ManageShippingRates extends BaseManageShippingRates
|
class ManageShippingRates extends BaseManageShippingRates
|
||||||
{
|
{
|
||||||
@@ -41,10 +53,30 @@ class ManageShippingRates extends BaseManageShippingRates
|
|||||||
$schema = parent::form($schema);
|
$schema = parent::form($schema);
|
||||||
|
|
||||||
return $schema->components(
|
return $schema->components(
|
||||||
$this->labelPriceFieldsAsFallbackWhenLive($schema->getComponents())
|
$this->labelPriceFieldsAsFallbackWhenLive(
|
||||||
|
$this->replaceShippingMethodField($schema->getComponents())
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function replaceShippingMethodField(array $components): array
|
||||||
|
{
|
||||||
|
return array_map(function ($component) {
|
||||||
|
if (method_exists($component, 'getName') && $component->getName() === 'shipping_method_id') {
|
||||||
|
return Select::make('shipping_method_id')
|
||||||
|
->label($component->getLabel())
|
||||||
|
->required()
|
||||||
|
->live()
|
||||||
|
->options(fn () => ShippingMethod::all()
|
||||||
|
->mapWithKeys(fn (ShippingMethod $method) => [$method->id => ShippingMethodName::resolve($method)]))
|
||||||
|
->searchable()
|
||||||
|
->columnSpan(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $component;
|
||||||
|
}, $components);
|
||||||
|
}
|
||||||
|
|
||||||
private function labelPriceFieldsAsFallbackWhenLive(array $components): array
|
private function labelPriceFieldsAsFallbackWhenLive(array $components): array
|
||||||
{
|
{
|
||||||
$isLive = fn (Get $get) => static::methodChargeBy($get('shipping_method_id')) === 'live';
|
$isLive = fn (Get $get) => static::methodChargeBy($get('shipping_method_id')) === 'live';
|
||||||
@@ -86,6 +118,14 @@ class ManageShippingRates extends BaseManageShippingRates
|
|||||||
|
|
||||||
return $table->columns(
|
return $table->columns(
|
||||||
array_map(function ($column) {
|
array_map(function ($column) {
|
||||||
|
if (method_exists($column, 'getName') && $column->getName() === 'shippingMethod.name') {
|
||||||
|
return TextColumn::make('shippingMethod.name')
|
||||||
|
->label(__('lunarpanel.shipping::relationmanagers.shipping_rates.table.shipping_method.label'))
|
||||||
|
->state(fn (ShippingRate $record) => $record->shippingMethod
|
||||||
|
? ShippingMethodName::resolve($record->shippingMethod)
|
||||||
|
: null);
|
||||||
|
}
|
||||||
|
|
||||||
if (method_exists($column, 'getName') && $column->getName() === 'basePrices.0') {
|
if (method_exists($column, 'getName') && $column->getName() === 'basePrices.0') {
|
||||||
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'))
|
||||||
|
|||||||
Reference in New Issue
Block a user