Gastos de envío
Módulo para el manejo de gastos de envío en bPanel 4.
Como añadir métodos de envío
Para añadir nuevas formas de envío al módulo, debe registrarse un nuevo paquete de composer que cumpla algunas condiciones:
Modelos
Interfaces
Por ahora, solo es necesario que el modelo del método de envío que vamos a definir
implemente la interfaz ShippingMethod.
Namespace
En el composer.json del plugin debe declararse lo siguiente dentro de autoload: psr-4,
aparte del namespace propio del plugin:
"Bittacora\\Bpanel4\\Shipping\\Models\\ShippingMethods\\": "src/Models"
Es imprescindible que el namespace en el que se registren los modelos sea el que se indica, ya que es donde se buscarán los métodos de envío. No importa que estén en paquetes diferentes mientras que se definan en ese namespace.
Luego en el modelo correspondiente a nuestro método de envío, forzaremos el namespace al que hemos indicado antes:
<?php
declare(strict_types=1);
namespace Bittacora\Bpanel4\Shipping\Models\ShippingMethods; // Forzamos el namespace
use ...
class MiModelo extends Model implements ShippingMethod
Habrá que limpiar la caché de Laravel para que encuentre las nuevas clases, ya que el proceso de búsqueda llevaba bastante tiempo y hubo que cachearlo.
Cálculo de precio en el carrito
Para dar más flexibilidad a la hora de calcular los gastos de envío en el carrito, se
llamará a una clase que implemente la interfaz ShippingMethodPriceCalculator, que será
definida por cada plugin.
Namespace
El namespace para estas clases debe ser Bittacora\Bpanel4\Shipping\Services\PriceCalculators, y
también habrá que declararlo en el composer.json de cada plugin, dentro de la sección
PSR-4 del apartado autoload:
"Bittacora\\Bpanel4\\Shipping\\Services\\PriceCalculators\\": "src/Services/PriceCalculators"
El nombre de la clase debe acabar con PriceCalculator. Por ejemplo, para el plugin de
envío gratuito, la clase sería
Bittacora\Bpanel4\Shipping\Services\PriceCalculators\FreeShipingPriceCalculator
Rutas
// Métodos de envío
Route::prefix('bpanel/envio')->name('bpanel4-shipping.nombre-del-plugin.bpanel.')->middleware(['web', 'auth', 'admin-menu'])
->group(static function () {
Route::get('/metodos-de-envio/NombreDelMetodoDeEnvio/{zone}/crear', [NombreDelMetodoDeEnvioAdminController::class, 'create'])->name('create');
Route::post('/metodos-de-envio/NombreDelMetodoDeEnvio/{zone}/crear', [NombreDelMetodoDeEnvioAdminController::class, 'store'])->name('store');
Route::get('/metodos-de-envio/NombreDelMetodoDeEnvio/{model}/editar', [NombreDelMetodoDeEnvioAdminController::class, 'edit'])->name('edit');
Route::post('/metodos-de-envio/NombreDelMetodoDeEnvio/{model}/editar', [NombreDelMetodoDeEnvioAdminController::class, 'update'])->name('update');
Route::get('/metodos-de-envio/NombreDelMetodoDeEnvio/{model}/eliminar', [NombreDelMetodoDeEnvioAdminController::class, 'destroy'])->name('destroy');
//...
});
nombre-del-plugin debe ser el nombre del plugin en kebab-case. El parámetro
de la ruta tendrá que ser {model} para todas las rutas excepto create, que
usará zone. {zone} es el id de la zona de envío a la que se debe asignar el
método de envío.
En el controlador del plugin en principio no habrá ninguna restricción, aparte
de que cuando inyectemos el modelo en el método edit (por ejemplo), la variable
tendrá que llamarse $model para que Laravel nos inyecte el modelo correctamente.
Eso si, el tipo de $model será el que corresponda al modelo de nuestro plugin,
por ejemplo, en el módulo de envío gratis, la función edit tiene como parámetro
FreeShipping $model.
public function edit(FreeShipping $model): View
Nota: Esto es así para que el datatable que lista los métodos de envío pueda construir las rutas de cualquier método de envío sin conocer de antemano cuales hay disponibles.
Service providers
En el service provider de cada plugin, habrá que registrar el método de envío para que esté disponible a la hora de construir listados con los métodos de envío disponibles.
Para hacerlo, en el método boot del service provider de cada plugin, llamaremos
a registerShippingMethod de ShippingFacade:
ShippingFacade::registerShippingMethod('Nombre del método de envío', ModeloDelPlugin::class);
El primer parámetro será el nombre de cara al usuario del método de envío, y el
segundo el nombre completo del modelo (por ejemplo \Bittacora\Bpanel4\Shipping\Models\ShippingMethods\FreeShipping)
Notas
La relación entre zona de envío y los distintos métodos de envío debería haber sido una relación polimórfica, pero cuando empecé a desarrollar estos paquetes, no me venía bien por la estructura que estaba siguiendo así que lo hice de la forma que se ve actualmente. Ahora se podría refactorizar para usar una relación polimórfica sin más, pero de momento no lo hago porque el código funciona y tiene tests. Más adelante nos podríamos plantear corregir esto si lo vemos necesario, pero de momento funciona bien como está y además no habría ninguna ventaja (solo que el código sería más "correcto").