validated(); /** @var \App\Models\Customer */ $customer = Customer::where('email', $data->email)->firstOrCreate([ 'email' => $data->email ]); DB::transaction(function () use (&$customer, $data, $request, $service) { $saved = $customer->save(); $customer->setOptIn($service->brand, $data->opt_in); // * Delete Single optin if exists. /** @var \App\Models\SingleOptin|null $singleOptin */ $singleOptin = SingleOptin::where('email', $data->email) ->where('brand_id', $service->brand->id)->first(); if ($singleOptin) { $saved = $singleOptin->delete() && $saved; } /** @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); $saved = $customerInfo->save() && $saved; /** @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); $saved = $customerLogin->save() && $saved; if (!$saved) { // @codeCoverageIgnoreStart throw new CrmException('Api failed to store customer.'); // @codeCoverageIgnoreEnd } }); return new CustomerResource($service->brand, $customer); } /** * Renders the specific customer infos * * @param \App\Models\Service $service * @param \App\Models\Customer $customer * @return \Illuminate\Http\Resources\Json\JsonResource */ public function show(Service $service, Customer $customer): JsonResource { // * Make sure we are accessing a customer that belongs to our service. $this->authorize('customerBelongsToService', $customer); return new CustomerResource($service->brand, $customer); } /** * Updates information for a specific customer * * @param \App\Http\Requests\Api\V2\UpdateCustomerRequest $request * @param \App\Models\Service $service * @param \App\Models\Customer $customer * @return \Illuminate\Http\Resources\Json\JsonResource * @throws \App\Exceptions\Api\V2\CrmException If saving the customer to DB failed. */ public function update(UpdateCustomerRequest $request, Service $service, Customer $customer): JsonResource { // * Make sure we are accessing a customer that belongs to our service. $this->authorize('customerBelongsToService', $customer); DB::transaction(function () use ($request, $customer, $service) { // To correct with create. $customer->fill($request->validated()); $saved = $customer->save(); 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()); $saved = $customerInfo->save() && $saved; /** @var \App\Models\CustomerLogin */ $customerLogin = $customer->login($service->brand, Customer::FIRST_OR_FAIL); $customerLogin->fill($request->validated()); $saved = $customerLogin->save() && $saved; if (!$saved) { // @codeCoverageIgnoreStart throw new CrmException('Api failed to update customer.'); // @codeCoverageIgnoreEnd } }); return new CustomerResource($service->brand, $customer); } /** * Deletes customer information for a specific service * * @param \App\Models\Service $service * @param \App\Models\Customer $customer * @return \Illuminate\Http\JsonResponse * @throws \App\Exceptions\Api\V2\CrmException If removing the customer off the DB failed. */ public function destroy(Service $service, Customer $customer): JsonResponse { // * Make sure we are accessing a customer that belongs to our service. $this->authorize('customerBelongsToService', $customer); // 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); DB::transaction(function () use ($service, $customer, $customerLogin, $customerInfo) { if ( $customerInfo->delete() === false || $customerLogin->delete() === false ) { // @codeCoverageIgnoreStart throw new CrmException('Api failed to delete customer.'); // @codeCoverageIgnoreEnd }; $customer->optInHistory()->whereHas('brand', function ($q) use ($service) { $q->where('id', $service->brand_id); })->delete(); // * Force loading real relation counts. $customer->unsetRelation('logins'); $customer->unsetRelation('infos'); $logins = $customer->logins()->count(); $infos = $customer->infos()->count(); // If customer is not associated with any brand then delete. if (!$logins and !$infos) { if ($customer->delete() === false) { // @codeCoverageIgnoreStart throw new CrmException('Api failed to update customer.'); // @codeCoverageIgnoreEnd } } }); return response()->json(); } /** * Authenticate the user * * @param \App\Http\Requests\Api\V2\AuthenticateRequest $request * @param \App\Models\Service $service * @return \Illuminate\Http\Resources\Json\JsonResource * @throws \App\Exceptions\Api\V2\ApiErrorException With ApiError::authFailed() in case * of wrong credentials. * @throws \App\Exceptions\Api\V2\ApiErrorException With ApiError::customerNotActivated() if * customer account is not activated. */ public function authenticate(AuthenticateRequest $request, Service $service): JsonResource { try { /** @var \App\Models\Customer */ $customer = Customer::where('email', $request->email)->firstOrFail(); /** @var \App\Models\CustomerLogin $customerLogin */ $customerLogin = $customer->login($service->brand, Customer::FIRST_OR_FAIL); 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')->afterResponse(); return new CustomerResource($service->brand, $customer); } catch (ModelNotFoundException $e) { throw new ApiErrorException(ApiError::authFailed()); } //end try } /** * Activate the account of the user * * @param \App\Models\Customer $customer * @param \App\Models\Service $service * @return \Illuminate\Http\JsonResponse * @throws \App\Exceptions\Api\V2\ApiErrorException With ApiError::customerAlreadyActive * if customer account is already active. * @throws \App\Exceptions\Api\V2\CrmException If saving the customer to DB failed. */ public function activateAccount(Customer $customer, Service $service) { // * Make sure we are accessing a customer that belongs to our service. $this->authorize('customerBelongsToService', $customer); /** @var \App\Models\CustomerLogin $login */ $login = $customer->login($service->brand, Customer::FIRST_OR_FAIL); if ($login->status) { throw new ApiErrorException(ApiError::customerAlreadyActive()); } $login->status = true; if (!$login->save()) { // @codeCoverageIgnoreStart throw new CrmException('Failed to save login'); // @codeCoverageIgnoreEnd } return response()->json(); } }