Big freaking update TMP refactor Participate

This commit is contained in:
Jérémy Munsch 2023-12-08 15:39:13 +01:00
parent 1c4a7d915e
commit 1b388e7265
No known key found for this signature in database
GPG key ID: 18361AF3BFEC0FEC
37 changed files with 549 additions and 389 deletions

View file

@ -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)

View file

@ -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();
});

View file

@ -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;
}
}
}
}

View file

@ -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
*

View file

@ -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;
}
/**

View file

@ -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'),

View file

@ -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'),
];
}
}

View file

@ -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());
}
}

View file

@ -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
*

View file

@ -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

View file

@ -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.

View file

@ -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();
}
}

View file

@ -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<string> $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',

View file

@ -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;
}
}

View file

@ -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');

View file

@ -0,0 +1,30 @@
<?php
namespace App\Providers;
use App\Models\Settings;
use Illuminate\Support\Facades\App;
use Illuminate\Support\ServiceProvider;
use LDCWEB\MesBR;
class MesBrApiServiceProvider extends ServiceProvider
{
/**
* Bootstrap the application services.
*
* @return void
*/
public function boot()
{
App::singleton('mesBrAPI', function () {
/** @var \App\Models\Settings|null */
$settings = app(Settings::class);
return new MesBR(
config('mesbr.endpoint'),
$settings->discounts_site,
$settings->discounts_campaign
);
});
}
}

View file

@ -197,6 +197,7 @@ return [
App\Providers\TranslationServiceProvider::class,
App\Providers\ViewServiceProvider::class,
App\Providers\CrmApiServiceProvider::class,
App\Providers\MesBrApiServiceProvider::class,
],
/*

View file

@ -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');
}
}
};

View file

@ -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');
}
}
};

View file

@ -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');
}
}
};

View file

@ -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');
}
}
};

View file

@ -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');
}
}
};

View file

@ -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');
}
}
};

View file

@ -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');
}
}
};

View file

@ -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');
}
}
};

View file

@ -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');
}
}
};

View file

@ -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');
}
}
};

View file

@ -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');
}
}
};

View file

@ -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');
}
}
};

View file

@ -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');
}
}
};

View file

@ -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');
}
}
};

View file

@ -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 = [];

View file

@ -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',
],
];

View file

@ -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);

View file

@ -21,7 +21,7 @@
<div class="list-group">
<span class="list-group-item list-group-item-dark">{{ __('Participation') }}</span>
@if ($settingsGlobal->reductions_activated)
@if ($settingsGlobal->discounts_activated)
{{-- WON BR --}}
<a class="list-group-item list-group-item-action" href="{{ route('re7.discount') }}"
title="{{ __('Afficher un bon de réduction dans un nouvel onglet') }}"
@ -52,7 +52,7 @@
<div class="list-group">
<span class="list-group-item list-group-item-dark">{{ __('Mails') }}</span>
@if ($settingsGlobal->reductions_activated)
@if ($settingsGlobal->discounts_activated)
{{-- WON BR MAIL --}}
<a class="list-group-item list-group-item-action" href="{{ route('re7.mail-discount') }}"
title="{{ __('Afficher le mail de bon de réduction dans un nouvel onglet') }}"

View file

@ -19,6 +19,6 @@
<p><span class="font-weight-bold">{{ __('ID : :id', ['id' => $code->id]) }}</span></p>
<p>{{ __('Utilisé ? : :used', ['used' => $code->code_used ? 'OUI' : 'NON']) }}</p>
<p>{{ __('Exporté ? : :exported', ['exported' => $code->code_exported ? 'OUI' : 'NON']) }}</p>
<p>{{ __('Créé le : :date_creation', ['date_creation' => $code->date_creation]) }}</p>
<p>{{ __('Créé le : :date_creation', ['date_creation' => $code->date_creation->isoFormat('DD/MM/YYYY')]) }}</p>
@endif
@endsection

View file

@ -330,69 +330,69 @@
</h5>
<div class="row">
{{-- REDUCTIONS_ACTIVATED --}}
{{-- DISCOUNTS_ACTIVATED --}}
<div class="col-12 col-md-6 mb-3">
<fieldset class="h-100 border p-3">
<legend>{{ Str::ucfirst(__('validation.custom.reductions_activated')) }}</legend>
<legend>{{ Str::ucfirst(__('validation.custom.discounts_activated')) }}</legend>
<div class="row">
<div class="col-12">
@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')),
]),
])
</div>
</div>
</fieldset>
</div>
{{-- REDUCTIONS_SITE --}}
<div class="col-12 col-md-6 mb-3" id="reductions-site">
{{-- DISCOUNTS_SITE --}}
<div class="col-12 col-md-6 mb-3" id="discounts-site">
<fieldset class="h-100 border p-3">
<legend>{{ Str::ucfirst(__('validation.custom.reductions_site')) }}</legend>
<legend>{{ Str::ucfirst(__('validation.custom.discounts_site')) }}</legend>
<div class="row">
<div class="col-12">
@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'),
])
</div>
</div>
</fieldset>
</div>
{{-- REDUCTIONS_CAMPAIGN --}}
<div class="col-12 col-md-6 mb-3" id="reductions-campaign">
{{-- DISCOUNTS_CAMPAIGN --}}
<div class="col-12 col-md-6 mb-3" id="discounts-campaign">
<fieldset class="h-100 border p-3">
<legend>{{ Str::ucfirst(__('validation.custom.reductions_campaign')) }}</legend>
<legend>{{ Str::ucfirst(__('validation.custom.discounts_campaign')) }}</legend>
<div class="row">
<div class="col-12">
@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'),
])
</div>
</div>
@ -407,7 +407,7 @@
'coupon_height' => 409,
];
@endphp
<div class="web-coupons mb-3" id="reductions-web-coupons" data-json='@json($data)'></div>
<div class="web-coupons mb-3" id="discounts-web-coupons" data-json='@json($data)'></div>
@include('back::modules.input-error', ['inputName' => 'web_coupons'])
@include('back::modules.input-error', ['inputName' => 'web_coupons.*'])
</div>