middleware(function (Request $request, callable $next) { $this->assertUserHasEnoughInfoToUseMesBr(); return $next($request); }); } /** * Display participation form * * @return \Illuminate\Contracts\View\View */ public function participate(): View { if (!Gate::check('participate', Participation::class)) { return view('theme::pages.participation-exhausted'); } return view('theme::pages.enter-code'); } /** * Participate Method * * @param \App\Http\Requests\Fo\ParticipateRequest $request * @return \Illuminate\Contracts\View\View */ public function participateSubmit(ParticipateRequest $request): 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()) ->where('won', false) ->get()->sortBy('available_at', 'ASC')->first(); /** @var \App\Models\Settings */ $settings = app(Settings::class); /** @var \App\Models\Customer */ $customer = auth('frontend')->user(); /** @var \App\Models\Code */ $code = $request->post('code'); /** @var \App\Models\Product|null */ $product = $request->post('code'); // * 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. if (Participation::customerAlreadyHasAnInstantWin($customer) or !$instantWin) { // ? 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. $responseView = $this->serveCouponWin($settings, $participation); // * On enregistre la participation du joueur. $participation->save(); return $responseView; } // * Le joueur à remporté un instant gagnant // Ici si fail car unique dupliqué catch. try { // Gain d'un gros lot. $this->instantWin($request, $participation, $instantWin); return view( 'theme::pages.participation.won_prize', compact('settings') )->with('prize', $instantWin->prize); } catch (\ErrorException $e) { // Unbind instant gagnant. $participation->instantWin()->delete(); // phpcs:ignore // TODO: si erreur il faut envoyer un mail à equipe.web@ldc.fr. } //end try }); } /** * Undocumented function * * @return \Illuminate\Http\Response */ public function formWinningProof() { $participation = Participation::where([ ['user_id', Auth::user()->id], ['sticker', null], ['ticket', null], ['barcode', null] ])->has('instantWin')->first(); if ($participation) { return view('theme::winning-proof', compact('participation')); } return redirect()->route('fo.homepage'); } // * --- PRIVATE METHODS --- /** * Handle instant wins * * @param string $serial * @param \App\Models\Participation $participation * @param \App\Models\InstantWin|null $instantWin * @return void */ private function instantWin( string $serial, Participation $participation, InstantWin|null $instantWin ): void { /** @var \App\Models\Settings */ $settings = app(Settings::class); $instantWin->won = true; // Should save now to prevent next player win on the same winning moment. $instantWin->save(); $participation->instantWin()->save($instantWin); // Envoi du courrier Arcadia. if ( $instantWin->prize->arcadia_operation_code !== 0 && $instantWin->prize->arcadia_support_code !== 0 ) { $crmId = auth('backend')->user()->crm_id; $fields = [ 'root' => [ [ 'fieldName' => 'order_date', 'fieldValue' => date('d/m/Y') ], [ 'fieldName' => 'operation', 'fieldValue' => $instantWin->prize->arcadia_operation_code ] ], 'orderLine' => [ [ 'fieldName' => 'code_unique', 'fieldValue' => $request->serial ], [ 'fieldName' => 'support_code', 'fieldValue' => $instantWin->prize->arcadia_support_code ], [ 'fieldName' => 'label_type_support', 'fieldValue' => 'Gain du lot : ' . $instantWin->prize->label ] ] ]; if ($settings->use_ean_codes === 1) { $codeEan = $request->code_ean; $fields['orderLine'][] = [ 'fieldName' => 'code_on_pack', 'fieldValue' => "$codeEan->code" ]; } $arcadiaMail = $this->apiCrm->ArcadiaOutgoingMail($crmId, $fields, 'game'); if ($arcadiaMail->status === 'KO') { Mail::to(config('mail.admin'))->send(new CourrierArcadiaError(auth('backend')->user())); } } //end if Mail::to(auth('backend')->user()->email)->send(new PrizeWon(auth('backend')->user(), $instantWin->prize, $settings)); $mails = json_decode($settings->notification_emails); foreach ($mails as $mail) { Mail::to($mail->email)->send(new NotifWinAdmin($settings, $participation)); } $participation->save(); } /** * Détermine si un BR doit être servi * renvoi la vue de gain BR ou la vue "Perdu" * * @param \App\Models\Settings $settings The game settings. * @param \App\Models\Participation $participation The actual participation * * @return \Illuminate\Contracts\View\View */ private function serveCouponWin(Settings $settings, Participation $participation): View { /** @var \App\Lib\Discount */ $discount = Arr::get( $settings->web_coupons, $this->getRandomWeightedElementIndex($settings->web_coupons) ); // return response((new DiscountWonMail( // new Address( // $user->email, // $user->first_name // ), // $settings->name, // $discount, // config('app.url') // ))->render()); $crmCoupon = $this->setDiscountAsWon($discount); // * On associe le coupon à la participation $participation->discount()->associate($discount); if (!$crmCoupon) { $participation->delete(); return back()->withErrors("Une erreur est survenue, merci de réessayez ultérieurement."); } Mail::to(Auth::user()->email)->send(new DiscountWonMail(Auth::user(), $coupon, $settings, $crmCoupon)); return view('theme::discount', compact('crmCoupon', 'coupon')); } /** * Try Call CRM + MesBr to setup disount * * @param \App\Models\Customer $customer * @param \App\Models\Discount $discount * @return void * @throws \Illuminate\Http\Exceptions\HttpResponseException * @throws \Psr\Container\NotFoundExceptionInterface * @throws \Psr\Container\ContainerExceptionInterface * @throws \InvalidArgumentException * @throws \Illuminate\Database\Eloquent\InvalidCastException */ private function setDiscountAsWon(Customer $customer, Discount $discount): void { // * Phase - 1 Recupération des informations CRM /** @var \LDC\LDCCRM\Models\Customer|null */ $crmUser = null; try { $crmUser = $customer->api_data; // ? Le compte du joueur est vérifié ? if (!$crmUser->status) { // * Le joueur doit avoir un compte vérifié pour participer. response()->redirectToRoute('fo.verification.notice') ->with('error', trans('Pour participer votre compte doit être activé')) ->throwResponse(); } } catch (ApiErrorException $e) { // * Customer is not found. if ($e->getApiError()->equals(ApiError::modelNotFound())) { // * Déconnexion immédiate et retour maison. auth('frontend')->logout(); response()->redirectToRoute('fo.home') ->with('error', trans('Une erreur est survenue, compte introuvable.')) ->throwResponse(); } report($e); Log::error('Unhandled response ' . $e->getApiError()->label); // * Retenter ? back()->with('error', trans('Une erreur est survenue, veuillez réssayer.'))->throwResponse(); } catch (CrmException | \Exception $e) { report($e); // * Retenter ? back()->with('error', trans('Une erreur est survenue, veuillez réssayer.'))->throwResponse(); } //end try // * Phase - 2 Mise à jour du coupon dans MesBr /** @var \LDCWEB\MesBR */ $mesBR = app('mesBrAPI'); $mesBR->updateCustomer($crmUser->user); $result = $mesBR->updatePanier($crmUser->user, $discount); if ($result["status"] === "OK") { $discount = new Discount(); $discount->link = $result["link"]; $discount->verification = $result["verif"]; $discount->basket_id = $result["basketId"]; $discount->save(); } else { Mail::to(config('mail.admin')) ->send(new NotifAdmin(\sprintf( 'MESBR : Une erreur est survenue. Code : %s Message : %s', $result["code"], $result["message"] ))); } // return $discount; } /** * 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() { // * Valider que le client dispose des donnés requises pour MesBR try { /** @var \App\Models\Customer */ $authUser = auth('frontend')->user(); $crmCustomer = $authUser->api_data; // * 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, 'postcode' => $crmCustomer->postcode, 'country' => $crmCustomer->country->value, 'city' => $crmCustomer->city ], [ 'birth_date' => $rules->get('birth_date'), 'address' => $rules->get('address'), 'postcode' => $rules->get('postcode'), 'country' => $rules->get('country'), 'city' => $rules->get('city') ] )->validate(); Session::remove('needCrmInfoUpdate'); } catch (ValidationException) { response()->redirectToRoute('fo.profil.verify') ->with('warning', trans( 'Vous devez compléter des informations sur votre profil pour pouvoir participer.' ))->throwResponse(); } catch (\Exception $e) { report($e); // * Retenter ? response()->redirectToRoute('fo.homepage') ->with('error', trans('Une erreur est survenue, veuillez réssayer.')) ->throwResponse(); } //end try } // * --- END PRIVATE METHODS --- }