Shopping : la confirmation de la commande

Notre boutique a bien avancé. Les commandes peuvent être passées en choisissant l’adresse de facturation et d’expédition, le mode de livraison et de paiement. Nous allons à présent nous intéresser à la confirmation de la commande pour le client.

Vous pouvez télécharger un ZIP du projet ici.

Un contrôleur

On crée un contrôleur qui va gérer la confirmation et plus tard le paiement par carte :

php artisan make:controller OrdersController

On ajoute la route pour la confirmation :

// Utilisateur authentifié
Route::middleware('auth')->group(function () {
  // Commandes
  Route::prefix('commandes')->group(function () {
      ...
      Route::name('commandes.confirmation')->get('confirmation/{order}', 'OrdersController@confirmation');

A la fin de la méthode store du contrôleur OrderController on ajouter la redirection vers la route qu’on vient de créer :

return redirect(route('commandes.confirmation', $order->id));

Pour le moment on va coder ainsi le contrôleur OrdersController :

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\ { Order, Shop };

class OrdersController extends Controller
{
    /**
     * Show order confirmation.
     *
     * @param  integer $id
     * @return \Illuminate\Http\Response
     */
    public function confirmation(Request $request, $id)
    {
        $order = Order::with('products', 'adresses', 'state')->findOrFail($id);

        if(in_array($order->state->slug, ['cheque', 'mandat', 'virement', 'carte', 'erreur'])) {
            
            $data = $this->data($request, $order);

            return view('command.confirmation', $data);
        }
    }

    /**
     * Get order data
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \App\Models\Order  $order
     * @return array
     */
    protected function data($request, $order)
    {
        $shop = Shop::firstOrFail();
        $data = compact('order', 'shop');

        if($order->state->slug === 'carte' || $order->state->slug === 'erreur') {
            // Là on s'occupera de Stripe
        }  
        
        return $data;
    }
}

On ignore pour le moment la sécurité (la route ne doit être accessible que pour le client concerné par la commande référencée) et le paiement avec Stripe.

La vue de confirmation

On crée une vue pour la confirmation :

Avec ce code :

@extends('layouts.app')

@section('content')
<div class="container">
  <ul class="collection with-header">

    <li class="collection-header">
      <h4>Votre commande est confirmée</h4>
      <p>Un e-mail vous a été envoyé à l'adresse <em>{{ auth()->user()->email }}</em> avec toutes ces informations.</p>
    </li>

    <li id="detail" class="collection-item">
      @include('command.partials.detail', [
        'tax' => $order->tax,
        'shipping' => $order->shipping,
        'total' => $order->total,
        'content' => $order->products,
      ])
      <div class="row">
        <div class="col s6">
          Référence de la commande :
        </div>
        <div class="col s6">
          <strong>{{ $order->reference }}</strong>
        </div>
      </div>
      <div class="row">
        <div class="col s6">
          Moyen de paiement :
        </div>
        <div class="col s6">
          <strong>{{ $order->payment_text }}</strong>
        </div>
      </div>  
    </li> 

    <li class="collection-item">      
      <div class="row">
        <div class="grid-example col s12 m6">
          <h5>Adresse de facturation @if($order->adresses->count() === 1) et de livraison @endif</h5>
          @include('account.addresses.partials.address', [
            'address' => $order->adresses->first(),
          ])
        </div>
        @if($order->adresses->count() > 1)
          <div class="grid-example col s12 m6">
            <h5>Adresse de livraison</h5>
            @include('account.addresses.partials.address', [
              'address' => $order->adresses->last(),
            ])
          </div>
        @endif
      </div>
    </li>

  </ul>

  <ul class="collection with-header">
    <li class="collection-item">
      <h5>Votre commande a bien été enregistrée.</h5>
      @if($order->state->slug === 'cheque')
        <p>Veuillez nous envoyer un chèque avec :</p>
        <ul>
          <li>- montant du règlement : <strong>{{ number_format($order->total * (1 + $order->tax) + $order->shipping, 2, ',', ' ') }} €</strong></li>     
          <li>- payable à l'ordre de <strong>{{ $shop->name }}</strong></li>
          <li>- à envoyer à <strong>{{ $shop->address }}</strong></li>
          <li>- n'oubliez pas d'indiquer votre référence de commande <strong>{{ $order->reference }}</strong></li>
        </ul>
        @if($order->pick)
          Vous pourrez venir chercher votre commande dès réception du paiement.
        @else
          <p><strong>Votre commande vous sera envoyée dès réception du paiement</strong>.</p>
        @endif

      @elseif($order->state->slug === 'mandat')
        <p>Vous avez choisi de payer par mandat administratif. Ce type de paiement est réservé aux administrations.</p>
        <p>Vous devez envoyer votre mandat administratif à :</p>
        <p><strong>{{ $shop->name }}</strong></p>
        <p><strong>{{ $shop->address }}</strong></p>
        <p>Vous pouvez aussi nous le transmettre par e-mail à cette adresse : <strong>{{ $shop->email }}</strong></p>
        <p>N'oubliez pas d'indiquer votre référence de commande <strong>{{ $order->reference }}</strong>.</p>
        @if($order->pick)
          <p>Vous pourrez venir chercher votre commande dès réception du mandat.</p>
        @else
          <p><strong>Votre commande vous sera envoyée dès réception de ce mandat.</strong>.</p>
        @endif

      @elseif($order->state->slug === 'virement')
        <p>Veuillez effectuer un virement sur notre compte :</p>
        <ul>
          <li>- montant du virement : <strong>{{ number_format($order->total * (1 + $order->tax) + $order->shipping, 2, ',', ' ') }} €</strong></li>
          <li>- titulaire : <strong>{{ $shop->holder }}</strong></li>  
          <li>- BIC : <strong>{{ $shop->bic }}</strong></li>
          <li>- IBAN : <strong>{{ $shop->iban }}</strong></li>
          <li>- banque : <strong>{{ $shop->bank }}</strong></li>
          <li>- adresse banque : <strong>{{ $shop->bank_address }}</strong></li>
          <li>- n'oubliez pas d'indiquer votre référence de commande <strong>{{ $order->reference }}</strong></li>
        </ul>
        @if($order->pick)
          <p>Vous pourrez venir chercher votre commande dès réception du paiement.</p>
        @else
          <p><strong>Votre commande vous sera envoyée dès réception du virement.</strong>.</p>
        @endif
        
      @elseif($order->state->slug === 'carte' || $order->state->slug === 'erreur')
        
        {{-- On devra s'occuper de Stripe ici --}}

      @endif

      <div id="payment-ok" class="card center-align white-text green darken-4 hide">
        <div class="card-content">
          <span class="card-title">Votre paiement a été validé</span>
          @if($order->pick)
            <p>Vous pouvez venir chercher votre commande</p>
          @else
            <p>Votre commande va vous être envoyée</p>
          @endif
        </div>
      </div>      

      <p>Pour toute question ou information complémentaire merci de contacter notre support client.</p>
    </li>
  </ul>

</div>
@endsection

Maintenant lorsqu’on a validé une commande on arrive sur la page de la confirmation avec plusieurs zones.

Une entête :

Pour le moment l’envoi de mail est un mensonge mais on arrangera ça plus tard.

Ensuite on a le détail de la commande :

Ensuite la ou les adresses :

Enfin un texte explicatif qui dépend du mode de paiement choisi (et du mode de livraison), par exemple pour un chèque :

Pour un virement avec un retrait sur place :

Et pour un mandat administratif :

On verra dans un prochain article le cas particulier de la carte bancaire.

Un autorisation

On ne veut pas qu’un client puisse voir la confirmation d’un autre client :

php artisan make:policy OrderPolicy

On prévoit ce code :

<?php

namespace App\Policies;

use App\Models\{ User, Order };
use Illuminate\Auth\Access\HandlesAuthorization;

class OrderPolicy
{
    use HandlesAuthorization;

    /**
     * Create a new policy instance.
     *
     * @return void
     */
    public function manage(User $user, Order $order)
    {
        return $user->id === $order->user_id;
    }
}

Ici on vérifie que l’utilisateur est bien le propriétaire de la commande.

On ajoute ce code dans la méthode confirmation du contrôleur OrdersController :

public function confirmation(Request $request, $id)
{
    ...

    if(in_array($order->state->slug, ['cheque', 'mandat', 'virement', 'carte', 'erreur'])) {

        $this->authorize('manage', $order);
      
        ...
    }
}

Il ne reste plus qu’à enregistrer l’autorisation dans le provider AuthServiceProvider :

use App\Models\Order;
use App\Policies\OrderPolicy;

...

protected $policies = [
    Order::class => OrderPolicy::class,
];

Ça c’est réglé.

La page d’accueil

On va en profiter pour compléter un peu la page d’accueil. Dans le bas de la page on a les renseignements de la boutique :

Enfin là justement on ne les a pas alors on va modifier cette partie du code de layouts/app.blade.php puisqu’on dispose de la variable $shop :

<footer class="page-footer">
  <div class="container">
    <div class="row">
      <div class="col l6 s12">
        <h5 class="white-text">{{ $shop->name }}</h5>
        <ul>
          <li class="grey-text text-lighten-3">{{ $shop->address }}</li>
          <li class="grey-text text-lighten-3">Appelez-nous : {{ $shop->phone }}</li>
          <li class="grey-text text-lighten-3">Écrivez-nous : {{ $shop->email }}</li>
          <br>
          <li><img src="/images/paiement.png" alt="Modes de paiement" width="250px"></li>
        </ul>
      </div>
      <div class="col l4 offset-l2 s12">
        <h5 class="white-text">Informations</h5>
      </div>
    </div>
  </div>
  <div class="footer-copyright">
    <div class="container">
      © 2020 {{ $shop->name }}
      <a class="grey-text text-lighten-4 right" href="#" target="_blank"><img src="/images/facebook.png" alt="Facebook"></a>
    </div>
  </div>
</footer>

Et voilà :

Tant qu’on y est on va ajouter aussi des informations de la boutique dans la partie supérieure pour la vue home :

@section('content')
<div class="container">

  <div class="row">     
    <div class="card">
      <div class="card-content">
      <span class="card-title center-align">{{ $shop->home }}</span>
        <br>
        <ul class="collapsible">
          <li>
            <div class="collapsible-header"><i class="material-icons">info</i>Informations générales</div>
            <div class="collapsible-body informations">
              <ul>
                <li>{{ $shop->home_infos }}</li>
              </ul>
            </div>
          </li>
          <li>
            <div class="collapsible-header"><i class="material-icons">local_shipping</i>Frais d'expédition</div>
            <div class="collapsible-body informations">
              <ul>
                <li>{{ $shop->home_shipping }}</li>
              </ul>
            </div>
          </li>
        </ul>
      </div>
    </div>
  </div>

On a maintenant un système « accordéon » pour afficher les informations générales et les renseignements sur les frais d’expédition :

Conclusion

Le client est maintenant informé de sa commande, il nous faudra ajouter plus tard l’envoi d’un email pour lui rappeller toutes ça et pour qu’il retrouve ces données facielement. On lui créera aussi un compte avec le détail de ses commandes.

Dans le prochain article on mettra en place le paiement avec Stripe.

Print Friendly, PDF & Email

7 commentaires sur “Shopping : la confirmation de la commande

  1. Salut
    juste une question de curiosité, quelle est la différence entre
    Route::name(‘commandes.confirmation’)->get(‘confirmation/{order}’, ‘OrdersController@confirmation’);
    et
    Route::get(‘confirmation/{order}’, ‘OrdersController@confirmation’)->name(‘commandes.confirmation’);
    ou est-ce la même chose ?

  2. Hello
    j’ai un problème suite a cette line $shop = Shop::firstOrFail();
    -je pense qu’il faut un paramètre à « firstOrFail() » ou a défaut on doit faire un « where » puis un « firstOrFail() » sans parametre

    Too few arguments to function Illuminate\Database\Eloquent\Builder::findOrFail(), 0 passed in E:\projets\www\bestshopping\vendor\laravel\framework\src\Illuminate\Support\Traits\ForwardsCalls.php on line 23 and at least 1 expected

Laisser un commentaire