diff --git a/README.md b/README.md index fd54e62..2e40608 100644 --- a/README.md +++ b/README.md @@ -32,5 +32,5 @@ sur le job de generation des codes. ## Améliorations possibles - Empecher de supprimer des lots si le jeu est démarré ? -- Permettre à une personne d'acceder à ses gains (formulaire si non complété, ou br si non télechargé) +- Permettre à une personne d'acceder à ses gains (formulaire si non complété, ou br si non télechargé) en étant connecté via un lien sur le front (lien + formulaires) diff --git a/app/Http/Controllers/Bo/InstantWinController.php b/app/Http/Controllers/Bo/InstantWinController.php index fef5410..7270311 100644 --- a/app/Http/Controllers/Bo/InstantWinController.php +++ b/app/Http/Controllers/Bo/InstantWinController.php @@ -28,7 +28,7 @@ class InstantWinController extends Controller */ public function index(): \Illuminate\Contracts\View\View { - $instantWinModelList = InstantWin::query()->orderBy('appear_date')->get(); + $instantWinModelList = InstantWin::query()->orderBy('available_at')->get(); return view('back::pages.instant-win.index', [ 'instantWinModelList' => $instantWinModelList @@ -97,8 +97,8 @@ class InstantWinController extends Controller // * Save Instant wins $this->generateArray($lotsGlobal, $datesGlobal, 0)->each(function (WinDayCalendar $winDayCalendar) { $winDayCalendar->lots->each(function (WinTimeElement $winTimeElement) { - $instantWin = new InstantWin(); - $instantWin->appear_date = $winTimeElement->time; + $instantWin = new InstantWin(); + $instantWin->available_at = $winTimeElement->time; $instantWin->prize()->associate($winTimeElement->prize); $instantWin->saveOrFail(); }); diff --git a/app/Http/Controllers/Bo/Re7Controller.php b/app/Http/Controllers/Bo/Re7Controller.php index 0c2fef4..24eae87 100644 --- a/app/Http/Controllers/Bo/Re7Controller.php +++ b/app/Http/Controllers/Bo/Re7Controller.php @@ -7,7 +7,7 @@ use App\Mail\Won\DiscountWonMail; use App\Mail\Won\PrizeWonMail; use App\Models\Prize; use App\Models\Settings; -use App\Models\Reduction; +use App\Models\Discount; use Illuminate\Contracts\View\View; use Illuminate\Http\Request; use Illuminate\Http\Response; @@ -79,11 +79,11 @@ class Re7Controller extends Controller $this->getRandomWeightedElementIndex($settings->web_coupons) ); - if (!$settings->reductions_activated) { + if (!$settings->discounts_activated) { return abort(404); } - $crmCoupon = new Reduction(); + $crmCoupon = new Discount(); return view('theme::pages.participation.won', compact('discount', 'crmCoupon')); } @@ -124,7 +124,7 @@ class Re7Controller extends Controller { /** @var \App\Models\Settings */ $settings = app(Settings::class); - if (!$settings->reductions_activated) { + if (!$settings->discounts_activated) { return abort(404); } @@ -181,30 +181,4 @@ class Re7Controller extends Controller return response('', 404); } //end switch } - - /** - * Utility function for getting random values with weighting. - * Pass in an associative array, such as array('A'=>5, 'B'=>45, 'C'=>50) - * An array like this means that "A" has a 5% chance of being selected, "B" 45%, and "C" 50%. - * The return value is the array key, A, B, or C in this case. Note that the values assigned - * do not have to be percentages. The values are simply relative to each other. If one value - * weight was 2, and the other weight of 1, the value with the weight of 2 has about a 66% - * chance of being selected. Also note that weights should be integers. - * - * @param array<\App\Lib\Discount> $weightedValues - * @return integer The winning key - * @url https://stackoverflow.com/a/11872928/4355295 - */ - private function getRandomWeightedElementIndex(array $weightedValues): int - { - mt_srand(time()); - $rand = mt_rand(1, max((int)collect($weightedValues)->sum('percentage'), 1)); - - foreach ($weightedValues as $key => $value) { - $rand -= $value->percentage; - if ($rand <= 0) { - return $key; - } - } - } } diff --git a/app/Http/Controllers/Controller.php b/app/Http/Controllers/Controller.php index 9461a60..6284b83 100644 --- a/app/Http/Controllers/Controller.php +++ b/app/Http/Controllers/Controller.php @@ -20,6 +20,33 @@ class Controller extends BaseController use AuthorizesRequests; use ValidatesRequests; + + /** + * Utility function for getting random values with weighting. + * Pass in an associative array, such as array('A'=>5, 'B'=>45, 'C'=>50) + * An array like this means that "A" has a 5% chance of being selected, "B" 45%, and "C" 50%. + * The return value is the array key, A, B, or C in this case. Note that the values assigned + * do not have to be percentages. The values are simply relative to each other. If one value + * weight was 2, and the other weight of 1, the value with the weight of 2 has about a 66% + * chance of being selected. Also note that weights should be integers. + * + * @param array<\App\Lib\Discount> $weightedValues + * @return integer The winning key + * @url https://stackoverflow.com/a/11872928/4355295 + */ + protected function getRandomWeightedElementIndex(array $weightedValues): int + { + mt_srand(time()); + $rand = mt_rand(1, max((int)collect($weightedValues)->sum('percentage'), 1)); + + foreach ($weightedValues as $key => $value) { + $rand -= $value->percentage; + if ($rand <= 0) { + return $key; + } + } + } + /** * Gives the redirection path for FO Auth controllers * diff --git a/app/Http/Controllers/Fo/ParticipateController.php b/app/Http/Controllers/Fo/ParticipateController.php index bc35167..3e8f02d 100644 --- a/app/Http/Controllers/Fo/ParticipateController.php +++ b/app/Http/Controllers/Fo/ParticipateController.php @@ -10,117 +10,133 @@ use App\Mail\NotifWinAdmin; use App\Mail\PrizeWon; use App\Mail\DiscountWonMail; use App\Models\BannedIp; +use App\Models\Customer; use App\Models\InstantWin; use App\Models\Participation; -use App\Models\Reduction; +use App\Models\Discount; use LDCWeb\MesBR; use App\Models\Settings; +use Illuminate\Contracts\View\View; +use Illuminate\Database\Eloquent\Builder; use Illuminate\Http\Request; +use Illuminate\Support\Arr; use Illuminate\Support\Facades\Auth; +use Illuminate\Support\Facades\DB; +use Illuminate\Support\Facades\Gate; +use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Mail; +use LDC\LDCCRM\Enums\ApiError; +use LDC\LDCCRM\Exceptions\ApiErrorException; +use LDC\LDCCRM\Exceptions\CrmException; class ParticipateController extends Controller { /** + * Display participation form * - * @var \LDCCRM\ApiV1 + * @return \Illuminate\Contracts\View\View */ - private $apiCrm; - - /** - * EnterCodeController - */ - public function __construct() + public function participate(): View { - // $this->apiCrm = new \LDCCRM\ApiV1(config('crm.endpoint'), config('crm.token')); - } - - /** - * Show enter code form - * - * @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory - */ - public function participate() - { - // $nbParticipations = Participation::where('user_id', Auth::user()->id)->count(); - /** @var \App\Models\Settings */ - $settings = app(Settings::class); - // if ($nbParticipations >= $settings->nb_participation_player) { - // return view('theme::participation-exhausted', compact('settings')); - // } - return view('theme::enter-code', compact('settings')); + 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|\Illuminate\Contracts\View\Factory + * @return \Illuminate\Contracts\View\View */ - public function participateSubmit(ParticipateRequest $request) + public function participateSubmit(ParticipateRequest $request): View { - // Récupération des données à utilisées. - /** @var \App\Models\Settings $settings */ - $settings = app(Settings::class); - - // * Cas IP bannie. - if (BannedIp::query()->where('ip', app('clientIp'))->exists()) { - return view('theme::participation-exhausted', compact('settings')); + if (Gate::check('participate', Participation::class)) { + return view('theme::pages.participation-exhausted'); } - // * Cas nombre de participation maximale atteint. - $nbParticipations = Participation::where('user_id', auth('backend')->user()->id)->count(); - if ($nbParticipations >= $settings->nb_participation_player) { - return view('theme::participation-exhausted', compact('settings')); - } + 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(); - // * Tous les cas "bloquants" sont passé, l'utilisateur participe à partir d'ici. - $participation = new Participation(); - $participation->user_id = auth('backend')->user()->id; - $participation->code_unique_id = $request->code->id; - $participation->code_ean_id = $request->code_ean ? $request->code_ean->id : null; - $participation->ip = app('clientIp'); - $participation->save(); + /** @var \App\Models\Settings */ + $settings = app(Settings::class); - // * Gestion des instants gagnants. - $userAlreadyWon = Participation::has('instantWin') - ->whereHas('user', function ($q) { - $q->whereId(auth('backend')->user()->id); - })->first(); + /** @var \App\Models\Customer */ + $customer = auth('frontend')->user(); - // * Si l'utilisateur actuel à déjà gagné un gros lot, pas d'instant gagnant. - if ($userAlreadyWon) { - return $this->serveCouponWin($settings, $participation); - } + /** @var \App\Models\Code */ + $code = $request->post('code'); + /** @var \App\Models\Product|null */ + $product = $request->post('code'); - $instantWin = InstantWin::where([['appear_date', '<', now()], ['won', 0]]) - ->orderBy('appear_date', 'ASC')->first(); - if ($instantWin) { + // * 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. - return $this->instantWin($settings, $request, $participation, $instantWin); + $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 - } - return $this->serveCouponWin($settings, $participation); + }); } /** * Handle instant wins * - * @param Settings $settings - * @param Request $request - * @param Participation $participation - * @param InstantWin|null $instantWin - * @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory + * @param string $serial + * @param \App\Models\Participation $participation + * @param \App\Models\InstantWin|null $instantWin + * @return void */ - private function instantWin(Settings $settings, Request $request, Participation &$participation, $instantWin) - { + 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(); @@ -179,96 +195,120 @@ class ParticipateController extends Controller Mail::to($mail->email)->send(new NotifWinAdmin($settings, $participation)); } $participation->save(); - return view('theme::pages.participation.won_prize', compact('settings')) - ->with('prize', $instantWin->prize); } /** * Détermine si un BR doit être servi * renvoi la vue de gain BR ou la vue "Perdu" * - * @param Settings $settings - * @param Participation $participation - * @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory + * @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) + private function serveCouponWin(Settings $settings, Participation $participation): View { - // Si le jeu est 100% gagnant. - if ($settings->reductions_activated === 1) { - $coupon = $this->getRandomCoupon($settings); - $crmCoupon = $this->updateCoupon($settings, $coupon->web_coupon_identifiant, $participation); - 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::reduction', compact('crmCoupon', 'coupon')); - } else { - return view('theme::loose'); + /** @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')); } /** - * Get a random coupon + * Try Call CRM + MesBr to setup disount * - * @param Settings $settings - * @return mixed + * @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 getRandomCoupon(Settings $settings) + private function setDiscountAsWon(Customer $customer, Discount $discount): void { - $webCoupons = json_decode($settings->web_coupons); - if (count($webCoupons) > 1) { - $lots = []; - foreach ($webCoupons as $webCoupon) { - $lots[] = $webCoupon; + // * 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(); } - foreach ($lots as $lot) { - for ($i = 0; $i < $lot->percentage; $i++) { - $tmp[] = $lot; - } + } 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(); } - shuffle($tmp); - return $tmp[0]; + 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 { - return $webCoupons[0]; + Mail::to(config('mail.admin')) + ->send(new NotifAdmin(\sprintf( + 'MESBR : Une erreur est survenue. Code : %s Message : %s', + $result["code"], + $result["message"] + ))); } - } - /** - * Update a coupon - * - * @param Settings $settings - * @param mixed $coupon - * @param Participation $participation - * @return \App\Models\Reduction|null - */ - private function updateCoupon(Settings $settings, mixed $coupon, Participation $participation) - { - $reduction = null; - $mesBR = new MesBR(config('mesbr.endpoint'), $settings->reductions_site, $settings->reductions_campaign); - - $crmUser = $this->apiCrm->getCustomer(Auth::user()->crm_id); - if ($crmUser->status === 'OK') { - $mesBR->updateContact($crmUser->user); - $result = $mesBR->updatePanier($crmUser->user, $coupon); - if ($result["status"] === "OK") { - $reduction = new Reduction(); - $reduction->link = $result["link"]; - $reduction->verification = $result["verif"]; - $reduction->basket_id = $result["basketId"]; - $reduction->save(); - $participation->reduction_id = $reduction->id; - $participation->save(); - } else { - Mail::to(config('mail.admin')) - ->send(new NotifAdmin(\sprintf( - 'MESBR : Une erreur est survenue. Code : %s Message : %s', - $result["code"], - $result["message"] - ))); - } - } //end if - return $reduction; + // return $discount; } /** diff --git a/app/Http/Requests/Bo/Settings/UpdateSettingsRequest.php b/app/Http/Requests/Bo/Settings/UpdateSettingsRequest.php index 1629eab..4b8cb50 100644 --- a/app/Http/Requests/Bo/Settings/UpdateSettingsRequest.php +++ b/app/Http/Requests/Bo/Settings/UpdateSettingsRequest.php @@ -33,16 +33,16 @@ class UpdateSettingsRequest extends FormRequest 'use_ean_codes' => $this->boolean('use_ean_codes'), 'activated_teaser' => $this->boolean('activated_teaser'), 'activated_close_page' => $this->boolean('activated_close_page'), - 'reductions_activated' => $this->boolean('reductions_activated'), + 'discounts_activated' => $this->boolean('discounts_activated'), 'winning_proof' => $this->boolean('winning_proof'), // Arrays. 'notification_emails' => collect($this->input('notification_emails'))->filter()->all(), // Remove some dates if the checkbox is uncheck. 'close_page_active_date' => $this->input('activated_close_page') ? $this->input('close_page_active_date') : null, - // Remove reductions datas if the reduction checkbox is uncheck. - 'reductions_site' => $this->input('reductions_activated') ? $this->input('reductions_site') : null, - 'reductions_campaign' => $this->input('reductions_activated') ? $this->input('reductions_campaign') : null, + // Remove discounts datas if the discount checkbox is uncheck. + 'discounts_site' => $this->input('discounts_activated') ? $this->input('discounts_site') : null, + 'discounts_campaign' => $this->input('discounts_activated') ? $this->input('discounts_campaign') : null, 'web_coupons' => collect($this->input('web_coupons'))->filter()->all(), ]); } @@ -69,13 +69,13 @@ class UpdateSettingsRequest extends FormRequest 'close_page_active_date' => 'nullable|required_if:activated_close_page,true,1|date|after_or_equal:today', 'redirect_close' => 'required|url:http,https', - 'reductions_activated' => 'required|boolean', - 'reductions_site' => 'nullable|required_if:reductions_activated,true,1|string|min:3|max:255', - 'reductions_campaign' => 'nullable|required_if:reductions_activated,true,1|string|min:3|max:255', + 'discounts_activated' => 'required|boolean', + 'discounts_site' => 'nullable|required_if:discounts_activated,true,1|string|min:3|max:255', + 'discounts_campaign' => 'nullable|required_if:discounts_activated,true,1|string|min:3|max:255', 'web_coupons' => [ 'present', 'array', function ($attribute, $value, $fail) { - if ($this->post('reductions_activated') and !collect($value)->filter()->count()) { + if ($this->post('discounts_activated') and !collect($value)->filter()->count()) { $fail(trans('validation.min.array', [ 'attribute' => Arr::get($this->attributes(), $attribute), 'min' => 1 @@ -138,9 +138,9 @@ class UpdateSettingsRequest extends FormRequest 'close_page_active_date' => trans('validation.custom.close_page_active_date'), 'redirect_close' => trans('validation.custom.redirect_close'), 'winning_proof' => trans('validation.custom.winning_proof'), - 'reductions_activated' => trans('validation.custom.reductions_activated'), - 'reductions_site' => trans('validation.custom.reductions_site'), - 'reductions_campaign' => trans('validation.custom.reductions_campaign'), + 'discounts_activated' => trans('validation.custom.discounts_activated'), + 'discounts_site' => trans('validation.custom.discounts_site'), + 'discounts_campaign' => trans('validation.custom.discounts_campaign'), 'web_coupons' => trans('Tableau des coupons'), 'web_coupons.*.web_coupon_identifiant' => trans('Identifiant coupon :index'), diff --git a/app/Http/Requests/Fo/ParticipateRequest.php b/app/Http/Requests/Fo/ParticipateRequest.php index 65c77be..c4357c3 100644 --- a/app/Http/Requests/Fo/ParticipateRequest.php +++ b/app/Http/Requests/Fo/ParticipateRequest.php @@ -6,8 +6,9 @@ use App\Models\Code; use App\Models\Participation; use App\Models\Product; use App\Models\Settings; +use Illuminate\Contracts\Database\Eloquent\Builder; use Illuminate\Foundation\Http\FormRequest; -use Illuminate\Support\Facades\Validator; +use Illuminate\Support\Facades\Gate; use Illuminate\Support\Str; use Kwaadpepper\Serial\Exceptions\SerialCasterException; @@ -20,7 +21,7 @@ class ParticipateRequest extends FormRequest */ public function authorize() { - return auth('frontend')->check(); + return Gate::check('participate', Participation::class); } /** @@ -30,50 +31,21 @@ class ParticipateRequest extends FormRequest */ protected function prepareForValidation() { - /** - * * Check si les codes ean sont utilisés, auquel cas - * * on test celui envoyé pour savoir s'il est correct. - * Modif demande vincent : - * Tester code ean existe avec 13, puis 8 puis 7 chars - * Si le code EAN est trouvé dans la liste, alors on prend l'objet correspondant, - * sinon on prend le premier objet qui contient les 7 1er chiffres (cas des EAN pds) - * - * Dans la base chaque code ean doit être rentré dans sa valeur absolue - * càd que les code ean 8 sont de longueur 8, 7 de longueur7 et 13 de longueur 13. - */ - - /** @var \App\Models\Settings */ - $settings = app(Settings::class); - - if ($settings->use_ean_codes) { - // ! We need to validate ean is 13 before resolving ean code. - /** @throws \Illuminate\Validation\ValidationException */ - Validator::validate($this->all(), [ - 'code_ean' => 'required|digits:13' - ], $this->attributes()); - - // * Union pour faire des recherches séparée en une seule requête. - /** @var \App\Models\Product|null */ - $codeEan = Product::where('code_ean', $this->code_ean) - ->union(Product::where('code_ean', Str::limit($this->code_ean, 8, ''))) - ->union(Product::where('code_ean', Str::limit($this->code_ean, 7, ''))) - ->first() ?? false; - - $this->merge(['code_ean' => $codeEan]); - } //end if try { $this->merge([ - 'serial' => $this->code, - 'code' => Code::whereId(Code::serialToInt(Str::upper(\strval($this->code))))->first() ?? false, + 'code' => Code::query()->where('id', Code::serialToInt( + Str::upper(\strval($this->code)) + ))->first() ?? false, ]); - } catch (SerialCasterException $e) { + } catch (SerialCasterException) { // * Provoquer l'affichage code incorrect. $this->merge([ 'code' => false, ]); } finally { $this->merge([ - 'accept_rules' => $this->accept_rules ? true : false + 'code_ean' => (string)$this->string('code_ean')->padLeft(13, '0'), + 'accept_rules' => $this->boolean('accept_rules') ]); } } @@ -90,61 +62,80 @@ class ParticipateRequest extends FormRequest $rules = [ 'accept_rules' => 'required|boolean|accepted', - 'code' => [ + 'serial' => [ 'required', // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassBeforeLastUsed function ($attribute, $value, $fail) use ($settings) { - if ( - $value === false or - !\is_object($value) or - \get_class($value) !== Code::class - ) { - $fail('Code unique incorrect, veuillez réessayer.'); - return false; - } elseif ($value->code_used === 1) { - $fail('Ce code unique n\'est plus utilisable.'); - return false; + // ? Le Code unique est resolved ? + if ($value === false or !\is_object($value) or \get_class($value) !== Code::class) { + $fail(trans('Code unique incorrect, veuillez réessayer.')); + return; } + /** @var \App\Models\Code $value */ + // ? Code unique déjà trop utilisé ? + if ($value->code_used) { + $fail(trans('Ce code unique n\'est plus utilisable.')); + return; + } + + /** Request réutilisable */ + $participationQuery = Participation::query() + ->whereHas('code', fn (Builder $q) => $q->where('id', $value->id)); + + /** @var \App\Models\Customer */ + $customer = auth('frontend')->user(); // * Check si l'utilisateur n'a pas déjà utilisé ce code. - $query = Participation::where([ - ['code_unique_id', $this->code->id], - ['user_id', auth('backend')->user()->id] - ]); + $query = (clone $participationQuery)->whereHas( + 'customer', + fn (Builder $q) => $q->where('id', $customer->id) + ); + // ! Une seule participation avec un code donné par joueur if ($query->exists()) { - $fail('Vous avez déjà utilisé ce code unique.'); + $fail(trans('Vous avez déjà utilisé ce code unique.')); + return; } - $codeNbUsage = Participation::where('code_unique_id', $this->code->id) - ->count(); - // * Gestion du nombre d'utilisation d'un code. - if ($codeNbUsage >= $settings->nb_unique_code_use) { - $this->code->code_used = 1; - return back()->withErrors("Ce code unique n'est plus utilisable."); - } else { - if ($codeNbUsage + 1 >= $settings->nb_unique_code_use) { - $this->code->code_used = 1; - } + // ? Le code unique à été trop utilisé ? + if ((clone $participationQuery)->count() >= $settings->nb_unique_code_use) { + $value->code_used = true; + $value->saveOrFail(); + $fail(trans('Ce code unique n\'est plus utilisable.')); + return; } - $this->code->saveOrFail(); } ] ]; + /** + * * Check si les codes ean sont utilisés, auquel cas + * * on test celui envoyé pour savoir s'il est correct. + * Modif demande vincent : + * Tester code ean existe avec 13, puis 8 puis 7 chars + * Si le code EAN est trouvé dans la liste, alors on prend l'objet correspondant, + * sinon on prend le premier objet qui contient les 7 1er chiffres (cas des EAN pds) + * + * Dans la base chaque code ean doit être rentré dans sa valeur absolue + * càd que les code ean 8 sont de longueur 8, 7 de longueur7 et 13 de longueur 13. + */ + // ? Does the game use EAN Codes ? if ($settings->use_ean_codes) { - $rules = \array_merge($rules, [ - 'code_ean' => [ - 'required', - // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassBeforeLastUsed - function ($attribute, $value, $fail) { - if (!\is_object($value) or \get_class($value) !== Product::class) { - $fail('Le code barre entré est incorrect, veuillez réessayer.'); - } - } - ] + $rules = \array_merge($rules, ['code_ean' => [ + 'required', + // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassBeforeLastUsed + function ($attribute, $value, $fail) { + // * Union pour faire des recherches séparée en une seule requête. + // ! code_ean is already str_padded to 13 + $productQuery = Product::query()->where('code_ean', $this->post('code_ean')) + ->union(Product::where('code_ean', Str::limit($this->post('code_ean'), 8, ''))) + ->union(Product::where('code_ean', Str::limit($this->post('code_ean'), 7, ''))); - ]); + if (!$productQuery->exists()) { + $fail(trans('Le code barre entré est incorrect, veuillez réessayer.')); + } + } + ]]); } return $rules; } @@ -158,8 +149,8 @@ class ParticipateRequest extends FormRequest { return [ 'code_ean' => \trans('code barre'), + 'serial' => \trans('code unique'), 'accept_rules' => \trans('règlements du jeu'), - 'code' => \trans('code unique'), ]; } } diff --git a/app/Models/BannedIp.php b/app/Models/BannedIp.php index 20ac5d3..dff3cb4 100644 --- a/app/Models/BannedIp.php +++ b/app/Models/BannedIp.php @@ -3,6 +3,7 @@ namespace App\Models; use App\Casts\Ip; +use App\Traits\Models\IsCachedAsCollection; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; @@ -13,6 +14,7 @@ use Illuminate\Database\Eloquent\Model; */ class BannedIp extends Model { + use IsCachedAsCollection; use HasFactory; /** @@ -37,4 +39,18 @@ class BannedIp extends Model protected $casts = [ 'ip' => Ip::class ]; + + // * EVENTS + + /** + * Perform any actions required after the model boots. + * + * @return void + */ + protected static function booted() + { + static::created(fn () => self::removeCached()); + static::updated(fn () => self::removeCached()); + static::deleted(fn () => self::removeCached()); + } } diff --git a/app/Models/Code.php b/app/Models/Code.php index ad4ed15..f9ae192 100644 --- a/app/Models/Code.php +++ b/app/Models/Code.php @@ -8,9 +8,9 @@ use Kwaadpepper\Serial\SerialCaster; /** * Code. * - * @property boolean $code_used Is the code used ? + * @property boolean $code_used Is the code used too much ? * @property boolean $code_exported Is the code exported ? - * @property \Illuminate\Support\Carbon $date_creation Date of creation. + * @property \Illuminate\Support\Carbon $date_creation Code creation date. * * @property-read string|null $code_unique The unique code * diff --git a/app/Models/Reduction.php b/app/Models/Discount.php similarity index 94% rename from app/Models/Reduction.php rename to app/Models/Discount.php index f08c06e..70191cc 100644 --- a/app/Models/Reduction.php +++ b/app/Models/Discount.php @@ -5,7 +5,7 @@ namespace App\Models; use Illuminate\Database\Eloquent\Model; /** - * Reduction. + * Bon de réduction * * @property string $link Link * @property string $basket_id Basket id @@ -15,7 +15,7 @@ use Illuminate\Database\Eloquent\Model; * * @property-read \App\Models\Participation $participation Associated participation. */ -class Reduction extends Model +class Discount extends Model { // * RELATIONSHIPS diff --git a/app/Models/InstantWin.php b/app/Models/InstantWin.php index 8f63597..eb41644 100644 --- a/app/Models/InstantWin.php +++ b/app/Models/InstantWin.php @@ -7,8 +7,8 @@ use Illuminate\Database\Eloquent\Model; /** * InstantWin. * - * @property \Illuminate\Support\Carbon $appear_date Appear date - * @property boolean $won Is the prize won ? + * @property \Illuminate\Support\Carbon $available_at When the instant win will be available. + * @property boolean $won Is the prize won ? * * @property-read \App\Models\Prize $prize Associated prize. * @property-read \App\Models\Participation $participation Associated participation. diff --git a/app/Models/Participation.php b/app/Models/Participation.php index cfb318b..af0d109 100644 --- a/app/Models/Participation.php +++ b/app/Models/Participation.php @@ -2,8 +2,10 @@ namespace App\Models; +use Illuminate\Contracts\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Model; +use IPLib\Address\AddressInterface; /** * Participation. @@ -21,7 +23,7 @@ use Illuminate\Database\Eloquent\Model; * @property-read \App\Models\Code $code Associated code. * @property-read \App\Models\Product $product Associated product. * @property-read \App\Models\InstantWin $instantWin Associated instantWin. - * @property-read \App\Models\Reduction $reduction Associated reduction. + * @property-read \App\Models\Discount $discount Associated discount. */ class Participation extends Model { @@ -68,13 +70,13 @@ class Participation extends Model } /** - * One to one Reduction relation + * One to one Discount relation * * @return \Illuminate\Database\Eloquent\Relations\HasOne */ - public function reduction() + public function discount() { - return $this->hasOne(Reduction::class); + return $this->hasOne(Discount::class); } // * GETTERS @@ -90,4 +92,44 @@ class Participation extends Model get: fn () => optional($this->product)->code_ean, ); } + + // * METHODS + + /** + * Make new participation but do not persist on DB + * + * @param \IPLib\Address\AddressInterface $ip Ip for the participation. + * @param \App\Models\Customer $customer The Customer playing the game. + * @param \App\Models\Code $code The unique code used to play. + * @param null|\App\Models\Product $product The product that holds the sticker if codes are actived. + * @return \App\Models\Participation + */ + public static function makeNew( + AddressInterface $ip, + Customer $customer, + Code $code, + Product|null $product = null + ): self { + $self = new self(); + $self->ip = $ip; + $self->customer()->associate($customer); + $self->code()->associate($code); + if ($product) { + $self->product()->associate($product); + } + return $self; + } + + /** + * Check if a customer has already won + * + * @param \App\Models\Customer $customer + * @return boolean + */ + public static function customerAlreadyHasAnInstantWin(Customer $customer): bool + { + return self::query()->whereHas('instantWin') + ->whereHas('user', fn (Builder $q) => $q->where('id', $customer->id)) + ->exists(); + } } diff --git a/app/Models/Settings.php b/app/Models/Settings.php index 6202461..5bb4f9c 100644 --- a/app/Models/Settings.php +++ b/app/Models/Settings.php @@ -23,9 +23,9 @@ use Illuminate\Database\Eloquent\Model; * @property boolean $activated_close_page Is the close page active ? * @property \Illuminate\Support\Carbon $close_page_active_date End date of the close page * @property string $redirect_close Link to redirect when the game is ended - * @property boolean $reductions_activated Are the reductions active ? - * @property string $reductions_site Reduction site - * @property string $reductions_campaign Reduction campaign + * @property boolean $discounts_activated Are the discounts active ? + * @property string $discounts_site Discount MesBr site + * @property string $discounts_campaign Discount MesBr campaign * @property array<\App\Lib\Discount> $web_coupons Array of web coupons * @property array $notification_emails Array of email to notify when there's a winnner * @property boolean $winning_proof Is the winning proof needed @@ -54,9 +54,9 @@ class Settings extends Model 'activated_close_page', 'close_page_active_date', 'redirect_close', - 'reductions_activated', - 'reductions_site', - 'reductions_campaign', + 'discounts_activated', + 'discounts_site', + 'discounts_campaign', 'web_coupons', 'notification_emails', 'winning_proof', diff --git a/app/Policies/ParticipationPolicy.php b/app/Policies/ParticipationPolicy.php index a9eda01..a8a4469 100644 --- a/app/Policies/ParticipationPolicy.php +++ b/app/Policies/ParticipationPolicy.php @@ -3,8 +3,12 @@ namespace App\Policies; use App\Enums\Users\RoleEnum; +use App\Models\BannedIp; +use App\Models\Customer; +use App\Models\Participation; use App\Models\User; use App\Policies\Rules\UserStaticRules; +use Illuminate\Contracts\Database\Eloquent\Builder; class ParticipationPolicy { @@ -18,4 +22,24 @@ class ParticipationPolicy { return UserStaticRules::atLeastRole($authUser, RoleEnum::marketing); } + + /** + * Wether a customer can participate + * + * @param \App\Models\Customer $authUser + * @return boolean + */ + public function participate(Customer $authUser): bool + { + /** @var \App\Models\Settings */ + $settings = app(Settings::class); + + // * Deny banned IP, Check did not participate too much + return !BannedIp::getCached()->where('ip', app('clientIp'))->exists() or + Participation::query()->whereHas( + 'customer', + fn (Builder $q) => + $q->where('id', $authUser->id) + )->count() >= $settings->nb_participation_player; + } } diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 3d7dfae..6a7d59f 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -54,6 +54,7 @@ class AppServiceProvider extends ServiceProvider Carbon::setLocale(config('app.locale')); Pluralizer::useLanguage('french'); + // * Settings Provider app()->singleton(Settings::class, function () { if (!($settings = Settings::getCached()->first())) { throw new \ErrorException('Settings not found in DB'); diff --git a/app/Providers/MesBrApiServiceProvider.php b/app/Providers/MesBrApiServiceProvider.php new file mode 100644 index 0000000..bbc644b --- /dev/null +++ b/app/Providers/MesBrApiServiceProvider.php @@ -0,0 +1,30 @@ +discounts_site, + $settings->discounts_campaign + ); + }); + } +} diff --git a/config/app.php b/config/app.php index 3720e96..b002a6c 100644 --- a/config/app.php +++ b/config/app.php @@ -197,6 +197,7 @@ return [ App\Providers\TranslationServiceProvider::class, App\Providers\ViewServiceProvider::class, App\Providers\CrmApiServiceProvider::class, + App\Providers\MesBrApiServiceProvider::class, ], /* diff --git a/database/migrations/2020_10_12_123129_create_settings.php b/database/migrations/2020_10_12_123129_create_settings.php index e18e778..3c04306 100644 --- a/database/migrations/2020_10_12_123129_create_settings.php +++ b/database/migrations/2020_10_12_123129_create_settings.php @@ -4,7 +4,7 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; -class CreateSettings extends Migration +return new class extends Migration { /** * Run the migrations. @@ -34,10 +34,10 @@ class CreateSettings extends Migration ->comment('Date limite pour utiliser la page de cloture, sinon redirection vers close page'); $table->string('redirect_close')->comment('Lien de redirection du jeu quand celui-ci est fermé'); - $table->boolean('reductions_activated') + $table->boolean('discounts_activated') ->comment('Les bon de réduction sont activés (gains de BR possibles)'); - $table->string('reductions_site')->nullable()->comment('Champ mesBR "site"'); - $table->string('reductions_campaign')->nullable()->comment('Champ mesBR "campaign"'); + $table->string('discounts_site')->nullable()->comment('Champ mesBR "site"'); + $table->string('discounts_campaign')->nullable()->comment('Champ mesBR "campaign"'); $table->json('web_coupons')->nullable()->comment('Les coupons disponibles comme gain pour les joueurs'); $table->json('notification_emails')->nullable()->comment('Les mails à notifier pour les évènements de jeu'); @@ -57,4 +57,4 @@ class CreateSettings extends Migration { Schema::dropIfExists('settings'); } -} +}; diff --git a/database/migrations/2020_10_20_165858_create_codes.php b/database/migrations/2020_10_20_165858_create_codes.php index 02fa65b..e9c909d 100644 --- a/database/migrations/2020_10_20_165858_create_codes.php +++ b/database/migrations/2020_10_20_165858_create_codes.php @@ -4,7 +4,7 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; -class CreateCodes extends Migration +return new class extends Migration { /** * Run the migrations. @@ -15,9 +15,9 @@ class CreateCodes extends Migration { Schema::create('codes', function (Blueprint $table) { $table->unsignedBigInteger('id')->primary(); - $table->boolean('code_used')->default(0); - $table->boolean('code_exported')->default(0); - $table->date('date_creation'); + $table->boolean('code_used')->default(0)->comment('Is the code used too much ?'); + $table->boolean('code_exported')->default(0)->comment('Has the code been exported ?'); + $table->date('date_creation')->comment('Code creation date'); }); } @@ -30,4 +30,4 @@ class CreateCodes extends Migration { Schema::dropIfExists('codes'); } -} +}; diff --git a/database/migrations/2020_10_23_094235_create_banned_ips.php b/database/migrations/2020_10_23_094235_create_banned_ips.php index 935293a..bbdcc9e 100644 --- a/database/migrations/2020_10_23_094235_create_banned_ips.php +++ b/database/migrations/2020_10_23_094235_create_banned_ips.php @@ -4,7 +4,7 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; -class CreateBannedIps extends Migration +return new class extends Migration { /** * Run the migrations. @@ -29,4 +29,4 @@ class CreateBannedIps extends Migration { Schema::dropIfExists('banned_ips'); } -} +}; diff --git a/database/migrations/2020_10_26_093014_create_faq_themes.php b/database/migrations/2020_10_26_093014_create_faq_themes.php index 6ee238b..5153231 100644 --- a/database/migrations/2020_10_26_093014_create_faq_themes.php +++ b/database/migrations/2020_10_26_093014_create_faq_themes.php @@ -4,7 +4,7 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; -class CreateFaqThemes extends Migration +return new class extends Migration { /** * Run the migrations. @@ -29,4 +29,4 @@ class CreateFaqThemes extends Migration { Schema::dropIfExists('faq_themes'); } -} +}; diff --git a/database/migrations/2020_10_26_093746_create_faq_questions.php b/database/migrations/2020_10_26_093746_create_faq_questions.php index 0bcd094..1d7ce00 100644 --- a/database/migrations/2020_10_26_093746_create_faq_questions.php +++ b/database/migrations/2020_10_26_093746_create_faq_questions.php @@ -4,7 +4,7 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; -class CreateFaqQuestions extends Migration +return new class extends Migration { /** * Run the migrations. @@ -31,4 +31,4 @@ class CreateFaqQuestions extends Migration { Schema::dropIfExists('faq_questions'); } -} +}; diff --git a/database/migrations/2020_10_27_160038_create_reductions.php b/database/migrations/2020_10_27_160038_create_discounts.php similarity index 78% rename from database/migrations/2020_10_27_160038_create_reductions.php rename to database/migrations/2020_10_27_160038_create_discounts.php index 88a96b5..b151b29 100644 --- a/database/migrations/2020_10_27_160038_create_reductions.php +++ b/database/migrations/2020_10_27_160038_create_discounts.php @@ -4,7 +4,7 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; -class CreateReductions extends Migration +return new class extends Migration { /** * Run the migrations. @@ -13,7 +13,7 @@ class CreateReductions extends Migration */ public function up() { - Schema::create('reductions', function (Blueprint $table) { + Schema::create('discounts', function (Blueprint $table) { $table->id(); $table->string('link'); $table->string('basket_id'); @@ -29,6 +29,6 @@ class CreateReductions extends Migration */ public function down() { - Schema::dropIfExists('reductions'); + Schema::dropIfExists('discounts'); } -} +}; diff --git a/database/migrations/2020_10_29_091811_create_prizes.php b/database/migrations/2020_10_29_091811_create_prizes.php index a5388df..a41646f 100644 --- a/database/migrations/2020_10_29_091811_create_prizes.php +++ b/database/migrations/2020_10_29_091811_create_prizes.php @@ -4,7 +4,7 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; -class CreatePrizes extends Migration +return new class extends Migration { /** * Run the migrations. @@ -40,4 +40,4 @@ class CreatePrizes extends Migration { Schema::dropIfExists('prizes'); } -} +}; diff --git a/database/migrations/2020_11_02_120718_create_jobs_table.php b/database/migrations/2020_11_02_120718_create_jobs_table.php index 1be9e8a..a786a89 100644 --- a/database/migrations/2020_11_02_120718_create_jobs_table.php +++ b/database/migrations/2020_11_02_120718_create_jobs_table.php @@ -4,7 +4,7 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; -class CreateJobsTable extends Migration +return new class extends Migration { /** * Run the migrations. @@ -33,4 +33,4 @@ class CreateJobsTable extends Migration { Schema::dropIfExists('jobs'); } -} +}; diff --git a/database/migrations/2021_08_18_154119_create_model_ranges_table.php b/database/migrations/2021_08_18_154119_create_model_ranges_table.php index f393ab8..fc0f3d8 100644 --- a/database/migrations/2021_08_18_154119_create_model_ranges_table.php +++ b/database/migrations/2021_08_18_154119_create_model_ranges_table.php @@ -4,7 +4,7 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; -class CreateModelRangesTable extends Migration +return new class extends Migration { /** * Run the migrations. @@ -28,4 +28,4 @@ class CreateModelRangesTable extends Migration { Schema::dropIfExists('model_ranges'); } -} +}; diff --git a/database/migrations/2021_08_18_154140_create_ranges_table.php b/database/migrations/2021_08_18_154140_create_ranges_table.php index 8d24d0e..f127b01 100644 --- a/database/migrations/2021_08_18_154140_create_ranges_table.php +++ b/database/migrations/2021_08_18_154140_create_ranges_table.php @@ -4,7 +4,7 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; -class CreateRangesTable extends Migration +return new class extends Migration { /** * Run the migrations. @@ -34,4 +34,4 @@ class CreateRangesTable extends Migration { Schema::dropIfExists('ranges'); } -} +}; diff --git a/database/migrations/2021_08_18_162010_create_products_table.php b/database/migrations/2021_08_18_162010_create_products_table.php index 03a3a8a..1e3b146 100644 --- a/database/migrations/2021_08_18_162010_create_products_table.php +++ b/database/migrations/2021_08_18_162010_create_products_table.php @@ -4,7 +4,7 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; -class CreateProductsTable extends Migration +return new class extends Migration { /** * Run the migrations. @@ -37,4 +37,4 @@ class CreateProductsTable extends Migration { Schema::dropIfExists('products'); } -} +}; diff --git a/database/migrations/2023_08_16_092101_create_customers_table.php b/database/migrations/2023_08_16_092101_create_customers_table.php index d67ca74..7787d28 100644 --- a/database/migrations/2023_08_16_092101_create_customers_table.php +++ b/database/migrations/2023_08_16_092101_create_customers_table.php @@ -4,7 +4,7 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; -class CreateCustomersTable extends Migration +return new class extends Migration { /** * Run the migrations. @@ -39,4 +39,4 @@ class CreateCustomersTable extends Migration { Schema::dropIfExists('customers'); } -} +}; diff --git a/database/migrations/2023_08_22_091935_create_participations.php b/database/migrations/2023_08_22_091935_create_participations.php index 8f8ba16..2eca03c 100644 --- a/database/migrations/2023_08_22_091935_create_participations.php +++ b/database/migrations/2023_08_22_091935_create_participations.php @@ -4,7 +4,7 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; -class CreateParticipations extends Migration +return new class extends Migration { /** * Run the migrations. @@ -15,14 +15,25 @@ class CreateParticipations extends Migration { Schema::create('participations', function (Blueprint $table) { $table->id(); - $table->string('ip'); - $table->string('sticker')->nullable(); - $table->string('ticket')->nullable(); + $table->string('ip')->comment('Adresse ip de la participation'); + + $table->string('sticker')->nullable()->comment('Si gagnant, fichier image du sticker utilisé'); + $table->string('ticket')->nullable() + ->comment('Si gagnant, fichier image du ticket de caisse prouvant l\'achat du produit stické'); $table->string('barcode')->nullable(); - $table->foreignId('customer_id')->constrained('customers'); - $table->foreignId('code_unique_id')->constrained('codes'); - $table->foreignId('product_id')->nullable()->constrained('products'); - $table->foreignId('reduction_id')->nullable()->constrained('reductions'); + + // * RELATIONSHIPS + $table->foreignId('customer_id')->comment('Customer participant') + ->constrained('customers'); + $table->foreignId('code_unique_id')->comment('Code unique utilisé') + ->constrained('codes'); + $table->foreignId('product_id')->nullable() + ->comment('Si code EAN activés, Produit porteur de l\'offre (code ean indiqué)') + ->constrained('products'); + + $table->foreignId('discount_id')->nullable() + ->comment('Bon de réduction gagné')->constrained('discounts'); + $table->timestamps(); }); } @@ -36,4 +47,4 @@ class CreateParticipations extends Migration { Schema::dropIfExists('participations'); } -} +}; diff --git a/database/migrations/2023_08_22_120243_create_instant_wins.php b/database/migrations/2023_08_22_120243_create_instant_wins.php index 34e8f80..e8aec91 100644 --- a/database/migrations/2023_08_22_120243_create_instant_wins.php +++ b/database/migrations/2023_08_22_120243_create_instant_wins.php @@ -4,7 +4,7 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; -class CreateInstantWins extends Migration +return new class extends Migration { /** * Run the migrations. @@ -15,11 +15,14 @@ class CreateInstantWins extends Migration { Schema::create('instant_wins', function (Blueprint $table) { $table->id(); - $table->dateTime('appear_date'); - $table->boolean('won')->default(0); - $table->foreignId('prize_id')->constrained('prizes'); - $table->foreignId('participation_id')->nullable() - ->constrained('participations')->unique(); + $table->timestamp('available_at') + ->comment('La date-heure à laquelle l\'instant gagnant pourras être gagné'); + $table->boolean('won')->default(0)->comment('L\'instant à été gagné ?'); + + $table->foreignId('prize_id')->comment('Le lot qui à été gagné')->constrained('prizes'); + $table->foreignId('participation_id') + ->comment('Le customer participant qui à gagné avec les informations sur sa participation') + ->nullable()->constrained('participations')->unique(); }); } @@ -32,4 +35,4 @@ class CreateInstantWins extends Migration { Schema::dropIfExists('instant_wins'); } -} +}; diff --git a/database/seeders/Mandatory/SettingsSeeder.php b/database/seeders/Mandatory/SettingsSeeder.php index 9f6299a..25b4729 100644 --- a/database/seeders/Mandatory/SettingsSeeder.php +++ b/database/seeders/Mandatory/SettingsSeeder.php @@ -28,7 +28,7 @@ class SettingsSeeder extends Seeder $settings->activated_teaser = false; $settings->activated_close_page = false; $settings->redirect_close = "https://example.test"; - $settings->reductions_activated = false; + $settings->discounts_activated = false; $settings->notification_emails = []; $settings->winning_proof = 0; $settings->web_coupons = []; diff --git a/resources/lang/fr/validation.php b/resources/lang/fr/validation.php index d9e7171..7515696 100644 --- a/resources/lang/fr/validation.php +++ b/resources/lang/fr/validation.php @@ -264,9 +264,9 @@ return [ 'redirect_close' => 'url de redirection après la date de fin du jeu', 'winning_proof' => 'activer les preuves de gain', 'company' => 'société', - 'reductions_activated' => 'activer les bons de réduction', - 'reductions_site' => 'référence du site', - 'reductions_campaign' => 'référence de la campagne', + 'discounts_activated' => 'activer les bons de réduction', + 'discounts_site' => 'référence du site', + 'discounts_campaign' => 'référence de la campagne', 'analytics' => 'analytics', ], ]; diff --git a/resources/ts/pages/settings.ts b/resources/ts/pages/settings.ts index a5afe2d..aab5bc8 100644 --- a/resources/ts/pages/settings.ts +++ b/resources/ts/pages/settings.ts @@ -17,33 +17,33 @@ document.addEventListener("DOMContentLoaded", function () { }); } - const inputReductionsActivated = document.querySelector("input[name=reductions_activated]") as HTMLInputElement | null; + const inputDiscountsActivated = document.querySelector("input[name=discounts_activated]") as HTMLInputElement | null; const inputActivatedClosePage = document.querySelector("input[name=activated_close_page]") as HTMLInputElement | null; - const reductionsSite = document.getElementById("reductions-site") as HTMLElement | null; - const reductionsCampaign = document.getElementById("reductions-campaign") as HTMLElement | null; - const reductionsWebCoupons = document.getElementById("reductions-web-coupons") as HTMLElement | null; + const discountsSite = document.getElementById("discounts-site") as HTMLElement | null; + const discountsCampaign = document.getElementById("discounts-campaign") as HTMLElement | null; + const discountsWebCoupons = document.getElementById("discounts-web-coupons") as HTMLElement | null; const closePageActiveDate = document.getElementById("close-page-active-date"); const settingsClosePageActiveDate = document.getElementById("settings-close-page-active-date") as HTMLInputElement | null; - const settingsReductionsSite = document.getElementById("settings-reductions-site") as HTMLInputElement | null; - const settingsReductionsCampaign = document.getElementById("settings-reductions-campaign") as HTMLInputElement | null; + const settingsDiscountsSite = document.getElementById("settings-discounts-site") as HTMLInputElement | null; + const settingsDiscountsCampaign = document.getElementById("settings-discounts-campaign") as HTMLInputElement | null; - if (!inputReductionsActivated) { - throw new Error("Missing input[name=reductions_activated]"); + if (!inputDiscountsActivated) { + throw new Error("Missing input[name=discounts_activated]"); } if (!inputActivatedClosePage) { throw new Error("Missing input[name=activated_close_page]"); } - if (!reductionsSite) { - throw new Error("Missing #reductions-site"); + if (!discountsSite) { + throw new Error("Missing #discounts-site"); } - if (!reductionsCampaign) { - throw new Error("Missing #reductions-campaign"); + if (!discountsCampaign) { + throw new Error("Missing #discounts-campaign"); } - if (!reductionsWebCoupons) { - throw new Error("Missing #reductions-web-coupons"); + if (!discountsWebCoupons) { + throw new Error("Missing #discounts-web-coupons"); } if (!closePageActiveDate) { throw new Error("Missing #close-page-active-date"); @@ -51,32 +51,32 @@ document.addEventListener("DOMContentLoaded", function () { if (!settingsClosePageActiveDate) { throw new Error("Missing #settings-close-page-active-date"); } - if (!settingsReductionsSite) { - throw new Error("Missing #settings-reductions-site"); + if (!settingsDiscountsSite) { + throw new Error("Missing #settings-discounts-site"); } - if (!settingsReductionsCampaign) { - throw new Error("Missing #settings-reductions-campaign"); + if (!settingsDiscountsCampaign) { + throw new Error("Missing #settings-discounts-campaign"); } - const reductionsWebCouponsInputs = reductionsWebCoupons.getElementsByTagName("input"); + const discountsWebCouponsInputs = discountsWebCoupons.getElementsByTagName("input"); - const toggleReduction = () => { - if (!inputReductionsActivated.checked) { - reductionsSite.style.display = "none"; - reductionsCampaign.style.display = "none"; - reductionsWebCoupons.style.display = "none"; - settingsReductionsSite.disabled = true; - settingsReductionsCampaign.disabled = true; - Array.from(reductionsWebCouponsInputs).forEach(element => { + const toggleDiscount = () => { + if (!inputDiscountsActivated.checked) { + discountsSite.style.display = "none"; + discountsCampaign.style.display = "none"; + discountsWebCoupons.style.display = "none"; + settingsDiscountsSite.disabled = true; + settingsDiscountsCampaign.disabled = true; + Array.from(discountsWebCouponsInputs).forEach(element => { element.disabled = true; }); } else { - reductionsSite.style.display = ""; - reductionsCampaign.style.display = ""; - reductionsWebCoupons.style.display = ""; - settingsReductionsSite.disabled = false; - settingsReductionsCampaign.disabled = false; - Array.from(reductionsWebCouponsInputs).forEach(element => { + discountsSite.style.display = ""; + discountsCampaign.style.display = ""; + discountsWebCoupons.style.display = ""; + settingsDiscountsSite.disabled = false; + settingsDiscountsCampaign.disabled = false; + Array.from(discountsWebCouponsInputs).forEach(element => { element.disabled = false; }); } @@ -92,9 +92,9 @@ document.addEventListener("DOMContentLoaded", function () { } }; - // Gestion du tableau pour reduction - inputReductionsActivated.addEventListener("change", toggleReduction); - toggleReduction(); + // Gestion du tableau pour discount + inputDiscountsActivated.addEventListener("change", toggleDiscount); + toggleDiscount(); // Gestion de l'activation de la page de fermeture (champ date à afficher ou non) inputActivatedClosePage.addEventListener("change", toggleClosePage); diff --git a/resources/views/layouts/re7-offcanvas.blade.php b/resources/views/layouts/re7-offcanvas.blade.php index 6355de9..8cbbf81 100644 --- a/resources/views/layouts/re7-offcanvas.blade.php +++ b/resources/views/layouts/re7-offcanvas.blade.php @@ -21,7 +21,7 @@
{{ __('Participation') }} - @if ($settingsGlobal->reductions_activated) + @if ($settingsGlobal->discounts_activated) {{-- WON BR --}} {{ __('Mails') }} - @if ($settingsGlobal->reductions_activated) + @if ($settingsGlobal->discounts_activated) {{-- WON BR MAIL --}} {{ __('ID : :id', ['id' => $code->id]) }}

