ldc-boutique-cnc/app/Http/Controllers/Fo/OrderController.php
2023-03-09 17:04:53 +01:00

860 lines
30 KiB
PHP

<?php
namespace App\Http\Controllers\Fo;
use App\Enums\Order\DeliveryModeEnum;
use App\Enums\GeneralConfigType;
use App\Enums\Order\DeliveryStatus;
use App\Enums\Order\OrderProcess;
use App\Enums\Order\PaymentModeEnum;
use App\Enums\Order\PaymentStatus;
use App\Enums\Order\TransactionStatus;
use App\Enums\Order\TransactionType;
use App\Enums\Order\ValidationStatus;
use App\Http\Controllers\Controller;
use App\Http\Requests\Fo\Orders\CheckoutRequest;
use App\Http\Requests\Fo\Orders\SetOrderTimeSlotRequest;
use App\Http\Requests\Fo\Orders\ShippingFormRequest;
use App\Http\Requests\Fo\Orders\ShippingModeFormRequest;
use App\Http\Resources\ShopResource;
use App\Lib\Helpers\ToolboxHelper;
use App\Mail\NewOrderIncome;
use App\Models\Customer\Customer;
use App\Models\Payment\Transaction;
use App\Models\Shop\DeliveryMode;
use App\Models\Site\GeneralConfig;
use App\Models\Shop\Order;
use App\Models\Shop\Shop;
use App\Models\Shop\Timeslot;
use App\Notifications\Order\OrderCreated;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\Facades\View;
use Illuminate\Support\Str;
use Illuminate\Validation\ValidationException;
use LDC\LDCCRM\Enums\Country;
class OrderController extends Controller
{
/**
* OrderController
*
* @return void
*/
public function __construct()
{
$this->middleware(function (Request $request, callable $next) {
// * On peut passer commande ?
$this->authorize('orderThings', Order::class);
return $next($request);
});
}
// * --- TUNNEL DE COMMANDE ---
/**
* Récapitualtif du panier
*
* * --- 1 ---
*
* @return \Illuminate\Contracts\View\View
*/
public function basketRecap()
{
$this->assertDoesNotHaveEmptyBasket();
$this->assertBasketDidNotChange();
$this->assertBasketHasMinAmount();
$this->setOrderProcessStep(OrderProcess::reviewBasket());
/** @var \Gloudemans\Shoppingcart\Cart */
$basket = app('basket');
$messages = [];
$basket = $this->filterBasketKeepOnlyOrderableItems($basket, $messages);
if (!empty($messages)) {
Session::flash('warning', \collect($messages)->implode(",\n"));
}
$basketItems = $this->basketToList($basket);
return view('theme::pages.order-tunnel.basket-recap', compact(
'basket',
'basketItems'
));
}
/**
* Select shipping Mode And create Session Order
*
* * --- 2 ---
*
* @return \Illuminate\Contracts\View\View
*/
public function shippingMode()
{
$this->assertDoesNotHaveEmptyBasket();
$this->assertBasketDidNotChange();
$this->assertBasketHasMinAmount();
$this->setOrderProcessStep(OrderProcess::shippingMethod(), OrderProcess::reviewBasket());
// * CREATE ORDER
/** @var \App\Models\Customer\Customer $customer */
$customer = auth('frontend')->user();
/** @var \Gloudemans\Shoppingcart\Cart */
$basket = app('basket');
/** @var \App\Models\Shop\Order|null $order */
$order = Order::getCurrentOrder();
// * If there was a previous order that was not ended use the ID.
/** @var \App\Models\Shop\Order */
$order = $order ?? new Order();
$order->mail_sent = false;
$order->delivery_status = DeliveryStatus::pending();
$order->payment_status = PaymentStatus::pending();
$order->validation_status = ValidationStatus::pending();
$order->assignBasket($basket);
$order->customer()->associate($customer);
// * Save Session Order
Session::put('currentOrder', $order);
/** @var \Illuminate\Database\Eloquent\Collection<\App\Models\Shop\DeliveryMode> */
$deliveryModes = app('DeliveryModesGlobal');
return view('theme::pages.order-tunnel.shipping-mode', \compact('deliveryModes'));
}
/**
* Save shipping Mode
*
* * --- 2 ---
*
* @param \App\Http\Requests\Fo\Orders\ShippingModeFormRequest $request
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
*/
public function shippingModeSubmit(ShippingModeFormRequest $request)
{
$this->assertDoesNotHaveEmptyBasket();
$this->assertBasketDidNotChange();
$this->assertBasketHasMinAmount();
$this->assertDoesHaveCurrentOrder();
$this->setOrderProcessStep(OrderProcess::shippingMethod(), OrderProcess::reviewBasket());
/** @var \App\Models\Shop\DeliveryMode $mode */
if (!($mode = DeliveryMode::availables()->where('mode', $request->mode)->first())) {
$e = new \RuntimeException('Mode de livraison non disponible', 1);
report($e);
Session::flash('error', trans('Mode de livraison non disponible'));
return \back()->withException($e);
}
$this->allowTimeSlotSelect();
/** @var \App\Models\Shop\Order $order */
$order = Order::getCurrentOrder();
$order->deliveryMode()->associate($mode);
Session::put('currentOrder', $order);
return \response()->redirectToRoute('order-tunnel.shipping');
}
/**
* Shipping informations
*
* * --- 3 ---
*
* ! Pour - Click and collect
*
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
* @throws \RuntimeException If delivery mode is unhandled.
*/
public function shipping()
{
$this->assertDoesNotHaveEmptyBasket();
$this->assertBasketDidNotChange();
$this->assertBasketHasMinAmount();
$this->assertDoesHaveCurrentOrder();
$this->assertDeliveryModeIsValid();
$this->setOrderProcessStep(OrderProcess::shippment(), OrderProcess::shippingMethod());
/** @var \App\Models\Shop\Order $order */
$order = Order::getCurrentOrder();
// * Switch Delivery modes
// * Pour afficher formulaire qui devra retourner une adresse 'shipping'
/**
* * Switch Delivery modes
* - Pour afficher formulaire qui devra retourner une adresse 'shipping'.
* - Qui devra fournir un timeslot dans le cas de clickAndCollect.
*/
/** @var \App\Enums\Order\DeliveryModeEnum|null */
$delivery_mode = \optional($order->deliveryMode)->mode;
switch ($delivery_mode) {
case DeliveryModeEnum::inShop():
// * 1 Select timeslot if not already done.
if (!$order->timeslot()->first() or !Session::get('deliveryModePickSlot')) {
$shops = Shop::all()->map(function (Shop $shop) {
return new ShopResource($shop);
});
$this->allowTimeSlotSelect(true);
View::share('mustSelectTimeSlot', true);
return \view('theme::pages.order-tunnel.pick-slot', \compact('order', 'shops'));
}
return \view('theme::pages.order-tunnel.shipping', \compact('order'));
default:
throw new \RuntimeException('Unhandled delivery mode ');
}
throw new \RuntimeException('This should never happen');
}
/**
* Save and validate timeslot
*
* * --- 3 ---
*
* @param \App\Http\Requests\Fo\Orders\SetOrderTimeSlotRequest $request
* @return \Illuminate\Http\RedirectResponse
* @throws \Illuminate\Validation\ValidationException If Creneau is not available anomore.
*/
public function validateSelectedTimeSlot(SetOrderTimeSlotRequest $request)
{
$this->assertDoesNotHaveEmptyBasket();
$this->assertBasketDidNotChange();
$this->assertBasketHasMinAmount();
$this->assertDoesHaveCurrentOrder();
$this->assertDeliveryModeIsValid();
$this->setOrderProcessStep(OrderProcess::shippment(), OrderProcess::shippingMethod());
/** @var \App\Models\Shop\Shop */
$shop = Shop::query()->where('id', $request->shop_id)->firstOrFail();
$creneau = Carbon::createFromFormat('d/m/Y H:i', "{$request->selected_day} {$request->selected_time}");
if (!$shop->isCreneauAvailable($creneau)) {
throw ValidationException::withMessages([
'error' => 'Ce créneau n\'est plus disponible'
]);
}
DB::transaction(function () use ($shop, $creneau) {
/** @var \App\Models\Shop\Order $order */
$order = Order::getCurrentOrder();
// * Assign order id we would use, if none already.
if (!$order->id) {
$order->id = Str::uuid();
}
Session::put('currentOrder', $order);
/** @var \App\Models\Shop\Timeslot */
$timeSlot = Timeslot::query()->whereHas('order', function (Builder $q) use ($order) {
$q->where('id', $order->id);
})->firstOrNew();
$timeSlot->order()->associate($order);
$timeSlot->shop()->associate($shop);
$timeSlot->slot = $creneau;
$timeSlot->saveOrFail();
});
return response()->redirectToRoute('order-tunnel.shipping');
}
/**
* SaveShippingAdress
*
* * --- 3 ---
*
* @param \App\Http\Requests\Fo\Orders\ShippingFormRequest $request
* @return \Illuminate\Http\RedirectResponse
* @throws \RuntimeException If somehow no email can be found.
*/
public function shippingSubmit(ShippingFormRequest $request)
{
$this->assertDoesNotHaveEmptyBasket();
$this->assertDoesHaveCurrentOrder();
$this->assertBasketDidNotChange();
$this->assertBasketHasMinAmount();
$this->assertDeliveryModeIsValid();
$this->setOrderProcessStep(OrderProcess::shippment(), OrderProcess::shippingMethod());
/** @var \App\Models\Shop\Order $order */
$order = Order::getCurrentOrder();
$order->fill($request->validated());
/** @var object */
$billing = $order->billing;
$billing->country = Country::france();
$order->billing = $billing;
$this->allowTimeSlotSelect();
// Fetch right email to send in.
if ($order->billing->email) {
$order->email = $order->billing->email;
} elseif ($order->shipping->email) {
$order->email = $order->shipping->email;
} else {
$order->email = $order->customer->api_data->email;
}
if (!$order->email) {
throw new \RuntimeException('Somehow no email was provided');
}
$this->fillShippingFromShopInfo($order);
// * Allow timeslot select
Session::put('currentOrder', $order);
return \response()->redirectToRoute('order-tunnel.review');
}
/**
* Valider le panier avant achat.
*
* * --- 4 ---
*
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
*/
public function review()
{
$this->assertDoesNotHaveEmptyBasket();
$this->assertBasketDidNotChange();
$this->assertBasketHasMinAmount();
$this->assertDoesHaveCurrentOrder();
$this->assertDeliveryModeIsValid();
$this->setOrderProcessStep(OrderProcess::paymentReview(), OrderProcess::shippment());
$this->allowTimeSlotSelect();
/** @var \App\Models\Customer\Customer $customer */
$customer = auth('frontend')->user();
/** @var \App\Models\Shop\Order $order */
$order = Order::getCurrentOrder();
// * Order completed email already sent.
if ($order->mail_sent) {
self::detroyCurrentBasket();
return \view('theme::pages.order-tunnel.done', \compact('order'));
}
/** @var \Gloudemans\Shoppingcart\Cart */
$basket = app('basket');
$availablePaymentModes = app('PaymentModesGlobal')->where('status', true);
return view('theme::pages.order-tunnel.review', \compact('basket', 'order', 'availablePaymentModes'));
}
/**
* Setup Order for submit
*
* * --- 4 ---
*
* @param \App\Http\Requests\Fo\Orders\CheckoutRequest $request
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
* @throws \RuntimeException If payment method is unhandled somehow.
*/
public function reviewSubmit(CheckoutRequest $request)
{
$this->assertDoesNotHaveEmptyBasket();
$this->assertBasketDidNotChange();
$this->assertDoesHaveCurrentOrder();
$this->assertDeliveryModeIsValid();
$this->setOrderProcessStep(OrderProcess::paymentReview(), OrderProcess::shippment());
/** @var \App\Models\Customer\Customer $customer */
$customer = auth('frontend')->user();
// * Force clone here to prevent session save model state (If something goes wrong).
/** @var \App\Models\Shop\Order $order */
$order = clone Order::getCurrentOrder();
// * Order completed email already sent.
if (!$order->exists and $order->mail_sent) {
self::detroyCurrentBasket();
return \view('theme::pages.order-tunnel.done', \compact('order'));
}
/** @var \App\Enums\Order\PaymentModeEnum */
$paymentMode = $request->modeEnum;
// * Check Payment mode
Gate::authorize('isAvailable', [PaymentMode::class, $paymentMode]);
// * Get Transaction
$transaction = Transaction::getCurrentTransaction() ??
Transaction::getNewInstance(
$paymentMode,
TransactionType::debit(),
$order->total_ttc,
);
$transaction->refresh();
// * If transaction is already payed.
if ($transaction->status->equals(TransactionStatus::validated())) {
// ! Prevent double checkout (double transaction), just let IPN (webhooks) handle this.
$e = new \RuntimeException('La transaction a déjà été traitée');
report($e);
$this->detroyCurrentBasket();
abort(500, trans($e->getMessage()));
}
// * If previously failed get a new one.
if ($transaction->status->equals(TransactionStatus::failed())) {
$transaction = Transaction::getNewInstance(
$paymentMode,
TransactionType::debit(),
$order->total_ttc,
);
}
// * If customer switched transaction mode.
if (!$transaction->payment_mode->equals($paymentMode)) {
// * Reuse previous
$transaction = Transaction::query()->whereHas('order', function (Builder $q) use ($order) {
$q->where('id', $order->id);
})->where('payment_mode', $paymentMode)->where('status', TransactionStatus::pending())
->first() ?? Transaction::getNewInstance(
$paymentMode,
TransactionType::debit(),
$order->total_ttc,
);
// * Remove other pending in shop transactions
Transaction::query()->whereHas('order', function (Builder $q) use ($order) {
$q->where('id', $order->id);
})->where('status', TransactionStatus::pending())->where('id', '!=', $transaction->id)
->where('payment_mode', PaymentModeEnum::inShop())->delete();
}
// * If payment mode is boutique just use the previous transaction if there was one.
if ($transaction->payment_mode->equals(PaymentModeEnum::inShop())) {
$transaction = Transaction::query()->whereHas('order', function (Builder $q) use ($order) {
$q->where('id', $order->id);
})->where('payment_mode', PaymentModeEnum::inShop())
->where('status', TransactionStatus::pending())->first() ?? $transaction;
}
// * Checkout using selected Payment system.
return $transaction->getAdapter()->checkout(
$customer,
$order,
$transaction,
// * When succeeded
function (Customer $customer, Order $order, Transaction $transaction) {
// * Associate transaction to order
$transaction->order()->associate($order);
// * Enregistrement commande avant checkout.
if (!$order->save() or !$transaction->save()) {
report(new \RuntimeException("Order saving error happened."));
throw ValidationException::withMessages([
'error' => trans('Une erreur est survenue, veuillez réssayer')
]);
}
// * Save Transaction
Session::put('currentTransaction', $transaction->refresh());
// * Save Order
Session::put('currentOrder', $order->refresh());
},
// ! If failed.
function () {
throw ValidationException::withMessages([
'error' => trans('Une erreur est survenue, veuillez réssayer')
]);
}
);
}
/**
* Redirection après paiement et validation
*
* * --- 5 ---
*
* ! Middleware Url signée ici
*
* * La méthode sers a récupérer la session après redirection du module de paiment.
*
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
*/
public function checkout()
{
/** @var \App\Models\Customer\Customer|null $customer */
$customer = auth('frontend')->user();
/** @var \App\Models\Shop\Order|null $order */
$order = Order::getCurrentOrder();
/** @var \App\Models\Payment\Transaction|null $transaction */
$transaction = Transaction::getCurrentTransaction();
if (!$customer or !$order or !$transaction) {
\redirect()->route('order-tunnel.review')
->with('warning', trans('La session est requise'))
->throwResponse();
}
// * Force clone here to prevent session save model state (If something goes wrong).
$order = clone $order;
$transaction = clone $transaction;
// * If transaction has already been processed.
if (!$transaction->status->equals(TransactionStatus::pending())) {
\redirect()->route('order-tunnel.review')
->with('warning', trans('Étape précédente requise'))
->throwResponse();
}
if (!($transaction = $transaction->getAdapter()->checkoutIsResponseIsValid($customer, $transaction))) {
\abort(400, trans('Impossible de valider la transaction'));
}
// * Save Transaction
Session::put('currentTransaction', $transaction);
// * Save Order
Session::put('currentOrder', $order);
return view('back::pages.order-tunnel-checkout');
}
/**
* Redirection après paiement et validation
*
* * --- 5 ---
*
* * La méthode sers a récupérer la session après redirection du module de paiment.
*
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
*/
public function checkoutVerify()
{
$this->assertDoesNotHaveEmptyBasket();
$this->assertDoesHaveCurrentOrder();
$this->assertDoesHaveCurrentTransaction();
if (!$this->checkThatActualProcessStepIs(OrderProcess::paymentReview())) {
\redirect()->route('order-tunnel.review')
->with('warning', trans('Étape précédente requise'))
->throwResponse();
}
return DB::transaction(function () {
/** @var \App\Models\Customer\Customer $customer */
$customer = auth('frontend')->user();
// * Force clone here to prevent session save model state (If something goes wrong).
/** @var \App\Models\Shop\Order $order */
$order = clone Order::getCurrentOrder();
// * Force clone here to prevent session save model state (If something goes wrong).
/** @var \App\Models\Payment\Transaction $transaction */
$transaction = clone Transaction::getCurrentTransaction();
// * Order completed email already sent.
if ($order->exists and $transaction->exists and $order->mail_sent) {
self::detroyCurrentBasket();
return \view('theme::pages.order-tunnel.done', \compact('order'));
}
$transaction->getAdapter()->checkoutVerify($transaction);
$transaction->saveOrFail();
// * Notification has been sent
Order::query()->where('id', $order->id)->update([
'mail_sent' => true
]);
$order->refresh();
// * Notifiy customer
$customer->notify(new OrderCreated($order));
/** @var object|null */
$notificationMail = \optional(\optional(GeneralConfig::query()
->where('type', GeneralConfigType::global())
->first())->data)->confirmed_orders_destination_email;
if (!\optional($notificationMail)->value) {
throw new \RuntimeException('Could not get new order email notification setting');
}
if ($order->validation_status->equals(ValidationStatus::pending())) {
// * Send mail after reponse to BO user.
dispatch(function () use (
$notificationMail,
$order
) {
Mail::to($notificationMail->value)->send(new NewOrderIncome($order));
})->afterResponse();
}
self::detroyCurrentBasket();
return view('theme::pages.order-tunnel.done', \compact('order'));
});
}
// * --- FIN TUNNEL DE COMMANDE ---
// * PRIVATE METHODS
/**
* Allow timeslot select in the tunnel even if already selected
*
* @param boolean $disallow To force disallow timeslot picker select.
* @return void
*/
private function allowTimeSlotSelect(bool $disallow = false)
{
// * Allow timeslot select
Session::put('deliveryModePickSlot', $disallow);
}
/**
* Assert user does not have an empty basket
* or redirect with warning
*
* @return void
*/
private function assertDoesHaveCurrentOrder()
{
if (
$order = Order::getCurrentOrder() and
$order->payment_status and
$order->payment_status->equals(PaymentStatus::payed())
) {
self::detroyCurrentBasket();
abort(\response()->view('theme::pages.order-tunnel.done', \compact('order')));
}
if (!$order) {
\redirect()->route('order-tunnel.basket.recap')->throwResponse();
}
}
/**
* Delete order steps, removes basket, ends tunnel transaction.
*
* @return void
*/
public static function detroyCurrentBasket()
{
/** @var \Gloudemans\Shoppingcart\Cart */
$basket = app('basket');
$basket->destroy();
// * Remove timeslot if order is not saved into DB.
/** @var \App\Models\Shop\Order|null */
if ($order = Session::get('currentOrder') and $order->timeslot and !$order->exists) {
$order->timeslot->delete();
}
Session::remove('currentOrder');
Session::remove('currentTransaction');
Session::remove('PreviousOrderStep');
Session::remove('OrderStep');
Session::remove('deliveryModePickSlot');
Session::remove('basketFingerPrint');
}
/**
* Assert user does not have an empty basket
* or redirect with warning
*
* @return void
*/
private function assertDoesNotHaveEmptyBasket(): void
{
/** @var \Gloudemans\Shoppingcart\Cart */
$basket = app('basket');
if (!$basket->count()) {
\redirect()->route('home')
->with('warning', trans('Vous n\'avez aucun produit dans votre panier'))
->throwResponse();
}
}
/**
* Assert user does not have an empty basket
* or redirect with warning
*
* @return void
*/
private function assertBasketDidNotChange(): void
{
/** @var \Gloudemans\Shoppingcart\Cart */
$basket = app('basket');
$actual_finger_print = hash('sha256', \json_encode($basket->content()->jsonSerialize()));
$session_finger_print = Session::get('basketFingerPrint');
Session::put('basketFingerPrint', $actual_finger_print);
if ($session_finger_print !== $actual_finger_print) {
Session::remove('deliveryModePickSlot');
\redirect()->route('order-tunnel.basket.recap')
->with('warning', trans('Votre panier à été modifié'))
->throwResponse();
}
}
/**
* Assert basket has the minimal amount required for payment
*
* @return void
*/
private function assertBasketHasMinAmount(): void
{
/** @var \Gloudemans\Shoppingcart\Cart */
$basket = app('basket');
$sampleOrder = new Order();
$sampleOrder->assignBasket($basket);
$minAmountForTransaction = \collect(PaymentModeEnum::toArray())
->max(function (PaymentModeEnum $paymentMode) {
return $paymentMode->minAmount;
});
if ($sampleOrder->total_ttc < $minAmountForTransaction) {
\redirect()->route('home')
->with('warning', trans('Le montant minimal pour une commande est de :minAmount', [
'minAmount' => ToolboxHelper::fmtCurrency($minAmountForTransaction)
]))->throwResponse();
}
}
/**
* Assert user does not have an empty basket
* or redirect with warning
*
* @return void
*/
private function assertDoesHaveCurrentTransaction()
{
$transaction = Transaction::getCurrentTransaction();
if (
!$transaction or ($transaction->status and
$transaction->status->equals(TransactionStatus::failed())
)
) {
\redirect()->route('order-tunnel.review')
->with('warning', trans('La transaction a échoué'))
->throwResponse();
}
}
/**
* Assert delivery mode si still available.
*
* @return void
*/
private function assertDeliveryModeIsValid(): void
{
$order = Order::getCurrentOrder();
if (!Gate::check('orderUsingDeliveryMode', $order)) {
Session::remove('deliveryModePickSlot');
\redirect()->route('order-tunnel.shipping-mode')
->with('warning', trans('Le mode de livraison n\'est pas disponible'))
->throwResponse();
}
}
/**
* Validate Process step
*
* @param \App\Enums\Order\OrderProcess $step
* @param \App\Enums\Order\OrderProcess|null $assertDid
* @return void
* @throws \Illuminate\Validation\ValidationException If previous was not done.
*/
private function setOrderProcessStep(OrderProcess $step, OrderProcess $assertDid = null): void
{
if ($assertDid) {
if (!Session::get('PreviousOrderStep')) {
Session::put('PreviousOrderStep', collect());
}
/** @var \Illuminate\Support\Collection */
$previousSteps = Session::get('PreviousOrderStep');
if (Session::get('OrderStep') < $step) {
/** @var \App\Enums\OrderProcess */
$previousStep = Session::get('OrderStep');
$previousSteps->put($previousStep->value, $previousStep);
Session::put('PreviousOrderStep', $previousSteps);
}
$this->assertDidProcessStep($assertDid);
} //end if
Session::put('OrderStep', $step);
}
/**
* Assert the the step is done.
*
* @param \App\Enums\Order\OrderProcess $assertDid
* @return void
* @throws \Illuminate\Validation\ValidationException If previous was not done.
*/
private function assertDidProcessStep(OrderProcess $assertDid): void
{
if (!Session::get('PreviousOrderStep')) {
Session::put('PreviousOrderStep', collect());
}
/** @var \Illuminate\Support\Collection */
$previousSteps = Session::get('PreviousOrderStep');
if (!$previousSteps->count()) {
\redirect()->route('home')
->with('warning', trans('Vous devez d\'abord valider votre panier'))
->throwResponse();
}
if (!$previousSteps->contains($assertDid)) {
throw ValidationException::withMessages(['Étape précédente requise']);
}
}
/**
* Assert the actual step is.
*
* @param \App\Enums\Order\OrderProcess $assertActual
* @return boolean
* @throws \Illuminate\Validation\ValidationException If previous was not done.
*/
private function checkThatActualProcessStepIs(OrderProcess $assertActual): bool
{
/** @var \App\Enums\OrderProcess|null */
$orderStep = Session::get('OrderStep');
return $orderStep and $orderStep->equals($assertActual);
}
/**
* Fill order shipping with in shop infos
*
* @param \App\Models\Shop\Order $order
* @return void
* @throws \Illuminate\Validation\ValidationException Si le créneau de reservation n'est plus trouvable.
*/
private function fillShippingFromShopInfo(Order $order)
{
if ($order->deliveryMode->mode->equals(DeliveryModeEnum::inShop())) {
/** @var \App\Models\Shop\Timeslot|null */
if (!($timeslot = $order->timeslot()->first())) {
throw ValidationException::withMessages([
'error' => trans('Créneau de réservation introuvable')
]);
}
$order->shipping = [
'firstname' => $timeslot->shop->name,
'lastname' => '',
'email' => null,
'phone' => $timeslot->shop->phone,
'line1' => $timeslot->shop->address,
'postal_code' => $timeslot->shop->postal_code,
'city' => $timeslot->shop->city,
'country' => $timeslot->shop->country
];
}
}
}