crmRepository = new CrmRepository(); $this->middleware(function (Request $request, callable $next) { $this->authorize('fo.gameEnabled'); $this->assertUserHasEnoughInfoToUseMesBr(); return $next($request); }); } /** * Display participation form */ public function participate(): View { if (! Gate::check('participate', Participation::class)) { /** @var view-string $view */ $view = 'theme::pages.participation.participation-exhausted'; return view($view); } /** @var view-string $view */ $view = 'theme::pages.participation.participate'; return view($view); } /** * Participate Method */ public function participateSubmit(ParticipateRequest $request): View { return DB::transaction(function () use ($request) { // ! On verrouille le ou les instants gagnant /** @var InstantWin|null */ $instantWin = InstantWin::query()->lockForUpdate() ->where('available_at', '<', now()) ->whereDoesntHave('participation') ->get()->sortBy('available_at')->first(); /** @var Settings */ $settings = resolve(Settings::class); /** @var Customer */ $customer = auth('frontend')->user(); /** @var Code|null */ $code = $request->post('unique_code'); /** @var Product|null */ $product = $request->post('product'); // * Make new participation $participation = Participation::makeNew( resolve('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) || ! $instantWin) { // * --- DISCOUNT WIN --- // ? Les BR sont activés ? if (! $settings->discounts_activated) { // * On enregistre la participation du joueur. $participation->save(); /** @var view-string $view Pas de coupons disponibles, le joueur à perdu. */ $view = 'theme::pages.participation.loose'; return view($view); } // * 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 = (string) $discount->web_coupon_identifiant; // * On enregistre la participation du joueur. $participation->save(); $crmCustomer = $this->crmRepository->fetchCrmCustomer($customer); $customer->notify(new HasWonDiscount( $discount, $crmCustomer->firstname )); /** @var view-string $view */ $view = 'theme::pages.participation.won'; return view($view, ['discount' => $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, $code?->code_unique, $product?->ean_code )); /** @var view-string $view */ $view = 'theme::pages.participation.won'; return view($view, [ 'prizeModel' => $instantWin->prize, 'participationModel' => $participation, 'crmCustomer' => $crmCustomer, ]); }); } // * --- PRIVATE METHODS --- /** * Try Call CRM + MesBr to setup discount * * @throws HttpResponseException If Any error occurs. * * @phpcs:disable Generic.Metrics.CyclomaticComplexity */ 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 Settings */ $settings = resolve(Settings::class); /** @var MesBr */ $mesBr = resolve('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.. */ /** @var object|null $result */ $result = $mesBr->updateCustomer($crmUser->hashcode, $crmUser->email, $crmUser->country->label()); if ($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 */ $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', ); 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 } /** * 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) * * @throws 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 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 --- }