Laravel 5 min de lecture

Construire un backoffice e-commerce Laravel Filament pour suivre stock et commandes

#laravel#filament#ecommerce

Créez un tableau de bord Filament simple pour piloter une boutique Laravel: commandes, chiffre d'affaires, alertes de stock et actions rapides.

Construire un backoffice e-commerce Laravel Filament pour suivre stock et commandes

Quand une boutique est administrée par une petite équipe, le backoffice doit aller droit au but: commandes à traiter, chiffre d'affaires, stock faible et accès rapides. Pas besoin d'un ERP lourd. Avec Laravel et Filament, on peut construire une interface claire, maintenable et adaptée au quotidien.

Ce tutoriel reprend une structure fréquente de boutique artisanale: produits, variantes, commandes, paiements et suivi de stock. L'objectif est de poser un dashboard utilisable dès le matin, sans ouvrir dix écrans.

Objectif

Nous allons créer:

  • des indicateurs de chiffre d'affaires et commandes;
  • une alerte de stock faible;
  • une table des dernières commandes;
  • une table des produits à surveiller;
  • quelques actions rapides pour l'équipe.

Le code reste volontairement générique. Il s'adapte à une boutique de bijoux, de produits personnalisés, de pièces détachées ou de produits numériques avec variantes.

Modèle minimal

On part de trois modèles:

// app/Models/Product.php
class Product extends Model
{
    public function variants(): HasMany
    {
        return $this->hasMany(ProductVariant::class);
    }
}
// app/Models/ProductVariant.php
class ProductVariant extends Model
{
    protected $casts = [
        'stock' => 'integer',
        'is_visible' => 'boolean',
    ];

    public function product(): BelongsTo
    {
        return $this->belongsTo(Product::class);
    }
}
// app/Models/Order.php
class Order extends Model
{
    protected $casts = [
        'total_cents' => 'integer',
        'paid_at' => 'datetime',
    ];

    public function isPaid(): bool
    {
        return $this->paid_at !== null;
    }
}

Pour un backoffice propre, évitez de recalculer toute la logique dans les vues. Ajoutez des scopes lisibles:

// app/Models/Order.php
public function scopePaid($query)
{
    return $query->whereNotNull('paid_at');
}

public function scopePending($query)
{
    return $query->whereIn('status', ['pending', 'paid']);
}
// app/Models/ProductVariant.php
public function scopeLowStock($query, int $threshold = 3)
{
    return $query->where('stock', '<=', $threshold);
}

Créer la page Filament

Filament permet de créer une page dédiée au tableau de bord:

php artisan make:filament-page ShopDashboard

Dans la page, préparez les données utiles:

// app/Filament/Pages/ShopDashboard.php
namespace App\Filament\Pages;

use App\Models\Order;
use App\Models\ProductVariant;
use Filament\Pages\Page;

class ShopDashboard extends Page
{
    protected static ?string $navigationIcon = 'heroicon-o-home';
    protected static string $view = 'filament.pages.shop-dashboard';
    protected static ?string $navigationLabel = 'Tableau de bord';

    public function getViewData(): array
    {
        $monthStart = now()->startOfMonth();

        return [
            'revenueCents' => Order::paid()
                ->where('paid_at', '>=', $monthStart)
                ->sum('total_cents'),
            'ordersToProcess' => Order::pending()->count(),
            'lowStockCount' => ProductVariant::lowStock()->count(),
            'latestOrders' => Order::latest()->limit(8)->get(),
            'lowStockVariants' => ProductVariant::query()
                ->with('product')
                ->lowStock()
                ->orderBy('stock')
                ->limit(10)
                ->get(),
        ];
    }
}

Afficher des indicateurs lisibles

Dans la vue Blade:

