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