ldc-crm/app/Http/Controllers/Api/V2/CustomerController.php
2021-10-26 12:01:40 +02:00

212 lines
7.6 KiB
PHP

<?php
namespace App\Http\Controllers\Api\V2;
use App\Enums\ApiError;
use App\Exceptions\Api\V2\ApiErrorException;
use App\Exceptions\Api\V2\CrmException;
use App\Http\Controllers\Controller;
use App\Http\Requests\Api\V2\AuthenticateRequest;
use App\Http\Requests\Api\V2\StoreCustomerRequest;
use App\Http\Requests\Api\V2\UpdateCustomerRequest;
use App\Http\Resources\Api\V2\CustomerResource;
use App\Jobs\UpdateCustomerLastConnection;
use App\Models\Customer;
use App\Models\Service;
use App\Models\SingleOptin;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Resources\Json\JsonResource;
class CustomerController extends Controller
{
/**
* Store a newly created resource in storage.
*
* @param \App\Request\StoreCustomerRequest $request
* @param \App\Models\Service $service
* @return \Illuminate\Http\Resources\Json\JsonResource
*/
public function store(StoreCustomerRequest $request, Service $service): JsonResource
{
$data = (object)$request->validated();
/** @var \App\Models\Customer */
$customer = Customer::where('email', $data->email)->firstOrCreate([
'email' => $data->email
]);
$customer->saveOrFail();
$customer->setOptIn($service->brand, $data->opt_in);
// Delete Single optin if exists
if (
$singleOptin = SingleOptin::where('email', $data->email)
->where('brand_id', $service->brand->id)->first()
) {
$singleOptin->delete();
}
/** @var \App\Models\CustomerInfo */
$customerInfo = $customer->info($service->brand, Customer::FIRST_OR_NEW);
if ($customerInfo->exists) {
throw new ApiErrorException(ApiError::customerExists());
}
$customerInfo->fill($request->validated());
$customerInfo->brand()->associate($service->brand);
$customerInfo->customer()->associate($customer);
$customerInfo->saveOrFail();
/** @var \App\Models\CustomerLogin */
$customerLogin = $customer->login($service->brand, Customer::FIRST_OR_NEW);
$customerLogin->fill($request->validated());
$customerLogin->brand()->associate($service->brand);
$customerLogin->customer()->associate($customer);
$customerLogin->saveOrFail();
return new CustomerResource($service->brand, $customer);
}
/**
* Display the specified resource.
*
* @param \App\Models\Service $service
* @param \App\Models\Customer $customer
* @return \Illuminate\Http\Resources\Json\JsonResource
*/
public function show(Customer $customer, Service $service): JsonResource
{
$this->authorize('customerBelongsToService', $customer);
return new CustomerResource($service->brand, $customer);
}
/**
* Update the specified resource in storage.
*
* @param \App\Request\UpdateCustomerRequest $request
* @param \App\Models\Service $service
* @param \App\Models\Customer $customer
* @return \Illuminate\Http\Resources\Json\JsonResource
*/
public function update(UpdateCustomerRequest $request, Customer $customer, Service $service): JsonResource
{
$this->authorize('customerBelongsToService', $customer);
// To correct with create
$customer->fill($request->all());
if ($customer->saveOrFail() === false) {
throw new CrmException(sprintf('Could not update customer %d', $customer));
}
if ($request->has('opt_in')) {
$customer->setOptIn($service->brand, $request->opt_in);
}
/** @var \App\Models\CustomerInfo */
$customerInfo = $customer->info($service->brand, Customer::FIRST_OR_FAIL);
$customerInfo->fill($request->validated());
$customerInfo->saveOrFail();
/** @var \App\Models\CustomerLogin */
$customerLogin = $customer->login($service->brand, Customer::FIRST_OR_FAIL);
$customerLogin->fill($request->validated());
$customerLogin->saveOrFail();
return new CustomerResource($service->brand, $customer);
}
/**
* Remove the specified resource from storage.
*
* @param \App\Models\Service $service
* @param \App\Models\Customer $customer
* @return \Illuminate\Http\JsonResponse
*/
public function destroy(Customer $customer, Service $service): JsonResponse
{
$this->authorize('customerBelongsToService', $customer);
// TODO : A voir pour les stats, obuton dans le bo qui permet de faire les stats sur les customer puis supprimer
// TODO : Gestion avec mesBR
/** @var \App\Models\CustomerInfo */
$customerInfo = $customer->info($service->brand, Customer::FIRST_OR_FAIL);
/** @var \App\Models\CustomerLogin */
$customerLogin = $customer->login($service->brand, Customer::FIRST_OR_FAIL);
if (
!$customerInfo->delete() ||
!$customerLogin->delete() ||
$customer->optInHistory()->whereHas('brand', function ($q) use ($service) {
$q->where('id', $service->brand_id);
})->delete() === false
) {
throw new CrmException(sprintf(
'Could not delete customer %d for brand %d',
$customer->id,
$service->brand->id
));
};
$logins = $customer->logins()->count();
$infos = $customer->infos()->count();
$history = $customer->optInHistory()->count();
// If customer is not associated with any brand then delete
if (!$logins and !$infos and !$history) {
if ($customer->delete() === false) {
throw new CrmException(sprintf(
'Could not delete customer %d',
$customer->id
));
}
}
return response()->json();
}
/**
* Authenticate the user
* @param \App\Models\Service $service
* @param \App\Request\AuthenticateRequest $request
* @return \Illuminate\Http\Resources\Json\JsonResource
*/
public function authenticate(AuthenticateRequest $request, Service $service): JsonResource
{
try {
/** @var \App\Models\Customer */
$customer = Customer::where('email', $request->email)->firstOrFail();
$customer->loadBrandData($service->brand, true);
$customerLogin = $customer->logins->first();
} catch (ModelNotFoundException $e) {
throw new ApiErrorException(ApiError::authFailed());
}
if (!$customerLogin->passwordMatch($request->password)) {
throw new ApiErrorException(ApiError::authFailed());
}
if (!$customerLogin->status) {
throw new ApiErrorException(ApiError::customerNotActivated());
}
UpdateCustomerLastConnection::dispatch($customer, $customerLogin, now())
->onConnection('database');
return new CustomerResource($service->brand, $customer);
}
/**
* Activate the account of the user
* @param Customer $customer
* @param Service $service
* @return \Illuminate\Http\JsonResponse
*/
public function activateAccount(Customer $customer, Service $service)
{
$this->authorize('customerBelongsToService', $customer);
$login = $customer->login($service->brand, Customer::FIRST_OR_FAIL);
if (!$login->status) {
$login->status = true;
$login->save();
return response()->json();
} else {
throw new ApiErrorException(ApiError::customerAlreadyActive());
}
}
}