{{ __('Utilisé ? : :used', ['used' => $code->code_used ? 'OUI' : 'NON']) }}

{{ __('Exporté ? : :exported', ['exported' => $code->code_exported ? 'OUI' : 'NON']) }}

-

{{ __('Créé le : :date_creation', ['date_creation' => $code->date_creation]) }}

+

{{ __('Créé le : :date_creation', ['date_creation' => $code->date_creation->isoFormat('DD/MM/YYYY')]) }}

@endif @endsection diff --git a/resources/views/pages/settings/form-inputs.blade.php b/resources/views/pages/settings/form-inputs.blade.php index 734e415..479707e 100644 --- a/resources/views/pages/settings/form-inputs.blade.php +++ b/resources/views/pages/settings/form-inputs.blade.php @@ -330,69 +330,69 @@
- {{-- REDUCTIONS_ACTIVATED --}} + {{-- DISCOUNTS_ACTIVATED --}}
- {{ Str::ucfirst(__('validation.custom.reductions_activated')) }} + {{ Str::ucfirst(__('validation.custom.discounts_activated')) }}
@include('back::partials.inputs.tinyint-boolean', [ - 'id' => 'settings-reductions-activated', - 'label' => Str::ucfirst(__('validation.custom.reductions_activated')), - 'name' => 'reductions_activated', + 'id' => 'settings-discounts-activated', + 'label' => Str::ucfirst(__('validation.custom.discounts_activated')), + 'name' => 'discounts_activated', 'required' => false, 'model' => $settingsModel ?? null, 'helper' => __('validation.boolean', [ - 'attribute' => Str::ucfirst(__('validation.custom.reductions_activated')), + 'attribute' => Str::ucfirst(__('validation.custom.discounts_activated')), ]), ])
- {{-- REDUCTIONS_SITE --}} -
+ {{-- DISCOUNTS_SITE --}} +
- {{ Str::ucfirst(__('validation.custom.reductions_site')) }} + {{ Str::ucfirst(__('validation.custom.discounts_site')) }}
@include('back::partials.inputs.varchar', [ - 'id' => 'settings-reductions-site', - 'label' => __('validation.custom.reductions_site'), + 'id' => 'settings-discounts-site', + 'label' => __('validation.custom.discounts_site'), 'hasWordCounter' => true, - 'name' => 'reductions_site', + 'name' => 'discounts_site', 'required' => false, 'model' => $settingsModel ?? null, 'helper' => __('validation.between.string', [ - 'attribute' => __('validation.custom.reductions_site'), + 'attribute' => __('validation.custom.discounts_site'), 'min' => 3, 'max' => 255, ]), - 'placeholder' => __('validation.custom.reductions_site'), + 'placeholder' => __('validation.custom.discounts_site'), ])
- {{-- REDUCTIONS_CAMPAIGN --}} -
+ {{-- DISCOUNTS_CAMPAIGN --}} +
- {{ Str::ucfirst(__('validation.custom.reductions_campaign')) }} + {{ Str::ucfirst(__('validation.custom.discounts_campaign')) }}
@include('back::partials.inputs.varchar', [ - 'id' => 'settings-reductions-campaign', - 'label' => __('validation.custom.reductions_campaign'), + 'id' => 'settings-discounts-campaign', + 'label' => __('validation.custom.discounts_campaign'), 'hasWordCounter' => true, - 'name' => 'reductions_campaign', + 'name' => 'discounts_campaign', 'required' => false, 'model' => $settingsModel ?? null, 'helper' => __('validation.between.string', [ - 'attribute' => __('validation.custom.reductions_campaign'), + 'attribute' => __('validation.custom.discounts_campaign'), 'min' => 3, 'max' => 255, ]), - 'placeholder' => __('validation.custom.reductions_campaign'), + 'placeholder' => __('validation.custom.discounts_campaign'), ])
@@ -407,7 +407,7 @@ 'coupon_height' => 409, ]; @endphp -
+
@include('back::modules.input-error', ['inputName' => 'web_coupons']) @include('back::modules.input-error', ['inputName' => 'web_coupons.*'])