{{-- resources/views/filament/pages/shop-dashboard.blade.php --}}
<x-filament-panels::page>
    <div class="grid gap-4 md:grid-cols-3">
        <x-filament::section>
            <p class="text-sm text-gray-500">Chiffre d'affaires du mois</p>
            <p class="mt-2 text-3xl font-bold">
                {{ number_format($revenueCents / 100, 2, ',', ' ') }} €
            </p>
        </x-filament::section>

        <x-filament::section>
            <p class="text-sm text-gray-500">Commandes à traiter</p>
            <p class="mt-2 text-3xl font-bold">{{ $ordersToProcess }}</p>
        </x-filament::section>

        <x-filament::section>
            <p class="text-sm text-gray-500">Alertes stock</p>
            <p class="mt-2 text-3xl font-bold">{{ $lowStockCount }}</p>
        </x-filament::section>
    </div>
</x-filament-panels::page>

Un bon tableau de bord n'a pas besoin d'être bavard. Les libellés doivent être concrets: "Commandes à traiter" est plus utile que "Statut opérationnel".

Ajouter les dernières commandes

Ajoutez une section sous les indicateurs:

<x-filament::section class="mt-6">
    <x-slot name="heading">Dernières commandes</x-slot>

    <div class="divide-y">
        @foreach ($latestOrders as $order)
            <div class="flex items-center justify-between py-3">
                <div>
                    <p class="font-medium">{{ $order->reference }}</p>
                    <p class="text-sm text-gray-500">{{ $order->customer_name }}</p>
                </div>
                <div class="text-right">
                    <p>{{ number_format($order->total_cents / 100, 2, ',', ' ') }} €</p>
                    <p class="text-sm text-gray-500">{{ $order->status }}</p>
                </div>
            </div>
        @endforeach
    </div>
</x-filament::section>

Si les noms clients sont sensibles, affichez une référence interne ou masquez les données en environnement de démo. C'est une bonne habitude quand vous publiez des captures.

Surveiller les variantes faibles

Pour une boutique avec tailles, couleurs ou matériaux, le stock se joue souvent au niveau de la variante.

<x-filament::section class="mt-6">
    <x-slot name="heading">Stock à surveiller</x-slot>

    <div class="divide-y">
        @foreach ($lowStockVariants as $variant)
            <div class="flex items-center justify-between py-3">
                <div>
                    <p class="font-medium">{{ $variant->product->name }}</p>
                    <p class="text-sm text-gray-500">{{ $variant->name }}</p>
                </div>
                <span class="rounded-full bg-orange-100 px-2 py-1 text-sm text-orange-700">
                    {{ $variant->stock }} restant
                </span>
            </div>
        @endforeach
    </div>
</x-filament::section>

Cette table évite les ventes impossibles et aide l'équipe à remettre en stock avant que le problème arrive côté client.

Actions rapides

Un tableau de bord devient vraiment utile quand il réduit les clics:

use Filament\Actions\Action;

protected function getHeaderActions(): array
{
    return [
        Action::make('createProduct')
            ->label('Créer un produit')
            ->url(route('filament.admin.resources.products.create')),

        Action::make('orders')
            ->label('Voir les commandes')
            ->url(route('filament.admin.resources.orders.index')),
    ];
}

Gardez peu d'actions. Trois ou quatre suffisent: créer un produit, voir les commandes, gérer les catégories, ajouter un événement ou un point de vente.

Points de vigilance

Ne chargez pas des milliers de lignes dans le dashboard. Les indicateurs doivent être agrégés en SQL, les listes limitées, et les relations eager-loadées avec with().

Pour le chiffre d'affaires, basez-vous sur un statut fiable: commande payée, paiement capturé ou facture validée. Ne mélangez pas paniers abandonnés et commandes payées.

Enfin, testez le rendu avec des données réalistes: stock à zéro, commande annulée, paiement échoué, produit masqué, variante supprimée. Le backoffice sert précisément quand les cas ne sont pas parfaits.

Conclusion

Laravel et Filament permettent de construire un backoffice e-commerce très efficace sans sur-ingénierie. La clé n'est pas d'afficher toutes les données, mais les bonnes: ce qui demande une action aujourd'hui.

Pour une petite boutique, un tableau de bord clair peut faire gagner plus de temps qu'une fonctionnalité spectaculaire: moins d'oublis, moins d'erreurs, et une administration qui reste simple.