ldc-boutique-cnc/app/Http/Controllers/CustomerController.php
2022-09-03 16:56:16 +02:00

606 lines
21 KiB
PHP

<?php
namespace App\Http\Controllers;
use App\Http\Requests\CustomerRegisterRequest;
use App\Http\Requests\LoginRequest;
use App\Http\Requests\UpdateInfosRequest;
use App\Mail\PasswordResetMail;
use App\Mail\RegisterConfirmMail;
use App\Models\Customers;
use App\Models\Magasin;
use App\Models\Order;
use App\Models\PasswordReset;
use App\Models\Salarie;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\Str;
use LDC\LDCCRM\Enums\ApiError;
use LDC\LDCCRM\Enums\Country;
use LDC\LDCCRM\Exceptions\ApiErrorException;
use LDC\LDCCRM\Exceptions\CrmException;
use LDC\LDCCRM\Exceptions\ValidationException;
use LDC\LDCCRM\Models\Customer as CrmCustomer;
class CustomerController extends Controller
{
/**
* Affiche la page d'inscription
*
* @return \Illuminate\Http\Response
*/
public function registerForm()
{
if (Auth::guard('customer')->check()) {
return redirect()->route('home');
}
return view('auth.register');
}
/**
* Enregistre le customer dans la base de données
* et CRM
*
* @param CustomerRegisterRequest $request
* @return \Illuminate\Http\RedirectResponse
*/
public function register(CustomerRegisterRequest $request)
{
try {
return DB::transaction(function () use ($request) {
$crmCustomer = new CrmCustomer(\array_intersect_key(
$request->validated(),
[
'firstname' => '',
'lastname' => '',
'birth_date' => '',
'address' => '',
'postcode' => '',
'country' => '',
'city' => '',
'phone' => '',
'email' => '',
'password' => '',
'opt_in' => '',
]
));
$crmCustomer->city = $request->town;
$crmCustomer->postcode = $request->postal_code;
$crmCustomer->opt_in = $request->optin ? true : false;
// * Country Is forced to france
$crmCustomer->country = Country::france();
$crmCustomer->save();
// * Enrregistrement du Hashcode
/** @var \App\Models\Customers $customer */
$customer = new Customers($request->all());
$customer->hashcode = $crmCustomer->hashcode;
$customer->saveOrFail();
// * liaison éventuelle avec la table salaries
if ($request->matricule && $request->code) {
/** @var \App\Models\Salarie $salarie */
$salarie = Salarie::where('matricule', '=', $request->matricule)
->where('code', '=', $request->code)
->firstOrFail();
$salarie->customer()->associate($customer);
$salarie->saveOrFail();
}
Mail::to($request->email)->send(new RegisterConfirmMail($customer, $request->firstname));
return view('auth.register-success', ['mail' => $request->email]);
});
} catch (ApiErrorException $e) {
if ($e->getApiError()->equals(ApiError::customerExists())) {
return back()->withInput()->withErrors('Un compte est déjà associé à cette adresse email.');
}
if ($e->getApiError()->equals(ApiError::validationFailed())) {
return back()->withInput()->withErrors($e->getMessage());
}
report($e);
return back()->withErrors('Une erreur est survenue, merci de réessayer ultérieurement.');
} catch (ModelNotFoundException $e) {
return back()->withErrors("Salarié $request->matricule, $request->code introuvable.");
} catch (ValidationException $e) {
return back()->withErrors($e->getMessage());
} catch (\Exception | \TypeError | CrmException $e) {
report($e);
// * Une erreur critique est survenue avec la CRM
return back()->withErrors('Une erreur est survenue, merci de réessayer ultérieurement.');
} //end try
return back()->withErrors('Une erreur est survenue, merci de réessayer ultérieurement.');
}
/**
* Retourne la page de connexion
*
* @param Request $request
* @return \Illuminate\Http\Response
*/
public function authenticateForm(Request $request)
{
if (Auth::guard('customer')->check()) {
return redirect()->route('account.dashboard');
}
if ($request->get('url')) {
Session::put('url.intended', $request->get('url'));
Session::save();
}
return view('auth.login');
}
/**
* Gère l'authentification des customers
*
* @param LoginRequest $request
* @return \Illuminate\Http\RedirectResponse
*/
public function authenticate(LoginRequest $request)
{
/** @var Customers|null */
$customer = Customers::where('email', $request->email)->first();
try {
/** @var \LDC\LDCCRM\CrmApiV2 */
$crm = app('crmAPI');
// * Ne devrait pas survenir, $crm->login throws ApiError::authFailed()
if (!$crm->login($request->email, $request->password)) {
// * mauvais identifiants
return back()->withErrors('Email ou mot de passe incorrect.');
}
// Dans tout les cas : récupérer le crm user.
$crmCustomer = $crm->getCustomer($request->email);
// Si pas de compte local mais existe en CRM.
if (!$customer) {
$customer = $this->createLocalCustomer($crmCustomer);
}
return $this->processLogin($customer, $request->remember);
} catch (ApiErrorException $e) {
return $this->handleLoginApiErrorException($e, $request);
} catch (CrmException | \Exception $e) {
report($e);
// Une erreur critique est survenue avec la CRM.
return back()->withErrors('Une erreur est survenue, merci de réessayer ultérieurement.');
} //end try
}
/**
* Active le compte d'un customer
*
* @param mixed $hashcode
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
*/
public function activate($hashcode)
{
$hashcode = filter_var($hashcode, FILTER_SANITIZE_STRING);
if (!($customer = Customers::select('hashcode')->where('hashcode', $hashcode)->first())) {
return view('auth.activate')->with('message', 'Ce lien d\'activation n\'est pas valide.');
}
try {
/** @var \LDC\LDCCRM\Models\Customer $crmCustomer */
$crmCustomer = $customer->apiData;
if ($crmCustomer->activate()) {
return view('auth.activate')
->with('message', 'Votre compte a bien été activé, vous pouvez désormais vous connecter.');
}
} catch (ApiErrorException $e) {
if ($e->getApiError()->equals(ApiError::customerAlreadyActive())) {
// phpcs:disable Generic.Files.LineLength.TooLong
return view('auth.activate')
->with('message', 'Votre compte est déjà activé, vous pouvez dès à présent vous connecter avec celui-ci.');
}
report($e);
// Une erreur critique est survenue avec la CRM.
return view('auth.activate')
->with('message', 'Une erreur est survenue, merci de réessayer ultérieurement.');
} catch (CrmException $e) {
report($e);
// Une erreur critique est survenue avec la CRM.
return view('auth.activate')
->with('message', 'Une erreur est survenue, merci de réessayer ultérieurement.');
} //end try
return view('auth.activate')->with('message', 'Ce lien d\'activation n\'est pas valide.');
}
/**
* deconnexion customer
*
* @return \Illuminate\Http\RedirectResponse
*/
public function logout()
{
if (Auth::guard('customer')->check()) {
Auth::guard('customer')->logout();
return redirect()->route('home');
}
}
/**
* page d'accès à la procédure mdp oublié
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Contracts\View\View
*
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClass
*/
public function forgotPasswordForm(Request $request)
{
// @phpcs:enable
return view('auth.passwords.forgot');
}
/**
* initialisation de la procédure de mdp oublié
*
* @param Request $request
* @return \Illuminate\Http\RedirectResponse
*/
public function passwordReset(Request $request)
{
$request->validate([
'email' => 'required|email:rfc|max:255',
]);
$email = filter_var($request->email, FILTER_SANITIZE_EMAIL);
$customerExist = Customers::where('email', $email)->count() === 0 ? false : true;
if ($customerExist) {
// Suppression des anciens tokens.
PasswordReset::where('email', $email)->delete();
$token = Str::random(80);
$passwordReset = new PasswordReset();
$passwordReset->email = $email;
$passwordReset->token = $token;
$passwordReset->created_at = now();
$passwordReset->save();
Mail::to($email)->send(new PasswordResetMail($token));
return back()->with(
'success',
__("La procédure pour changer votre mot de passe a été envoyé sur votre email.")
);
} else {
return back()->withErrors(__("Cette adresse email n'est pas enregistrée dans nos services."));
}
}
/**
* Print the view used to change the password of a user when he required it
* @param string $token Token used to identificate the user to change the password.
* @return \Illuminate\Contracts\View\View The view to print
*/
public function viewChangePassword(string $token)
{
$pwdReset = PasswordReset::where('token', $token)->first();
if (!$pwdReset) {
abort(419);
}
$customer = Customers::where('email', $pwdReset->email)->first();
if (!$customer) {
abort(404);
}
return view('auth.passwords.reset', compact('customer'))->with('token', $token);
}
/**
* changement de mot de passe (depuis la procédure de mdp oublié)
*
* @param Request $request
* @param mixed $token
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
*/
public function changePassword(Request $request, $token)
{
$request->validate([
'password' => 'required|confirmed|min:8|max:255'
]);
/** @var \App\Models\PasswordReset $passwordReset */
$passwordReset = PasswordReset::where('token', $token)->first();
/** @var \App\Models\Customers $customer */
$customer = Customers::where('email', optional($passwordReset)->email)->firstOrFail();
/** @var \LDC\LDCCRM\CrmApiV2 */
$crm = app('crmAPI');
try {
if ($crm->login($customer->email, $request->password)) {
return back()->withErrors('Vous ne pouvez pas utiliser un de vos anciens mot de passe.');
}
// phpcs:ignore Generic.CodeAnalysis.EmptyStatement.DetectedCatch
} catch (ApiErrorException $e) {
// * continue
}
try {
if (!($crmCustomer = $crm->getCustomer($customer->hashcode))) {
return back()
->withErrors('Changement impossible, compte inexistant.');
}
$crmCustomer->password = $request->password;
$crmCustomer->save();
} catch (\TypeError | CrmException | ApiErrorException $e) {
report($e);
// Une erreur critique est survenue avec la CRM.
return back()->withErrors('Une erreur est survenue, merci de réessayer ultérieurement.');
} catch (ValidationException $e) {
return back()->withErrors(sprintf('Nouveau mot de passe : %s', $e->getMessage()));
}
$passwordReset->deleteOrFail();
return view('auth.passwords.reset-ok', compact('customer'));
}
/**
* profil client (mon compte)
*
* @param Request $request
* @return \Illuminate\Contracts\View\View
*
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClass
*/
public function dashboard(Request $request)
{
// @phpcs:enable
// Show Profile.
/** @var \App\Models\Customers|null $customer */
$customer = Auth::guard('customer')->user();
if (!$customer) {
abort(404);
}
/** @var \LDC\LDCCRM\Models\Customer $crmCustomer */
$crmCustomer = $customer->apiData;
/** @var object $crmInfos */
$crmInfos = \json_decode(\json_encode($crmCustomer));
$birthDate = explode('-', $crmCustomer->birth_date);
return view('customer.dashboard', compact('customer', 'crmInfos', 'birthDate'));
}
/**
* Send a request to the CRM to change the given customer's informations
* @param UpdateInfosRequest $request
* @return \Illuminate\Http\RedirectResponse
*/
public function updateInfos(UpdateInfosRequest $request)
{
if (($result = $this->updateUserInfo($request)) === true) {
return back()->with('success', trans(
'Vos informations ont bien été enregistrées.'
));
}
return back()->withInput()->withErrors(
$result !== false ? $result : trans(
'Une erreur est survenue, merci de réessayer ultérieurement.'
)
);
}
/**
* changement de mot de passe depuis le profil
*
* @param Request $request
* @return \Illuminate\Http\RedirectResponse
*/
public function changePasswordWhenAuthenticated(Request $request)
{
$request->validate([
'password' => 'required|min:8|confirmed|max:255'
]);
$crm = app('crmApi');
$customer = $crm->changePwdCustomer(Auth::guard('customer')->user()->crm_id, $request->password);
if ($customer->status === "OK") {
return back()->with('success', __("Modifications enregistrés !"));
} else {
return back()->withErrors(__("Une erreur est survenue, merci de réessayer ultérieurement."));
}
}
/**
* affichage des commandes du customer connecté
*
* @param Request $request
* @return \Illuminate\Contracts\View\View
*
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClass
*/
public function myOrders(Request $request)
{
// @phpcs:enable
$orders = Order::where('customer_id', Auth::guard('customer')->user()->id)->orderBy('date', 'DESC')->get();
return view('customer.my-orders', compact('orders'));
}
/**
* Show detail commande
*
* @param string $reference
* @return \Illuminate\Contracts\View\View
*/
public function orderDetail(string $reference)
{
$order = Order::where('reference', '=', $reference)
->where('customer_id', Auth::guard('customer')->user()->id)
->firstOrFail();
if ($order->status_id == 1) {
$magasin = null;
} else {
$magasin = Magasin::find($order->timeslot->magasin->id);
}
return view('customer.order-detail', compact('order', 'magasin'));
}
/**
* delete customers
*
* @param integer $id
* @return void
*/
public function delete(int $id)
{
dump('deleting' . $id);
die('Not implemented yet');
}
/**
* Create a local customer
*
* @param CrmCustomer $crmCustomer
* @return \app\Models\Customers
* @throws \Throwable If saving to DB failed.
*/
private function createLocalCustomer(CrmCustomer $crmCustomer): Customers
{
/** @var \App\Models\Customers $customer */
$customer = Customers::firstOrNew([
'email' => $crmCustomer->email
]);
$customer->hashcode = $crmCustomer->hashcode;
$customer->saveOrFail();
return $customer;
}
/**
* Handle Api error exception
*
* @param ApiErrorException $e
* @param LoginRequest $request
* @return \Illuminate\Http\RedirectResponse
*/
private function handleLoginApiErrorException(ApiErrorException $e, LoginRequest $request)
{
/** @var Customers|null */
$customer = Customers::where('email', $request->email)->first();
/** @var \LDC\LDCCRM\CrmApiV2 */
$crm = app('crmAPI');
switch ($e->getApiError()) {
case ApiError::authFailed():
// * mauvais identifiants
return back()->withErrors('Email ou mot de passe incorrect.');
case ApiError::customerNotActivated():
// * le compte n'est pas activé
if (!$customer) {
try {
if (!($crmCustomer = $crm->getCustomer($request->email))) {
Log::critical(sprintf('Customer %s coulnd not be retrieved from crm', $request->email));
return back()->withErrors(
trans('Une erreur est survenue, merci de réessayer ultérieurement.')
);
}
$customer = $this->createLocalCustomer($crmCustomer);
} catch (CrmException | ApiErrorException $e) {
report($e);
// Une erreur critique est survenue avec la CRM.
return back()->withErrors('Une erreur est survenue, merci de réessayer ultérieurement.');
}
}
Mail::to($request->email)->send(new RegisterConfirmMail($customer, null));
return back()
->withErrors(
trans('Votre compte n\'est pas activé, vérifiez dans vos emails pour y trouver
le mail de confirmation. Un lien d\'activation vous a été renvoyé.')
);
default:
report($e);
// * une erreur non gérée
return back()->withErrors('Une erreur est survenue, merci de réessayer ultérieurement.');
} //end switch
}
/**
* Login a customer
*
* @param Customers $customer
* @param boolean $remember
* @return \Illuminate\Routing\Redirector|\Illuminate\Http\RedirectResponse
*/
private function processLogin(Customers $customer, bool $remember)
{
/** @var \Illuminate\Auth\SessionGuard */
$guard = auth('customer');
$guard->login($customer, $remember);
$url = Session::pull('url.intended');
Session::forget('url.intended');
Session::save();
return !empty($url) ? redirect()->to($url) : redirect()->route('account.dashboard');
}
/**
* Updates user info
*
* @param UpdateInfosRequest $request
* @return boolean|string return strictly true if success,
* false il failed, could be a string with message error if failed
*/
private function updateUserInfo(UpdateInfosRequest $request)
{
/** @var \App\Models\Customers */
$customer = auth('customer')->user();
if (!$customer) {
return \redirect()->back();
}
/** @var \LDC\LDCCRM\Models\Customer */
$crmCustomer = $customer->apiData;
$data = [
'firstname' => $request->firstname,
'lastname' => $request->lastname,
'birth_date' => $request->year . '-' . $request->month . '-' . $request->day,
'address' => $request->address,
'postcode' => $request->postcode,
'city' => $request->city,
'phone' => \strval($request->phone),
'opt_in' => \boolval($request->optin),
];
// * remove phone if empty
if (isset($data['phone']) and !strlen($data['phone'])) {
unset($data['phone']);
}
try {
$crmCustomer->fill($data);
$crmCustomer->save();
} catch (ValidationException $e) {
return $e->getMessage();
} catch (ApiErrorException $e) {
if ($e->getApiError()->equals(ApiError::validationFailed())) {
return $e->getMessage();
}
report($e);
return false;
} catch (CrmException | \TypeError $e) {
report($e);
return false;
}
return true;
}
}