- tag 2.0.1
- Add Questions segementation - Fix Customer delete Tests
This commit is contained in:
parent
642d3cce08
commit
787ee5a4c5
30 changed files with 533 additions and 46 deletions
|
|
@ -7,6 +7,7 @@ use App\Enums\ApiStatus;
|
|||
use App\Enums\ArcadiaMailType;
|
||||
use App\Enums\ArcadiaOrderType;
|
||||
use App\Enums\Country;
|
||||
use App\Enums\QuestionType;
|
||||
use App\Exceptions\Api\V2\ApiErrorException;
|
||||
use App\Exceptions\Api\V2\CrmException;
|
||||
use Illuminate\Console\Command;
|
||||
|
|
@ -106,7 +107,8 @@ class GenerateCrmClient extends Command
|
|||
ApiStatus::class,
|
||||
ArcadiaMailType::class,
|
||||
ArcadiaOrderType::class,
|
||||
Country::class
|
||||
Country::class,
|
||||
QuestionType::class
|
||||
], 'Enums');
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,8 +3,28 @@
|
|||
namespace App\Http\Controllers\Api\V2;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Api\V2\StoreCustomerAnswers;
|
||||
use App\Models\Answer;
|
||||
use App\Models\Customer;
|
||||
use App\Models\Service;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
class AnswerController extends Controller
|
||||
{
|
||||
//
|
||||
/**
|
||||
* Store the customer answers
|
||||
*
|
||||
* @param \App\Http\Requests\Api\V2\StoreCustomerAnswers $request
|
||||
* @param \App\Models\Service $service
|
||||
* @param \App\Models\Customer $customer
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassBeforeLastUsed
|
||||
public function storeCustomerAnswers(StoreCustomerAnswers $request, Service $service, Customer $customer): JsonResponse
|
||||
{
|
||||
$this->authorize('customerBelongsToService', $customer);
|
||||
$answersID = Answer::whereIn('id', $request->answers)->pluck('id')->toArray();
|
||||
$customer->answers()->sync($answersID);
|
||||
return \response()->json();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,11 +32,13 @@ class ArcadiaController extends Controller
|
|||
{
|
||||
public function outgoingMailDefault(SendArchadiaDefaultMailRequest $request, Customer $customer, Service $service)
|
||||
{
|
||||
$this->authorize('customerBelongsToService', $customer);
|
||||
return $this->handleArcadiaMail($request, ArcadiaMailType::default(), $customer, $service);
|
||||
}
|
||||
|
||||
public function outgoingMailGame(SendArchadiaGameMailRequest $request, Customer $customer, Service $service)
|
||||
{
|
||||
$this->authorize('customerBelongsToService', $customer);
|
||||
return $this->handleArcadiaMail($request, ArcadiaMailType::game(), $customer, $service);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -73,6 +73,7 @@ class CustomerController extends Controller
|
|||
*/
|
||||
public function show(Customer $customer, Service $service): JsonResource
|
||||
{
|
||||
$this->authorize('customerBelongsToService', $customer);
|
||||
return new CustomerResource($service->brand, $customer);
|
||||
}
|
||||
|
||||
|
|
@ -86,6 +87,7 @@ class CustomerController extends Controller
|
|||
*/
|
||||
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) {
|
||||
|
|
@ -117,6 +119,7 @@ class CustomerController extends Controller
|
|||
*/
|
||||
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 */
|
||||
|
|
@ -124,13 +127,31 @@ class CustomerController extends Controller
|
|||
/** @var \App\Models\CustomerLogin */
|
||||
$customerLogin = $customer->login($service->brand)->firstOrFail();
|
||||
|
||||
if (!$customerInfo->delete() || !$customerLogin->delete()) {
|
||||
throw new CrmException(sprintf('Could not delete customer %d for brand %d', $customer, $service->brand));
|
||||
}
|
||||
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
|
||||
));
|
||||
};
|
||||
|
||||
if (!$customer->logins()->count() and !$customer->infos()->count()) {
|
||||
$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));
|
||||
throw new CrmException(sprintf(
|
||||
'Could not delete customer %d',
|
||||
$customer->id
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -176,6 +197,7 @@ class CustomerController extends Controller
|
|||
*/
|
||||
public function activateAccount(Customer $customer, Service $service)
|
||||
{
|
||||
$this->authorize('customerBelongsToService', $customer);
|
||||
$login = $customer->login($service->brand)->firstOrFail();
|
||||
|
||||
if ($login->status === 0) {
|
||||
|
|
|
|||
|
|
@ -3,8 +3,69 @@
|
|||
namespace App\Http\Controllers\Api\V2;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Resources\Api\V2\QuestionsResource;
|
||||
use App\Models\Answer;
|
||||
use App\Models\Customer;
|
||||
use App\Models\Question;
|
||||
use App\Models\Service;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
use Illuminate\Http\Resources\Json\ResourceCollection;
|
||||
|
||||
class QuestionController extends Controller
|
||||
{
|
||||
//
|
||||
/**
|
||||
* Display all specified resources.
|
||||
*
|
||||
* @param \App\Models\Service $service
|
||||
* @return \Illuminate\Http\Resources\Json\JsonResource
|
||||
*/
|
||||
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassAfterLastUsed
|
||||
public function index(Service $service): ResourceCollection
|
||||
{
|
||||
return new QuestionsResource($service->brand->questions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display all specified resources.
|
||||
*
|
||||
* @param \App\Models\Service $service
|
||||
* @return \Illuminate\Http\Resources\Json\JsonResource
|
||||
*/
|
||||
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassAfterLastUsed
|
||||
public function indexWithResponse(Service $service, Customer $customer): ResourceCollection
|
||||
{
|
||||
$this->authorize('customerBelongsToService', $customer);
|
||||
$customerAnswers = Answer::whereHas('customers', function ($q) use ($customer) {
|
||||
$q->whereId($customer->id);
|
||||
})->get();
|
||||
$customerAnswers = Answer::whereHas('customers', function ($q) use ($customer) {
|
||||
$q->whereId($customer->id);
|
||||
})->whereHas('question', function ($q) use ($service) {
|
||||
$q->whereHas('brand', function ($q) use ($service) {
|
||||
$q->whereId($service->brand->id);
|
||||
});
|
||||
})->get();
|
||||
return new QuestionsResource($service->brand->questions, $customerAnswers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display all specified resource by customer.
|
||||
*
|
||||
* @param \App\Models\Service $service
|
||||
* @param \App\Models\Customer $customer
|
||||
* @return \Illuminate\Http\Resources\Json\JsonResource
|
||||
*/
|
||||
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassAfterLastUsed
|
||||
public function unAnsweredBy(Service $service, Customer $customer): JsonResource
|
||||
{
|
||||
$this->authorize('customerBelongsToService', $customer);
|
||||
$questions = Question::whereHas('brand', function ($q) use ($service) {
|
||||
$q->where('id', $service->brand->id);
|
||||
})->whereDoesntHave('answers', function ($q) use ($customer) {
|
||||
$q->whereIn('id', Answer::whereHas('customers', function ($q) use ($customer) {
|
||||
$q->where('id', $customer->id);
|
||||
})->pluck('id'));
|
||||
})->with('answers')->get();
|
||||
return new QuestionsResource($questions);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
47
app/Http/Requests/Api/V2/StoreCustomerAnswers.php
Normal file
47
app/Http/Requests/Api/V2/StoreCustomerAnswers.php
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests\Api\V2;
|
||||
|
||||
use App\Models\Answer;
|
||||
use App\Models\Question;
|
||||
|
||||
class StoreCustomerAnswers extends BaseApiRequest
|
||||
{
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
// resolve Service
|
||||
$service = app()->make(\App\Models\Service::class);
|
||||
$brandId = $service->brand->id;
|
||||
$question = Question::findOrFail($this->question);
|
||||
$questionTableName = (new Question())->getTable();
|
||||
$answerTableName = (new Answer())->getTable();
|
||||
return [
|
||||
'question' => [
|
||||
'required',
|
||||
"exists:$questionTableName,id",
|
||||
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassBeforeLastUsed
|
||||
function ($attribute, $value, $fail) use ($question, $brandId) {
|
||||
if ($question->brand->id !== $brandId) {
|
||||
$fail("$attribute does not belong to brand $brandId");
|
||||
}
|
||||
}
|
||||
],
|
||||
'answers' => 'required|array',
|
||||
'answers.*' => [
|
||||
'int',
|
||||
'distinct',
|
||||
"exists:$answerTableName,id",
|
||||
function ($attribute, $value, $fail) use ($question) {
|
||||
if (Answer::findOrFail($value)->question->id !== $question->id) {
|
||||
$fail("$attribute does not belong to question $question->id");
|
||||
}
|
||||
}
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
||||
26
app/Http/Resources/Api/V2/AnswersResource.php
Normal file
26
app/Http/Resources/Api/V2/AnswersResource.php
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Resources\Api\V2;
|
||||
|
||||
use App\Models\Answer;
|
||||
use Illuminate\Http\Resources\Json\ResourceCollection as JsonResourceCollection;
|
||||
|
||||
class AnswersResource extends JsonResourceCollection
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return array
|
||||
*/
|
||||
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClass
|
||||
public function toArray($request)
|
||||
{
|
||||
return $this->collection->map(function (Answer $answer) {
|
||||
return [
|
||||
'id' => $answer->id,
|
||||
'answer' => $answer->answer
|
||||
];
|
||||
});
|
||||
}
|
||||
}
|
||||
34
app/Http/Resources/Api/V2/QuestionResource.php
Normal file
34
app/Http/Resources/Api/V2/QuestionResource.php
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Resources\Api\V2;
|
||||
|
||||
use App\Models\Question;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class QuestionResource extends JsonResource
|
||||
{
|
||||
|
||||
/** @var Question */
|
||||
private $question;
|
||||
|
||||
public function __construct(Question $question)
|
||||
{
|
||||
$this->question = $question;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return array
|
||||
*/
|
||||
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClass
|
||||
public function toArray($request)
|
||||
{
|
||||
return [
|
||||
'id' => $this->question->id,
|
||||
'question' => $this->question->question,
|
||||
'answers' => new AnswersResource($this->question->answers)
|
||||
];
|
||||
}
|
||||
}
|
||||
49
app/Http/Resources/Api/V2/QuestionsResource.php
Normal file
49
app/Http/Resources/Api/V2/QuestionsResource.php
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Resources\Api\V2;
|
||||
|
||||
use App\Models\Question;
|
||||
use Illuminate\Http\Resources\Json\ResourceCollection as JsonResourceCollection;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
class QuestionsResource extends JsonResourceCollection
|
||||
{
|
||||
|
||||
/** @var \Illuminate\Support\Collection */
|
||||
protected $userAnwsers = null;
|
||||
|
||||
/**
|
||||
* Create a new resource instance.
|
||||
*
|
||||
* @param mixed $resource
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($resource, Collection $userAnwsers = null)
|
||||
{
|
||||
$this->userAnwsers = $userAnwsers;
|
||||
parent::__construct($resource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return array
|
||||
*/
|
||||
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClass
|
||||
public function toArray($request)
|
||||
{
|
||||
return $this->collection->map(function (Question $question) {
|
||||
$question = [
|
||||
'id' => $question->id,
|
||||
'type' => $question->type->value,
|
||||
'question' => $question->question,
|
||||
'answers' => new AnswersResource($question->answers)
|
||||
];
|
||||
if ($this->userAnwsers) {
|
||||
$question['customerAnswers'] = new AnswersResource($this->userAnwsers);
|
||||
}
|
||||
return $question;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -24,12 +24,12 @@ class Answer extends Model
|
|||
}
|
||||
|
||||
/**
|
||||
* Answer hasOneThrough relation
|
||||
* Answer belongsToMany relation
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\HasOneThrough
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
|
||||
*/
|
||||
public function customer()
|
||||
public function customers()
|
||||
{
|
||||
return $this->hasOneThrough(Customer::class, 'customer_answer');
|
||||
return $this->belongsToMany(Customer::class, 'customer_answer');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,16 @@ class Brand extends Model
|
|||
return $this->hasMany(Service::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Question hasMany relation
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||
*/
|
||||
public function questions()
|
||||
{
|
||||
return $this->hasMany(Question::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* CustomerInfo hasMany relation
|
||||
*
|
||||
|
|
|
|||
|
|
@ -84,6 +84,16 @@ class Customer extends Model
|
|||
return $this->belongsToMany(Brand::class, CustomerInfo::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Answers belongsToMany relation
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
|
||||
*/
|
||||
public function answers()
|
||||
{
|
||||
return $this->belongsToMany(Answer::class, 'customer_answer');
|
||||
}
|
||||
|
||||
public function setOptIn(Brand $brand, bool $optIn)
|
||||
{
|
||||
// Ajout dans la table d'historique des opt-in de la nouvelle valeur
|
||||
|
|
|
|||
|
|
@ -20,4 +20,14 @@ class CustomerOptInHistory extends Model
|
|||
{
|
||||
return $this->belongsTo(Customer::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Brand BelongsTo relation
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
public function brand()
|
||||
{
|
||||
return $this->belongsTo(Brand::class);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
17
app/Policies/CustomerPolicy.php
Normal file
17
app/Policies/CustomerPolicy.php
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
namespace App\Policies;
|
||||
|
||||
use App\Models\Customer;
|
||||
use App\Models\Service;
|
||||
use Illuminate\Auth\Access\HandlesAuthorization;
|
||||
|
||||
class CustomerPolicy
|
||||
{
|
||||
use HandlesAuthorization;
|
||||
|
||||
public function customerBelongsToService(Service $service, Customer $customer)
|
||||
{
|
||||
return $customer->login($service->brand)->exists();
|
||||
}
|
||||
}
|
||||
|
|
@ -52,6 +52,7 @@ class AuthServiceProvider extends ServiceProvider
|
|||
|
||||
try {
|
||||
$service = Service::getFromApiToken($apiToken);
|
||||
$service = $service->load('brand');
|
||||
app()->bind(Service::class, function () use ($service) {
|
||||
return $service;
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit eb69ef30e9d2512d26c9f2718ef4d7d054dd766b
|
||||
Subproject commit a336b3bfca10f6d383e585d68e80cc85b1b7295d
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "ldc/ldccrmv2client",
|
||||
"type": "project",
|
||||
"version": "2.0.0",
|
||||
"version": "2.0.1",
|
||||
"description": "LDC CRM V2",
|
||||
"authors": [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,8 +2,7 @@
|
|||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Enums\QuestionType;
|
||||
use App\Models\Question;
|
||||
use App\Models\Answer;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
class AnswerFactory extends Factory
|
||||
|
|
@ -14,7 +13,7 @@ class AnswerFactory extends Factory
|
|||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $model = Question::class;
|
||||
protected $model = Answer::class;
|
||||
|
||||
/**
|
||||
* Define the model's default state.
|
||||
|
|
@ -24,8 +23,7 @@ class AnswerFactory extends Factory
|
|||
public function definition()
|
||||
{
|
||||
return [
|
||||
'question' => $this->faker->name,
|
||||
'type' => collect(QuestionType::toArray())->random()->value,
|
||||
'answer' => $this->faker->realText(20),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ class QuestionFactory extends Factory
|
|||
public function definition()
|
||||
{
|
||||
return [
|
||||
'question' => $this->faker->name,
|
||||
'question' => $this->faker->realText(40),
|
||||
'type' => collect(QuestionType::toArray())->random()->value,
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ class CreateCustomerAnswerTable extends Migration
|
|||
public function up()
|
||||
{
|
||||
Schema::create('customer_answer', function (Blueprint $table) {
|
||||
$table->foreignId('question_id')->constrained('questions');
|
||||
$table->foreignId('answer_id')->constrained('answers');
|
||||
$table->foreignId('customer_id')->constrained('customers');
|
||||
$table->timestamp('created_at')->useCurrent();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -2,7 +2,9 @@
|
|||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Models\Answer;
|
||||
use App\Models\Brand;
|
||||
use App\Models\Question;
|
||||
use App\Models\Service;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
|
|
@ -20,6 +22,14 @@ class BrandSeeder extends Seeder
|
|||
Service::factory(1)->make()->each(
|
||||
/** @var \App\Models\Service $service*/
|
||||
function ($service) use ($brand) {
|
||||
Question::factory(10)->make()->each(function ($question) use ($brand) {
|
||||
$question->brand()->associate($brand);
|
||||
$question->save();
|
||||
Answer::factory(rand(3, 4))->make()->each(function ($answer) use ($question) {
|
||||
$answer->question()->associate($question);
|
||||
$answer->save();
|
||||
});
|
||||
});
|
||||
$service->brand()->associate($brand);
|
||||
$service->save();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ use App\Http\Controllers\Api\V2\ApiController as V2ApiController;
|
|||
use App\Http\Controllers\Api\V2\ArcadiaController as V2ArcadiaController;
|
||||
use App\Http\Controllers\Api\V2\CustomerController as V2CustomerController;
|
||||
use App\Http\Controllers\Api\V2\OptinController as V2OptinController;
|
||||
use App\Http\Controllers\Api\V2\AnswerController as V2AnswerController;
|
||||
use App\Http\Controllers\Api\V2\QuestionController as V2QuestionController;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
@ -43,11 +45,13 @@ Route::prefix('v2')->name('apiV2.')->group(function () {
|
|||
Route::post('/auth', [V2ApiController::class, 'authenticate'])->name('authenticate');
|
||||
Route::middleware('auth:api')->group(function () {
|
||||
Route::post('/optin', [V2OptinController::class, 'optin'])->name('optin');
|
||||
Route::apiResource('customer', V2CustomerController::class)->except(['index']);
|
||||
Route::prefix('customer')->name('customer.')->group(function () {
|
||||
Route::apiResource('customers', V2CustomerController::class)->except(['index']);
|
||||
Route::prefix('customers')->name('customers.')->group(function () {
|
||||
Route::post('/authenticate', [V2CustomerController::class, 'authenticate'])->name('authenticate');
|
||||
Route::prefix('{customer}')->group(function () {
|
||||
Route::post('/activate', [V2CustomerController::class, 'activateAccount'])->name('activate');
|
||||
Route::post('/answers', [V2AnswerController::class, 'storeCustomerAnswers'])
|
||||
->name('answers.store');
|
||||
});
|
||||
});
|
||||
Route::prefix('arcadia')->name('arcadia.')->group(function () {
|
||||
|
|
@ -56,5 +60,12 @@ Route::prefix('v2')->name('apiV2.')->group(function () {
|
|||
Route::post('/outgoing-mail/{customer}/game', [V2ArcadiaController::class, 'outgoingMailGame'])
|
||||
->name('outgoingMailGame');
|
||||
});
|
||||
Route::apiResource('questions', V2QuestionController::class)->only(['index']);
|
||||
Route::prefix('questions')->name('questions.')->group(function () {
|
||||
Route::get('/un-answered-by/{customer}', [V2QuestionController::class, 'unAnsweredBy'])
|
||||
->name('unAnsweredBy');
|
||||
Route::get('/with-answers/{customer}', [V2QuestionController::class, 'indexWithResponse'])
|
||||
->name('indexWithResponse');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -69,12 +69,16 @@ class ApiBase extends BaseTestCase
|
|||
* @param boolean $status the customer status for a brand
|
||||
* @return array
|
||||
*/
|
||||
protected function getCustomer(bool $status = true): array
|
||||
protected function getCustomer(bool $status = true, bool $random = true): array
|
||||
{
|
||||
/** @var \App\Models\Costumer $customer */
|
||||
$customer = Customer::whereHas('logins', function ($q) use ($status) {
|
||||
$q->where('status', $status);
|
||||
})->inRandomOrder()->firstOrFail();
|
||||
});
|
||||
if ($random) {
|
||||
$customer = $customer->inRandomOrder();
|
||||
}
|
||||
$customer = $customer->firstOrFail();
|
||||
/** @var \App\Models\Login $login */
|
||||
$login = $customer->logins()->where('status', $status)->firstOrFail();
|
||||
/** @var \App\Models\Brand $brand */
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ class ArcadiaTest extends ApiBase
|
|||
use DatabaseTransactions;
|
||||
|
||||
/**
|
||||
* route: apiV2.customer.arcadia.outgoingMail
|
||||
* route: apiV2.customers.arcadia.outgoingMail
|
||||
*/
|
||||
public function testArcadiaSendOrderDefault()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ class CustomerTest extends ApiBase
|
|||
}
|
||||
|
||||
/**
|
||||
* route: apiV2.customer.authenticate
|
||||
* route: apiV2.customers.authenticate
|
||||
*/
|
||||
public function testApiAuthenticateCustomer()
|
||||
{
|
||||
|
|
@ -42,7 +42,7 @@ class CustomerTest extends ApiBase
|
|||
$response = $this->callApiWithToken(
|
||||
$service,
|
||||
'post',
|
||||
route('apiV2.customer.authenticate', ['customer' => $info->hashcode]),
|
||||
route('apiV2.customers.authenticate', ['customer' => $info->hashcode]),
|
||||
[
|
||||
'email' => $customer->email,
|
||||
'password' => 'testPassword'
|
||||
|
|
@ -65,7 +65,7 @@ class CustomerTest extends ApiBase
|
|||
}
|
||||
|
||||
/**
|
||||
* route: apiV2.customer.store
|
||||
* route: apiV2.customers.store
|
||||
*/
|
||||
public function testApiStoreCustomer()
|
||||
{
|
||||
|
|
@ -83,7 +83,7 @@ class CustomerTest extends ApiBase
|
|||
'postcode' => '72160',
|
||||
'opt_in' => true
|
||||
];
|
||||
$response = $this->callApiWithToken($service, 'post', route('apiV2.customer.store'), $data);
|
||||
$response = $this->callApiWithToken($service, 'post', route('apiV2.customers.store'), $data);
|
||||
$json = $response->decodeResponseJson();
|
||||
|
||||
$this->assertApiResponseStatusIs($json, ApiStatus::OK());
|
||||
|
|
@ -106,7 +106,7 @@ class CustomerTest extends ApiBase
|
|||
$this->assertEquals($data['city'], $json->json('data.city'));
|
||||
$this->assertEquals($data['postcode'], $json->json('data.postcode'));
|
||||
|
||||
$response = $this->callApiWithToken($service, 'post', route('apiV2.customer.store'), $data);
|
||||
$response = $this->callApiWithToken($service, 'post', route('apiV2.customers.store'), $data);
|
||||
$json = $response->decodeResponseJson();
|
||||
|
||||
$this->assertApiResponseStatusIs($json, ApiStatus::KO());
|
||||
|
|
@ -115,28 +115,28 @@ class CustomerTest extends ApiBase
|
|||
|
||||
|
||||
$data['password'] = 'password';
|
||||
$response = $this->callApiWithToken($service, 'post', route('apiV2.customer.store'), $data);
|
||||
$response = $this->callApiWithToken($service, 'post', route('apiV2.customers.store'), $data);
|
||||
$json = $response->decodeResponseJson();
|
||||
$this->assertApiResponseStatusIs($json, ApiStatus::KO());
|
||||
$this->assertEquals(ApiError::validationFailed()->value, $json->json('data.code'));
|
||||
}
|
||||
|
||||
/**
|
||||
* route: apiV2.customer.activate
|
||||
* route: apiV2.customers.activate
|
||||
*/
|
||||
public function testActivateCustomer()
|
||||
{
|
||||
extract($this->getCustomer(false));
|
||||
|
||||
$response = $this->callApiWithToken($service, 'post', route(
|
||||
'apiV2.customer.activate',
|
||||
'apiV2.customers.activate',
|
||||
['customer' => $info->hashcode]
|
||||
), []);
|
||||
$json = $response->decodeResponseJson();
|
||||
$this->assertApiResponseStatusIs($json, ApiStatus::OK());
|
||||
|
||||
$response = $this->callApiWithToken($service, 'post', route(
|
||||
'apiV2.customer.activate',
|
||||
'apiV2.customers.activate',
|
||||
['customer' => $info->hashcode]
|
||||
), []);
|
||||
$json = $response->decodeResponseJson();
|
||||
|
|
@ -146,7 +146,7 @@ class CustomerTest extends ApiBase
|
|||
}
|
||||
|
||||
/**
|
||||
* route: apiV2.customer.update
|
||||
* route: apiV2.customers.update
|
||||
*/
|
||||
public function testApiUpdateCustomer()
|
||||
{
|
||||
|
|
@ -167,7 +167,7 @@ class CustomerTest extends ApiBase
|
|||
|
||||
foreach ($data as $rowName => $row) {
|
||||
$response = $this->callApiWithToken($service, 'patch', route(
|
||||
'apiV2.customer.update',
|
||||
'apiV2.customers.update',
|
||||
['customer' => $info->hashcode]
|
||||
), [$rowName => $row]);
|
||||
$json = $response->decodeResponseJson();
|
||||
|
|
@ -189,7 +189,7 @@ class CustomerTest extends ApiBase
|
|||
}
|
||||
}
|
||||
$response = $this->callApiWithToken($service, 'patch', route(
|
||||
'apiV2.customer.update',
|
||||
'apiV2.customers.update',
|
||||
['customer' => $info->hashcode]
|
||||
), ['address2' => 'anything']);
|
||||
$json = $response->decodeResponseJson();
|
||||
|
|
@ -198,14 +198,14 @@ class CustomerTest extends ApiBase
|
|||
}
|
||||
|
||||
/**
|
||||
* route: apiV2.customer.show
|
||||
* route: apiV2.customers.show
|
||||
*/
|
||||
public function testApiGetCustomer()
|
||||
{
|
||||
extract($this->getCustomer());
|
||||
|
||||
$response = $this->callApiWithToken($service, 'get', route(
|
||||
'apiV2.customer.show',
|
||||
'apiV2.customers.show',
|
||||
['customer' => $info->hashcode]
|
||||
));
|
||||
$json = $response->decodeResponseJson();
|
||||
|
|
@ -226,7 +226,7 @@ class CustomerTest extends ApiBase
|
|||
$uuid = Str::uuid();
|
||||
|
||||
$response = $this->callApiWithToken($service, 'get', route(
|
||||
'apiV2.customer.show',
|
||||
'apiV2.customers.show',
|
||||
['customer' => $uuid]
|
||||
));
|
||||
$json = $response->decodeResponseJson();
|
||||
|
|
@ -252,7 +252,7 @@ class CustomerTest extends ApiBase
|
|||
extract($this->getCustomer());
|
||||
$service = $brand->services()->firstOrFail();
|
||||
$response = $this->callApiWithToken($service, 'delete', route(
|
||||
'apiV2.customer.destroy',
|
||||
'apiV2.customers.destroy',
|
||||
['customer' => $info->hashcode]
|
||||
));
|
||||
$json = $response->decodeResponseJson();
|
||||
|
|
@ -260,7 +260,7 @@ class CustomerTest extends ApiBase
|
|||
$this->assertEmpty($json->json('data'));
|
||||
|
||||
$response = $this->callApiWithToken($service, 'get', route(
|
||||
'apiV2.customer.show',
|
||||
'apiV2.customers.show',
|
||||
['customer' => $info->hashcode]
|
||||
));
|
||||
$json = $response->decodeResponseJson();
|
||||
|
|
|
|||
72
tests/Feature/ApiV2/QuestionTest.php
Normal file
72
tests/Feature/ApiV2/QuestionTest.php
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\Feature\ApiV2;
|
||||
|
||||
use App\Enums\ApiStatus;
|
||||
use App\Models\Question;
|
||||
|
||||
class QuestionTest extends ApiBase
|
||||
{
|
||||
|
||||
/**
|
||||
* route: apiV2.questions.index
|
||||
*/
|
||||
public function testQuestionIndex()
|
||||
{
|
||||
extract($this->getCustomer());
|
||||
|
||||
$response = $this->callApiWithToken($service, 'get', route('apiV2.questions.index'));
|
||||
$json = $response->decodeResponseJson();
|
||||
$this->assertApiResponseStatusIs($json, ApiStatus::OK());
|
||||
}
|
||||
|
||||
/**
|
||||
* route: apiV2.questions.indexWithResponse
|
||||
*/
|
||||
public function testQuestionIndexWithAnswers()
|
||||
{
|
||||
extract($this->getCustomer(true, false));
|
||||
$service = $brand->services()->firstOrFail();
|
||||
$response = $this->callApiWithToken($service, 'get', route(
|
||||
'apiV2.questions.indexWithResponse',
|
||||
['customer' => $info->hashcode]
|
||||
));
|
||||
$json = $response->decodeResponseJson();
|
||||
$this->assertApiResponseStatusIs($json, ApiStatus::OK());
|
||||
}
|
||||
|
||||
/**
|
||||
* route: apiV2.questions.unAnsweredBy
|
||||
*/
|
||||
public function testCustomerUnAnsweredIndex()
|
||||
{
|
||||
extract($this->getCustomer());
|
||||
$service = $brand->services()->firstOrFail();
|
||||
$response = $this->callApiWithToken($service, 'get', route(
|
||||
'apiV2.questions.unAnsweredBy',
|
||||
['customer' => $info->hashcode]
|
||||
));
|
||||
$json = $response->decodeResponseJson();
|
||||
$this->assertApiResponseStatusIs($json, ApiStatus::OK());
|
||||
}
|
||||
|
||||
/**
|
||||
* route: apiV2.customers.answers.store
|
||||
*/
|
||||
public function testQuestionSetAnswer()
|
||||
{
|
||||
extract($this->getCustomer(true, false));
|
||||
$question = Question::whereHas('brand', function ($q) use ($brand) {
|
||||
$q->whereId($brand->id);
|
||||
})->inRandomOrder()->firstOrFail();
|
||||
$answer = $question->answers->first();
|
||||
$response = $this->callApiWithToken($service, 'post', route('apiV2.customers.answers.store', [
|
||||
'customer' => $info->hashcode
|
||||
]), [
|
||||
'question' => $question->id,
|
||||
'answers' => [$answer->id]
|
||||
]);
|
||||
$json = $response->decodeResponseJson();
|
||||
$this->assertApiResponseStatusIs($json, ApiStatus::OK());
|
||||
}
|
||||
}
|
||||
|
|
@ -68,6 +68,6 @@ class SingleOptinTest extends ApiBase
|
|||
'postcode' => '72160',
|
||||
'opt_in' => true
|
||||
];
|
||||
$this->callApiWithToken($service, 'post', route('apiV2.customer.store'), $data);
|
||||
$this->callApiWithToken($service, 'post', route('apiV2.customers.store'), $data);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -251,11 +251,11 @@ class CrmClientV2CustomerTest extends CrmClientTester
|
|||
public function testCustomerDelete()
|
||||
{
|
||||
$api = new CrmApiV2();
|
||||
$customer = $api->getCustomerOrNew(static::$info->hashcode);
|
||||
$customer = $api->getCustomer('toto.delarogerie@gmail.com');
|
||||
|
||||
$this->assertTrue($customer->delete());
|
||||
|
||||
$customer = $api->getCustomerOrNew(static::$info->hashcode);
|
||||
$customer = $api->getCustomerOrNew('toto.delarogerie@gmail.com');
|
||||
$this->assertEquals(null, $customer->hashcode);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
75
tests/Unit/CrmClientV2QuestionTest.php
Normal file
75
tests/Unit/CrmClientV2QuestionTest.php
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\Unit;
|
||||
|
||||
use Exception;
|
||||
use LDC\LDCCRM\CrmApiV2;
|
||||
use LDC\LDCCRM\Models\Answer;
|
||||
use LDC\LDCCRM\Models\Question;
|
||||
|
||||
class CrmClientV2QuestionTest extends CrmClientTester
|
||||
{
|
||||
|
||||
public function testGetAllQuestions()
|
||||
{
|
||||
$questions = Question::all();
|
||||
$this->assertNotEmpty($questions, 'Should have returned some questions');
|
||||
}
|
||||
|
||||
public function testGetAllQuestionsWithCustomerAnswers()
|
||||
{
|
||||
$api = new CrmApiV2();
|
||||
$customer = $api->getCustomerOrNew(static::$info->hashcode);
|
||||
$questions = Question::allWithCustomerAnswers($customer);
|
||||
$this->assertNotEmpty($questions, 'Should have returned some questions');
|
||||
}
|
||||
|
||||
public function testGetAllCustomerUnAnsweredQuestions()
|
||||
{
|
||||
$api = new CrmApiV2();
|
||||
$customer = $api->getCustomerOrNew(static::$info->hashcode);
|
||||
$questions = Question::unansweredBy($customer);
|
||||
$this->assertNotEmpty($questions, 'Should have returned some questions');
|
||||
}
|
||||
|
||||
public function testSubmitCustomerAnswer()
|
||||
{
|
||||
$questions = Question::all();
|
||||
|
||||
$api = new CrmApiV2();
|
||||
$customer = $api->getCustomerOrNew(static::$info->hashcode);
|
||||
$result = Answer::setQuestionAnswers(
|
||||
$customer->hashcode,
|
||||
$questions[0]->id,
|
||||
[
|
||||
$questions[0]->answers[0]->id,
|
||||
$questions[0]->answers[1]->id
|
||||
]
|
||||
);
|
||||
$this->assertTrue($result);
|
||||
}
|
||||
|
||||
public function testGetAllCustomerUnansweredQuestionsShouldNotContainFirst()
|
||||
{
|
||||
$this->expectNotToPerformAssertions();
|
||||
$unWantedQuestion = Question::all()[0];
|
||||
|
||||
$api = new CrmApiV2();
|
||||
$customer = $api->getCustomerOrNew(static::$info->hashcode);
|
||||
$questions = Question::unansweredBy($customer);
|
||||
|
||||
foreach ($questions as $question) {
|
||||
if ($unWantedQuestion->id === $question->id) {
|
||||
throw new Exception('The question should not appear');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function testGetAllQuestionsWithCustomerAnswersShouldHaveAnswers()
|
||||
{
|
||||
$api = new CrmApiV2();
|
||||
$customer = $api->getCustomerOrNew(static::$info->hashcode);
|
||||
$questions = Question::allWithCustomerAnswers($customer);
|
||||
$this->assertNotEmpty($questions[0]['customerAnswers'], 'Should have customer answers');
|
||||
}
|
||||
}
|
||||
|
|
@ -36,6 +36,12 @@ class CrmClientV2RouterTest extends CrmClientTester
|
|||
if (\strpos($route['uri'], '{customer}') !== false) {
|
||||
$query['customer'] = 1;
|
||||
}
|
||||
if (\strpos($route['uri'], '{question}') !== false) {
|
||||
$query['question'] = 1;
|
||||
}
|
||||
if (\strpos($route['uri'], '{answer}') !== false) {
|
||||
$query['answer'] = 1;
|
||||
}
|
||||
$request = Utils::getResquest($name, $query, $data);
|
||||
$request->uri;
|
||||
$request->method;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue