crmRepository = new CrmRepository(); $this->middleware(function (Request $request, callable $next) { $this->authorize('fo.gameEnabled'); $this->assertUserHasEnoughInfoToUseMesBr(); return $next($request); }); } /** * Display participation form * * @return \Illuminate\Contracts\View\View */ public function participate(): \Illuminate\Contracts\View\View { if (!Gate::check('participate', Participation::class)) { return view('theme::pages.participation.participation-exhausted'); } return view('theme::pages.participation.participate'); } /** * Participate Method * * @param \App\Http\Requests\Fo\ParticipateRequest $request * @return \Illuminate\Contracts\View\View */ public function participateSubmit(ParticipateRequest $request): \Illuminate\Contracts\View\View { return DB::transaction(function () use ($request) { // ! On verrouille le ou les instants gagnant /** @var \App\Models\InstantWin|null */ $instantWin = InstantWin::query()->lockForUpdate() ->where('available_at', '<', now()) ->whereDoesntHave('participation') ->get()->sortBy('available_at')->first(); /** @var \App\Models\Settings */ $settings = app(Settings::class); /** @var \App\Models\Customer */ $customer = auth('frontend')->user(); /** @var \App\Models\Code|null */ $code = $request->post('unique_code'); /** @var \App\Models\Product|null */ $product = $request->post('product'); // * Make new participation $participation = Participation::makeNew( app('clientIp'), $customer, $code, $product ); // * Si l'utilisateur actuel à déjà gagné un gros lot, pas d'instant gagnant. // ? As-t-on un instant gagnant ? if (Participation::customerAlreadyHasAnInstantWin($customer) or !$instantWin) { // * --- DISCOUNT WIN --- // ? Les BR sont activés ? if (!$settings->discounts_activated) { // * On enregistre la participation du joueur. $participation->save(); // * Pas de coupons disponibles, le joueur à perdu return view('theme::pages.participation.loose'); } // * Le joueur à gagné un coupon. /** @var \App\Lib\Discount Coupon aléatoire en fonction du ratio de chaque coupon */ $discount = Arr::get( $settings->web_coupons, $this->getRandomWeightedElementIndex($settings->web_coupons) ); $this->setDiscountAsWon($customer, $discount); // * Le joueur à remporté un coupon $participation->discount_code = $discount->web_coupon_identifiant; // * On enregistre la participation du joueur. $participation->save(); $crmCustomer = $this->crmRepository->fetchCrmCustomer($customer); $customer->notify(new HasWonDiscount( $discount, $crmCustomer->firstname )); return view('theme::pages.participation.won', compact('discount')); } //end if // * --- INSTANT WIN --- // * On enregistre la participation du joueur. $participation->save(); // * Le joueur à remporté un instant gagnant $instantWin->participation()->associate($participation); $instantWin->save(); $crmCustomer = $this->crmRepository->fetchCrmCustomer($customer); // * Notify customer for his win $customer->notify(new HasWonInstantWin( $instantWin->prize, $crmCustomer->firstname )); // * Dispatch notification to mail list Mail::to($settings->notification_emails)->send(new PrizeWonAdminMail( $settings->name, $participation->created_at, $instantWin->prize->label, $crmCustomer, optional($code)->code_unique, optional($product)->ean_code )); return view('theme::pages.participation.won', [ 'prizeModel' => $instantWin->prize, 'participationModel' => $participation, 'crmCustomer' => $crmCustomer ]); }); } // * --- PRIVATE METHODS --- /** * Try Call CRM + MesBr to setup discount * * @param \App\Models\Customer $customer * @param LibDiscount $discount * @return void * @throws \Illuminate\Http\Exceptions\HttpResponseException If Any error occurs. * @phpcs:disable Squiz.Commenting.FunctionCommentThrowTag.WrongNumber */ private function setDiscountAsWon(Customer $customer, LibDiscount $discount): void { // phpcs:enable // * Phase - 1 Recupération des informations CRM /** @var \LDC\LDCCRM\Models\Customer*/ $crmUser = $this->crmRepository->fetchCrmCustomer($customer); // * Phase - 2 Mise à jour du coupon dans MesBr try { /** @var \App\Models\Settings */ $settings = app(Settings::class); /** @var \LDC\MESBR\MesBr */ $mesBr = app('mesBrAPI'); // * MaJ Customer /** @var string */ $crm_customer_hashcode = retry(3, function () use ($mesBr, $crmUser) { /** * 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.. */ $result = $mesBr->updateCustomer($crmUser->hashcode, $crmUser->email, $crmUser->country->label()); if (optional($result)->status !== "OK") { throw new \RuntimeException( \sprintf( 'MESBR : Une erreur est survenue. Code : %s Message : %s', $result->code ?? 'Undefined', $result->message ?? 'Undefined' ) ); } /** @var object|null */ $crm_customer = optional($result)->customer; if (empty(optional($crm_customer)->hashcode)) { throw new \RuntimeException( 'MESBR : Une erreur est survenue. Update Customer n\'as pas retourné le customer hashcode' ); } return $crm_customer->hashcode; }, 100); // * Maj Panier $result = $mesBr->updateBasket( $crmUser, strval($discount->web_coupon_identifiant) ); if (Arr::get($result, 'status') === "OK") { // * La réponse est conforme ? $needed_fields = ['ref']; if (!Arr::has($result, $needed_fields)) { throw new \RuntimeException(sprintf( 'MESBR : Il manques des champs dans la réponse, attendu => %s, donné => %s', json_encode($needed_fields), json_encode($result), )); } // * Tout est OK return; } throw new \RuntimeException( \sprintf( 'MESBR : Une erreur est survenue. Code : %s Message : %s', $result["code"] ?? 'Undefined', $result["message"] ?? 'Undefined' ) ); } catch (\RuntimeException $e) { report($e); // * Retenter ? back()->with('error', trans('front.messages.unexpected_error_try_later'))->throwResponse(); } //end try throw new \Error('Should not reach this point'); } /** * 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) * * @return void * @throws \Illuminate\Http\Exceptions\HttpResponseException If customer data doest not validate * or and error occurs. */ private function assertUserHasEnoughInfoToUseMesBr(): void { // * Valider que le client dispose des donnés requises pour MesBr try { /** @var \App\Models\Customer */ $authUser = auth('frontend')->user(); $crmCustomer = $this->crmRepository->fetchCrmCustomer($authUser); // * On valide les données selon les critères du site $rules = collect((new CreateAccountRequest())->rules()); Validator::make( [ 'birth_date' => $crmCustomer->birth_date, 'address' => $crmCustomer->address, 'postal_code' => $crmCustomer->postcode, 'country' => $crmCustomer->country->value, 'city' => $crmCustomer->city ], [ 'birth_date' => $rules->get('birth_date'), 'address' => $rules->get('address'), 'postal_code' => $rules->get('postal_code'), 'country' => $rules->get('country'), 'city' => $rules->get('city') ] )->validate(); Session::remove('needCrmInfoUpdate'); } catch (ValidationException) { response()->redirectToRoute('fo.profil.verify') ->with('warning', trans( 'front.messages.profile_incomplete_cannot_play' ))->throwResponse(); } catch (\Exception $e) { report($e); // * Retenter ? response()->redirectToRoute('fo.homepage') ->with('error', trans('front.messages.unexpected_error_try_later')) ->throwResponse(); } //end try } // * --- END PRIVATE METHODS --- }