318 lines
12 KiB
PHP
318 lines
12 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Fo;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Http\Requests\Fo\Customers\CreateAccountRequest;
|
|
use App\Http\Requests\Fo\ParticipateRequest;
|
|
use App\Lib\Discount as LibDiscount;
|
|
use App\Mail\Won\PrizeWonAdminMail;
|
|
use App\Models\Customer;
|
|
use App\Models\InstantWin;
|
|
use App\Models\Participation;
|
|
use App\Models\Discount;
|
|
use App\Models\Settings;
|
|
use App\Notifications\Customer\HasWonDiscount;
|
|
use App\Notifications\Customer\HasWonInstantWin;
|
|
use App\Repositories\Fo\CrmRepository;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Arr;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Gate;
|
|
use Illuminate\Support\Facades\Mail;
|
|
use Illuminate\Support\Facades\Session;
|
|
use Illuminate\Support\Facades\Validator;
|
|
use Illuminate\Validation\ValidationException;
|
|
|
|
class ParticipateController extends Controller
|
|
{
|
|
/** @var \App\Repositories\Fo\CrmRepository $crmRepository */
|
|
private $crmRepository;
|
|
/**
|
|
* ParticipateController
|
|
*
|
|
* @return void
|
|
*/
|
|
public function __construct()
|
|
{
|
|
$this->crmRepository = new CrmRepository();
|
|
$this->middleware(function (Request $request, callable $next) {
|
|
$this->authorize('fo.gameEnabled');
|
|
$this->assertUserHasEnoughInfoToUseMesBr();
|
|
return $next($request);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Display participation form
|
|
*
|
|
* @return \Illuminate\Contracts\View\View
|
|
*/
|
|
public function participate(): \Illuminate\Contracts\View\View
|
|
{
|
|
if (!Gate::check('participate', Participation::class)) {
|
|
return view('theme::pages.participation.participation-exhausted');
|
|
}
|
|
return view('theme::pages.participation.participate');
|
|
}
|
|
|
|
/**
|
|
* Participate Method
|
|
*
|
|
* @param \App\Http\Requests\Fo\ParticipateRequest $request
|
|
* @return \Illuminate\Contracts\View\View
|
|
*/
|
|
public function participateSubmit(ParticipateRequest $request): \Illuminate\Contracts\View\View
|
|
{
|
|
return DB::transaction(function () use ($request) {
|
|
// ! On verrouille le ou les instants gagnant
|
|
/** @var \App\Models\InstantWin|null */
|
|
$instantWin = InstantWin::query()->lockForUpdate()
|
|
->where('available_at', '<', now())
|
|
->whereDoesntHave('participation')
|
|
->get()->sortBy('available_at')->first();
|
|
|
|
/** @var \App\Models\Settings */
|
|
$settings = app(Settings::class);
|
|
|
|
/** @var \App\Models\Customer */
|
|
$customer = auth('frontend')->user();
|
|
|
|
/** @var \App\Models\Code|null */
|
|
$code = $request->post('unique_code');
|
|
/** @var \App\Models\Product|null */
|
|
$product = $request->post('product');
|
|
|
|
// * Make new participation
|
|
$participation = Participation::makeNew(
|
|
app('clientIp'),
|
|
$customer,
|
|
$code,
|
|
$product
|
|
);
|
|
|
|
// * Si l'utilisateur actuel à déjà gagné un gros lot, pas d'instant gagnant.
|
|
// ? As-t-on un instant gagnant ?
|
|
if (Participation::customerAlreadyHasAnInstantWin($customer) or !$instantWin) {
|
|
// * --- DISCOUNT WIN ---
|
|
// ? Les BR sont activés ?
|
|
if (!$settings->discounts_activated) {
|
|
// * On enregistre la participation du joueur.
|
|
$participation->save();
|
|
|
|
// * Pas de coupons disponibles, le joueur à perdu
|
|
return view('theme::pages.participation.loose');
|
|
}
|
|
|
|
// * Le joueur à gagné un coupon.
|
|
/** @var \App\Lib\Discount Coupon aléatoire en fonction du ratio de chaque coupon */
|
|
$discount = Arr::get(
|
|
$settings->web_coupons,
|
|
$this->getRandomWeightedElementIndex($settings->web_coupons)
|
|
);
|
|
|
|
$mesBrDiscount = $this->setDiscountAsWon($customer, $discount);
|
|
|
|
// * Le joueur à remporté un coupon
|
|
$participation->discount()->associate($mesBrDiscount);
|
|
// * On enregistre la participation du joueur.
|
|
$participation->save();
|
|
|
|
$crmCustomer = $this->crmRepository->fetchCrmCustomer($customer);
|
|
|
|
$customer->notify(new HasWonDiscount(
|
|
$discount,
|
|
$mesBrDiscount,
|
|
$crmCustomer->firstname
|
|
));
|
|
|
|
return view('theme::pages.participation.won', compact('discount', 'mesBrDiscount'));
|
|
} //end if
|
|
|
|
// * --- INSTANT WIN ---
|
|
// * On enregistre la participation du joueur.
|
|
$participation->save();
|
|
// * Le joueur à remporté un instant gagnant
|
|
$instantWin->participation()->associate($participation);
|
|
$instantWin->save();
|
|
|
|
$crmCustomer = $this->crmRepository->fetchCrmCustomer($customer);
|
|
|
|
// * Notify customer for his win
|
|
$customer->notify(new HasWonInstantWin(
|
|
$instantWin->prize,
|
|
$crmCustomer->firstname
|
|
));
|
|
|
|
// * Dispatch notification to mail list
|
|
Mail::to($settings->notification_emails)->send(new PrizeWonAdminMail(
|
|
$settings->name,
|
|
$participation->created_at,
|
|
$instantWin->prize->label,
|
|
$crmCustomer,
|
|
optional($code)->code_unique,
|
|
optional($product)->ean_code
|
|
));
|
|
|
|
return view('theme::pages.participation.won', [
|
|
'prizeModel' => $instantWin->prize,
|
|
'participationModel' => $participation,
|
|
'crmCustomer' => $crmCustomer
|
|
]);
|
|
});
|
|
}
|
|
|
|
// * --- PRIVATE METHODS ---
|
|
|
|
/**
|
|
* Try Call CRM + MesBr to setup discount
|
|
*
|
|
* @param \App\Models\Customer $customer
|
|
* @param LibDiscount $discount
|
|
* @return \App\Models\Discount
|
|
* @throws \Illuminate\Http\Exceptions\HttpResponseException If Any error occurs.
|
|
* @phpcs:disable Squiz.Commenting.FunctionCommentThrowTag.WrongNumber
|
|
*/
|
|
private function setDiscountAsWon(Customer $customer, LibDiscount $discount): \App\Models\Discount
|
|
{
|
|
// phpcs:enable
|
|
// * Phase - 1 Recupération des informations CRM
|
|
/** @var \LDC\LDCCRM\Models\Customer*/
|
|
$crmUser = $this->crmRepository->fetchCrmCustomer($customer);
|
|
|
|
// * Phase - 2 Mise à jour du coupon dans MesBr
|
|
try {
|
|
/** @var \App\Models\Settings */
|
|
$settings = app(Settings::class);
|
|
|
|
/** @var \LDC\MESBR\MesBr */
|
|
$mesBr = app('mesBrAPI');
|
|
|
|
// * MaJ Customer
|
|
/** @var string */
|
|
$crm_customer_hashcode = retry(3, function () use ($mesBr, $crmUser) {
|
|
/**
|
|
* Parce que MesBr n'est pas fiable il faut retenter pour avoir
|
|
* l'id client, des fois cet id sera dans hashcode...
|
|
*
|
|
* Id est necessaire pour update panier..
|
|
*/
|
|
$result = $mesBr->updateCustomer($crmUser->hashcode, $crmUser->email, $crmUser->country);
|
|
if (optional($result)->status !== "OK") {
|
|
throw new \RuntimeException(
|
|
\sprintf(
|
|
'MESBR : Une erreur est survenue. Code : %s Message : %s',
|
|
$result->code ?? 'Undefined',
|
|
$result->message ?? 'Undefined'
|
|
)
|
|
);
|
|
}
|
|
/** @var object|null */
|
|
$crm_customer = optional($result)->customer;
|
|
if (empty(optional($crm_customer)->hashcode)) {
|
|
throw new \RuntimeException(
|
|
'MESBR : Une erreur est survenue. Update Customer n\'as pas retourné le customer hashcode'
|
|
);
|
|
}
|
|
|
|
return $crm_customer->hashcode;
|
|
}, 100);
|
|
|
|
// * Maj Panier
|
|
$result = $mesBr->updatePanier(
|
|
$crmUser,
|
|
$crm_customer_hashcode,
|
|
$settings->discounts_site,
|
|
strval($discount->web_coupon_identifiant)
|
|
);
|
|
|
|
if (Arr::get($result, 'status') === "OK") {
|
|
// * La réponse est conforme ?
|
|
$needed_fields = ['link', 'verif', 'basketId'];
|
|
if (!Arr::has($result, $needed_fields)) {
|
|
throw new \RuntimeException(sprintf(
|
|
'MESBR : Il manques des champs dans la réponse, attendu => %s, donné => %s',
|
|
json_encode($needed_fields),
|
|
json_encode($result),
|
|
));
|
|
}
|
|
|
|
$discountModel = new Discount();
|
|
$discountModel->link = Arr::get($result, 'link');
|
|
$discountModel->verification = Arr::get($result, 'verif');
|
|
$discountModel->basket_id = Arr::get($result, 'basketId');
|
|
$discountModel->save();
|
|
|
|
// * Tout est OK
|
|
return $discountModel;
|
|
}
|
|
|
|
throw new \RuntimeException(
|
|
\sprintf(
|
|
'MESBR : Une erreur est survenue. Code : %s Message : %s',
|
|
$result["code"] ?? 'Undefined',
|
|
$result["message"] ?? 'Undefined'
|
|
)
|
|
);
|
|
} catch (\RuntimeException $e) {
|
|
report($e);
|
|
// * Retenter ?
|
|
back()->with('error', trans('Une erreur est survenue, veuillez réssayer.'))->throwResponse();
|
|
} //end try
|
|
|
|
throw new \Error('Should not reach this point');
|
|
}
|
|
|
|
/**
|
|
* Assert that user has enough info filled on his profile to win a Discount
|
|
* Or redirect him to the fill form
|
|
* ! Also validates its birth date (because beeing an adult is required to participate)
|
|
*
|
|
* @return void
|
|
* @throws \Illuminate\Http\Exceptions\HttpResponseException If customer data doest not validate
|
|
* or and error occurs.
|
|
*/
|
|
private function assertUserHasEnoughInfoToUseMesBr(): void
|
|
{
|
|
|
|
// * Valider que le client dispose des donnés requises pour MesBr
|
|
try {
|
|
/** @var \App\Models\Customer */
|
|
$authUser = auth('frontend')->user();
|
|
$crmCustomer = $this->crmRepository->fetchCrmCustomer($authUser);
|
|
|
|
// * On valide les données selon les critères du site
|
|
$rules = collect((new CreateAccountRequest())->rules());
|
|
Validator::make(
|
|
[
|
|
'birth_date' => $crmCustomer->birth_date,
|
|
'address' => $crmCustomer->address,
|
|
'postal_code' => $crmCustomer->postcode,
|
|
'country' => $crmCustomer->country->value,
|
|
'city' => $crmCustomer->city
|
|
],
|
|
[
|
|
'birth_date' => $rules->get('birth_date'),
|
|
'address' => $rules->get('address'),
|
|
'postal_code' => $rules->get('postal_code'),
|
|
'country' => $rules->get('country'),
|
|
'city' => $rules->get('city')
|
|
]
|
|
)->validate();
|
|
Session::remove('needCrmInfoUpdate');
|
|
} catch (ValidationException) {
|
|
response()->redirectToRoute('fo.profil.verify')
|
|
->with('warning', trans(
|
|
'Vous devez compléter des informations sur votre profil pour pouvoir participer.'
|
|
))->throwResponse();
|
|
} catch (\Exception $e) {
|
|
report($e);
|
|
// * Retenter ?
|
|
response()->redirectToRoute('fo.homepage')
|
|
->with('error', trans('Une erreur est survenue, veuillez réssayer.'))
|
|
->throwResponse();
|
|
} //end try
|
|
}
|
|
|
|
// * --- END PRIVATE METHODS ---
|
|
}
|