ldc-gen-game-web/app/Http/Controllers/Fo/ParticipateController.php

320 lines
11 KiB
PHP
Raw Permalink Normal View History

2020-10-29 15:40:23 +01:00
<?php
2026-10-02 12:09:46 +02:00
declare(strict_types=1);
namespace App\Http\Controllers\Fo;
2020-10-29 15:40:23 +01:00
use App\Http\Controllers\Controller;
2023-12-08 18:55:55 +01:00
use App\Http\Requests\Fo\Customers\CreateAccountRequest;
2023-12-05 12:33:25 +01:00
use App\Http\Requests\Fo\ParticipateRequest;
2023-12-12 14:56:12 +01:00
use App\Lib\Discount as LibDiscount;
2023-12-12 12:25:45 +01:00
use App\Mail\Won\PrizeWonAdminMail;
2026-10-02 12:09:46 +02:00
use App\Models\Code;
use App\Models\Customer;
use App\Models\InstantWin;
use App\Models\Participation;
2026-10-02 12:09:46 +02:00
use App\Models\Product;
2020-10-29 15:40:23 +01:00
use App\Models\Settings;
2023-12-12 14:56:12 +01:00
use App\Notifications\Customer\HasWonDiscount;
2023-12-12 12:25:45 +01:00
use App\Notifications\Customer\HasWonInstantWin;
use App\Repositories\Fo\CrmRepository;
2026-10-02 12:09:46 +02:00
use Exception;
use Illuminate\Contracts\View\View;
use Illuminate\Http\Exceptions\HttpResponseException;
2020-10-29 15:40:23 +01:00
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Facades\Mail;
2023-12-08 18:55:55 +01:00
use Illuminate\Support\Facades\Session;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\ValidationException;
2026-10-02 12:09:46 +02:00
use LDC\MESBR\MesBr;
use RuntimeException;
2020-10-29 15:40:23 +01:00
2023-12-07 16:59:17 +01:00
class ParticipateController extends Controller
2020-10-29 15:40:23 +01:00
{
2026-10-02 12:09:46 +02:00
private readonly CrmRepository $crmRepository;
2023-12-08 18:55:55 +01:00
/**
* ParticipateController
*/
public function __construct()
{
$this->crmRepository = new CrmRepository();
2023-12-08 18:55:55 +01:00
$this->middleware(function (Request $request, callable $next) {
2023-12-12 12:25:45 +01:00
$this->authorize('fo.gameEnabled');
2023-12-08 18:55:55 +01:00
$this->assertUserHasEnoughInfoToUseMesBr();
2026-10-02 12:09:46 +02:00
2023-12-08 18:55:55 +01:00
return $next($request);
});
}
2022-01-11 10:26:06 +01:00
/**
* Display participation form
2022-01-11 10:26:06 +01:00
*/
2026-10-02 12:09:46 +02:00
public function participate(): View
2021-08-18 17:08:02 +02:00
{
2026-10-02 12:09:46 +02:00
if (! Gate::check('participate', Participation::class)) {
/** @var view-string $view */
$view = 'theme::pages.participation.participation-exhausted';
return view($view);
}
2026-10-02 12:09:46 +02:00
/** @var view-string $view */
$view = 'theme::pages.participation.participate';
return view($view);
2020-10-29 15:40:23 +01:00
}
2022-01-11 10:26:06 +01:00
/**
* Participate Method
*/
2026-10-02 12:09:46 +02:00
public function participateSubmit(ParticipateRequest $request): View
2021-08-18 17:08:02 +02:00
{
return DB::transaction(function () use ($request) {
// ! On verrouille le ou les instants gagnant
2026-10-02 12:09:46 +02:00
/** @var InstantWin|null */
$instantWin = InstantWin::query()->lockForUpdate()
->where('available_at', '<', now())
2023-12-12 12:25:45 +01:00
->whereDoesntHave('participation')
->get()->sortBy('available_at')->first();
2026-10-02 12:09:46 +02:00
/** @var Settings */
$settings = resolve(Settings::class);
2026-10-02 12:09:46 +02:00
/** @var Customer */
$customer = auth('frontend')->user();
2020-10-29 15:40:23 +01:00
2026-10-02 12:09:46 +02:00
/** @var Code|null */
2023-12-12 12:25:45 +01:00
$code = $request->post('unique_code');
2026-10-02 12:09:46 +02:00
/** @var Product|null */
2023-12-12 12:25:45 +01:00
$product = $request->post('product');
// * Make new participation
$participation = Participation::makeNew(
2026-10-02 12:09:46 +02:00
resolve('clientIp'),
$customer,
$code,
$product
);
// * Si l'utilisateur actuel à déjà gagné un gros lot, pas d'instant gagnant.
2023-12-12 12:25:45 +01:00
// ? As-t-on un instant gagnant ?
2026-10-02 12:09:46 +02:00
if (Participation::customerAlreadyHasAnInstantWin($customer) || ! $instantWin) {
2023-12-12 14:56:12 +01:00
// * --- DISCOUNT WIN ---
// ? Les BR sont activés ?
2026-10-02 12:09:46 +02:00
if (! $settings->discounts_activated) {
// * On enregistre la participation du joueur.
$participation->save();
2026-10-02 12:09:46 +02:00
/** @var view-string $view Pas de coupons disponibles, le joueur à perdu. */
$view = 'theme::pages.participation.loose';
return view($view);
}
2022-01-11 10:26:06 +01:00
// * Le joueur à gagné un coupon.
2026-10-02 12:09:46 +02:00
/** @var \App\Lib\Discount Coupon aléatoire en fonction du ratio de chaque coupon */
2023-12-12 14:56:12 +01:00
$discount = Arr::get(
$settings->web_coupons,
$this->getRandomWeightedElementIndex($settings->web_coupons)
);
2025-10-27 16:23:02 +01:00
$this->setDiscountAsWon($customer, $discount);
2023-12-12 14:56:12 +01:00
// * Le joueur à remporté un coupon
$participation->discount_code = (string) $discount->web_coupon_identifiant;
// * On enregistre la participation du joueur.
$participation->save();
$crmCustomer = $this->crmRepository->fetchCrmCustomer($customer);
2023-12-12 16:12:50 +01:00
2023-12-12 14:56:12 +01:00
$customer->notify(new HasWonDiscount(
$discount,
2023-12-12 16:12:50 +01:00
$crmCustomer->firstname
2023-12-12 14:56:12 +01:00
));
2026-10-02 12:09:46 +02:00
/** @var view-string $view */
$view = 'theme::pages.participation.won';
return view($view, ['discount' => $discount]);
} // end if
2023-12-12 14:56:12 +01:00
// * --- INSTANT WIN ---
2023-12-12 12:55:05 +01:00
// * On enregistre la participation du joueur.
2023-12-12 12:25:45 +01:00
$participation->save();
2023-12-12 12:55:05 +01:00
// * Le joueur à remporté un instant gagnant
$instantWin->participation()->associate($participation);
$instantWin->save();
2023-12-12 12:25:45 +01:00
$crmCustomer = $this->crmRepository->fetchCrmCustomer($customer);
2023-12-12 16:12:50 +01:00
2023-12-12 12:25:45 +01:00
// * Notify customer for his win
$customer->notify(new HasWonInstantWin(
$instantWin->prize,
2023-12-12 16:12:50 +01:00
$crmCustomer->firstname
2023-12-12 12:25:45 +01:00
));
// * Dispatch notification to mail list
Mail::to($settings->notification_emails)->send(new PrizeWonAdminMail(
$settings->name,
$participation->created_at,
$instantWin->prize->label,
2023-12-12 16:12:50 +01:00
$crmCustomer,
2026-10-02 12:09:46 +02:00
$code?->code_unique,
$product?->ean_code
2023-12-12 12:25:45 +01:00
));
2026-10-02 12:09:46 +02:00
/** @var view-string $view */
$view = 'theme::pages.participation.won';
return view($view, [
'prizeModel' => $instantWin->prize,
'participationModel' => $participation,
2026-10-02 12:09:46 +02:00
'crmCustomer' => $crmCustomer,
2023-12-12 12:25:45 +01:00
]);
});
2022-01-11 10:26:06 +01:00
}
2023-12-08 18:55:55 +01:00
// * --- PRIVATE METHODS ---
/**
2023-12-12 14:56:12 +01:00
* Try Call CRM + MesBr to setup discount
2022-01-11 10:26:06 +01:00
*
2026-10-02 12:09:46 +02:00
* @throws HttpResponseException If Any error occurs.
*
* @phpcs:disable Generic.Metrics.CyclomaticComplexity
2022-01-11 10:26:06 +01:00
*/
2025-10-27 16:23:02 +01:00
private function setDiscountAsWon(Customer $customer, LibDiscount $discount): void
2021-08-18 17:08:02 +02:00
{
2023-12-12 14:56:12 +01:00
// phpcs:enable
// * Phase - 1 Recupération des informations CRM
2026-10-02 12:09:46 +02:00
/** @var \LDC\LDCCRM\Models\Customer */
$crmUser = $this->crmRepository->fetchCrmCustomer($customer);
// * Phase - 2 Mise à jour du coupon dans MesBr
2023-12-12 14:56:12 +01:00
try {
2026-10-02 12:09:46 +02:00
/** @var Settings */
$settings = resolve(Settings::class);
2023-12-12 14:56:12 +01:00
2026-10-02 12:09:46 +02:00
/** @var MesBr */
$mesBr = resolve('mesBrAPI');
2023-12-12 14:56:12 +01:00
// * MaJ Customer
/** @var string */
$crm_customer_hashcode = retry(3, function () use ($mesBr, $crmUser) {
2023-12-12 14:56:12 +01:00
/**
* Parce que MesBr n'est pas fiable il faut retenter pour avoir
* l'id client, des fois cet id sera dans hashcode...
*
* Id est necessaire pour update panier..
*/
2026-10-02 12:09:46 +02:00
/** @var object|null $result */
$result = $mesBr->updateCustomer($crmUser->hashcode, $crmUser->email, $crmUser->country->label());
2026-10-02 12:09:46 +02:00
if ($result?->status !== 'OK') {
throw new RuntimeException(
2023-12-12 14:56:12 +01:00
\sprintf(
'MESBR : Une erreur est survenue. Code : %s Message : %s',
2026-10-02 12:09:46 +02:00
$result->code ?? 'Undefined',
2023-12-12 14:56:12 +01:00
$result->message ?? 'Undefined'
)
);
}
2026-10-02 12:09:46 +02:00
/** @var object|null $crm_customer */
$crm_customer = $result->customer ?? null;
throw_if(
empty($crm_customer->hashcode),
RuntimeException::class,
'MESBR : Une erreur est survenue. Update Customer n\'as pas retourné le customer hashcode',
);
2023-12-12 14:56:12 +01:00
return $crm_customer->hashcode;
2023-12-12 14:56:12 +01:00
}, 100);
// * Maj Panier
2025-10-27 16:23:02 +01:00
$result = $mesBr->updateBasket(
2023-12-12 14:56:12 +01:00
$crmUser,
2024-01-31 09:03:18 +00:00
strval($discount->web_coupon_identifiant)
2023-12-12 14:56:12 +01:00
);
2023-12-12 12:25:45 +01:00
2026-10-02 12:09:46 +02:00
if (Arr::get($result, 'status') === 'OK') {
2023-12-12 14:56:12 +01:00
// * La réponse est conforme ?
2025-10-27 16:23:02 +01:00
$needed_fields = ['ref'];
2026-10-02 12:09:46 +02:00
if (! Arr::has($result, $needed_fields)) {
throw new RuntimeException(sprintf(
2023-12-12 14:56:12 +01:00
'MESBR : Il manques des champs dans la réponse, attendu => %s, donné => %s',
json_encode($needed_fields),
json_encode($result),
));
}
2023-12-12 12:25:45 +01:00
2023-12-12 14:56:12 +01:00
// * Tout est OK
2025-10-27 16:23:02 +01:00
return;
2023-12-12 14:56:12 +01:00
}
2026-10-02 12:09:46 +02:00
throw new RuntimeException(
2023-12-12 14:56:12 +01:00
\sprintf(
'MESBR : Une erreur est survenue. Code : %s Message : %s',
2026-10-02 12:09:46 +02:00
$result['code'] ?? 'Undefined',
$result['message'] ?? 'Undefined'
2023-12-12 14:56:12 +01:00
)
);
2026-10-02 12:09:46 +02:00
} catch (RuntimeException $e) {
2023-12-12 14:56:12 +01:00
report($e);
// * Retenter ?
back()->with('error', trans('front.messages.unexpected_error_try_later'))->throwResponse();
2026-10-02 12:09:46 +02:00
} // end try
}
2022-01-11 10:26:06 +01:00
/**
2023-12-08 18:55:55 +01:00
* Assert that user has enough info filled on his profile to win a Discount
* Or redirect him to the fill form
* ! Also validates its birth date (because beeing an adult is required to participate)
2022-01-11 10:26:06 +01:00
*
2026-10-02 12:09:46 +02:00
* @throws HttpResponseException If customer data doest not validate
* or and error occurs.
2022-01-11 10:26:06 +01:00
*/
2024-01-29 11:28:52 +00:00
private function assertUserHasEnoughInfoToUseMesBr(): void
2021-08-18 17:08:02 +02:00
{
2023-12-12 12:25:45 +01:00
// * Valider que le client dispose des donnés requises pour MesBr
2023-12-08 18:55:55 +01:00
try {
2026-10-02 12:09:46 +02:00
/** @var Customer */
2023-12-08 18:55:55 +01:00
$authUser = auth('frontend')->user();
$crmCustomer = $this->crmRepository->fetchCrmCustomer($authUser);
2023-12-08 18:55:55 +01:00
// * On valide les données selon les critères du site
2026-10-02 12:09:46 +02:00
$rules = collect(new CreateAccountRequest()->rules());
2023-12-08 18:55:55 +01:00
Validator::make(
[
2026-10-02 12:09:46 +02:00
'birth_date' => $crmCustomer->birth_date,
'address' => $crmCustomer->address,
'postal_code' => $crmCustomer->postcode,
2026-10-02 12:09:46 +02:00
'country' => $crmCustomer->country->value,
'city' => $crmCustomer->city,
2023-12-08 18:55:55 +01:00
],
[
2026-10-02 12:09:46 +02:00
'birth_date' => $rules->get('birth_date'),
'address' => $rules->get('address'),
'postal_code' => $rules->get('postal_code'),
2026-10-02 12:09:46 +02:00
'country' => $rules->get('country'),
'city' => $rules->get('city'),
2023-12-08 18:55:55 +01:00
]
)->validate();
Session::remove('needCrmInfoUpdate');
} catch (ValidationException) {
response()->redirectToRoute('fo.profil.verify')
->with('warning', trans(
'front.messages.profile_incomplete_cannot_play'
2023-12-08 18:55:55 +01:00
))->throwResponse();
2026-10-02 12:09:46 +02:00
} catch (Exception $e) {
2023-12-08 18:55:55 +01:00
report($e);
// * Retenter ?
response()->redirectToRoute('fo.homepage')
->with('error', trans('front.messages.unexpected_error_try_later'))
2023-12-08 18:55:55 +01:00
->throwResponse();
2026-10-02 12:09:46 +02:00
} // end try
}
2023-12-08 18:55:55 +01:00
// * --- END PRIVATE METHODS ---
2020-10-29 15:40:23 +01:00
}