Docs/Backend Development
Module Development

Backend Development

Building Laravel backend code for AutoCom modules.

Service Provider

The service provider is the entry point for your module's backend:

<?php

namespace Modules\ShippingDelhivery;

use Illuminate\Support\ServiceProvider;
use Modules\Core\Contracts\ShippingProviderContract;
use Modules\ShippingDelhivery\App\Services\DelhiveryService;

class ShippingDelhiveryServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        // Register config
        $this->mergeConfigFrom(__DIR__.'/Config/config.php', 'delhivery');

        // Bind service to contract
        $this->app->bind(ShippingProviderContract::class, DelhiveryService::class);
    }

    public function boot(): void
    {
        // Load routes
        $this->loadRoutesFrom(__DIR__.'/routes/api.php');

        // Load migrations
        $this->loadMigrationsFrom(__DIR__.'/Database/Migrations');

        // Publish config (optional)
        $this->publishes([
            __DIR__.'/Config/config.php' => config_path('delhivery.php'),
        ], 'delhivery-config');
    }
}

Defining Routes

# modules/ShippingDelhivery/backend/routes/api.php

<?php

use Illuminate\Support\Facades\Route;
use Modules\ShippingDelhivery\App\Http\Controllers\DelhiveryController;
use Modules\ShippingDelhivery\App\Http\Controllers\DelhiveryWebhookController;

Route::middleware(['api', 'auth:api'])
    ->prefix('api/v1/shipping/delhivery')
    ->group(function () {
        Route::post('/shipments', [DelhiveryController::class, 'createShipment']);
        Route::get('/shipments/{awb}/track', [DelhiveryController::class, 'track']);
        Route::get('/shipments/{awb}/label', [DelhiveryController::class, 'downloadLabel']);
        Route::post('/shipments/{awb}/cancel', [DelhiveryController::class, 'cancel']);
    });

// Webhook endpoint (no auth required)
Route::prefix('api/webhooks')
    ->group(function () {
        Route::post('/delhivery', [DelhiveryWebhookController::class, 'handle']);
    });

Controllers

<?php

namespace Modules\ShippingDelhivery\App\Http\Controllers;

use App\Http\Controllers\Controller;
use Illuminate\Http\JsonResponse;
use Modules\ShippingDelhivery\App\Http\Requests\CreateShipmentRequest;
use Modules\ShippingDelhivery\App\Services\DelhiveryService;

class DelhiveryController extends Controller
{
    public function __construct(
        private DelhiveryService $delhivery
    ) {}

    public function createShipment(CreateShipmentRequest $request): JsonResponse
    {
        $shipment = $this->delhivery->createShipment(
            $request->validated()
        );

        return response()->json([
            'data' => $shipment,
            'message' => 'Shipment created successfully',
        ], 201);
    }

    public function track(string $awb): JsonResponse
    {
        $tracking = $this->delhivery->trackShipment($awb);

        return response()->json(['data' => $tracking]);
    }
}

Form Requests

<?php

namespace Modules\ShippingDelhivery\App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class CreateShipmentRequest extends FormRequest
{
    public function authorize(): bool
    {
        return true; // Auth handled by middleware
    }

    public function rules(): array
    {
        return [
            'order_id' => ['required', 'uuid', 'exists:orders,id'],
            'weight_kg' => ['required', 'numeric', 'min:0.1', 'max:50'],
            'dimensions' => ['nullable', 'array'],
            'dimensions.length' => ['nullable', 'numeric'],
            'dimensions.width' => ['nullable', 'numeric'],
            'dimensions.height' => ['nullable', 'numeric'],
            'pickup_date' => ['nullable', 'date', 'after:today'],
            'is_cod' => ['boolean'],
            'cod_amount' => ['required_if:is_cod,true', 'numeric', 'min:0'],
        ];
    }
}

Working with Core Models

Use the Core module's Eloquent models in your services:

use Modules\Core\Models\Order;
use Modules\Core\Models\Product;
use Modules\Core\Models\Customer;

// Query orders
$orders = Order::where('status', 'ready_to_ship')
    ->whereNull('shipment_id')
    ->with(['customer', 'shippingAddress', 'items'])
    ->get();

// Access relationships
$order->customer->full_name;
$order->shippingAddress->city;
$order->items->sum('total');

// Update with metadata
$order->setMetadata('delhivery_awb', $awb);
$order->setMetadata('shipped_at', now());
$order->save();

Dispatching Events

use Modules\Core\Events\ShipmentCreated;
use Modules\Core\Events\ShipmentStatusChanged;

// When shipment is created
event(new ShipmentCreated($shipment));

// When status changes (from webhook)
event(new ShipmentStatusChanged(
    shipment: $shipment,
    oldStatus: 'in_transit',
    newStatus: 'delivered'
));

Background Jobs

<?php

namespace Modules\ShippingDelhivery\Jobs;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Modules\ShippingDelhivery\App\Services\DelhiveryService;

class SyncTrackingStatus implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable;

    public function __construct(
        public string $awb
    ) {}

    public function handle(DelhiveryService $delhivery): void
    {
        $tracking = $delhivery->trackShipment($this->awb);

        // Update shipment status
        // Dispatch events if status changed
    }
}

// Dispatch the job
SyncTrackingStatus::dispatch($awb)->onQueue('tracking');