diff --git a/config/app.php b/config/app.php index 2fdca33..7b1a326 100644 --- a/config/app.php +++ b/config/app.php @@ -186,6 +186,7 @@ return [ * Domain Service Providers... */ \Src\Zone\User\Application\Providers\UserServiceProvider::class, + \Src\Zone\Company\Application\Providers\CompanyServiceProvider::class, /* * Package Service Providers... diff --git a/database/migrations/2022_10_02_114301_create_companies_table.php b/database/migrations/2022_10_02_114301_create_companies_table.php new file mode 100644 index 0000000..892f65a --- /dev/null +++ b/database/migrations/2022_10_02_114301_create_companies_table.php @@ -0,0 +1,35 @@ +id(); + $table->string('fiscal_name'); + $table->string('social_name'); + $table->string('vat'); + $table->boolean('is_active')->default(1); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('companies'); + } +}; diff --git a/src/Common/Infrastructure/Laravel/Providers/RouteServiceProvider.php b/src/Common/Infrastructure/Laravel/Providers/RouteServiceProvider.php index e97cf29..3a0de2a 100644 --- a/src/Common/Infrastructure/Laravel/Providers/RouteServiceProvider.php +++ b/src/Common/Infrastructure/Laravel/Providers/RouteServiceProvider.php @@ -39,6 +39,7 @@ class RouteServiceProvider extends ServiceProvider ->group(function() { require base_path('src/Auth/Presentation/HTTP/routes.php'); require base_path('src/Zone/User/Presentation/HTTP/routes.php'); + require base_path('src/Zone/Company/Presentation/HTTP/routes.php'); }); }); } diff --git a/src/Zone/Company/Application/Exceptions/VatAlreadyUsedException.php b/src/Zone/Company/Application/Exceptions/VatAlreadyUsedException.php new file mode 100644 index 0000000..1a58d38 --- /dev/null +++ b/src/Zone/Company/Application/Exceptions/VatAlreadyUsedException.php @@ -0,0 +1,11 @@ +input('fiscal_name')), + social_name: new SocialName($request->input('social_name')), + vat: new Vat($request->input('vat')), + is_active: $request->input('is_active'), + ); + } + + public static function fromEloquent(CompanyEloquentModel $companyEloquent): Company + { + return new Company( + id: $companyEloquent->id, + fiscal_name: new FiscalName($companyEloquent->fiscal_name), + social_name: new SocialName($companyEloquent->social_name), + vat: new Vat($companyEloquent->vat), + is_active: $companyEloquent->is_active, + ); + } + + public static function toEloquent(Company $company): CompanyEloquentModel + { + $companyEloquent = new CompanyEloquentModel(); + if ($company->id) { + $companyEloquent = CompanyEloquentModel::query()->find($company->id); + } + $companyEloquent->fiscal_name = $company->fiscal_name; + $companyEloquent->social_name = $company->social_name; + $companyEloquent->vat = $company->vat; + $companyEloquent->is_active = $company->is_active; + return $companyEloquent; + } +} \ No newline at end of file diff --git a/src/Zone/Company/Application/Providers/CompanyServiceProvider.php b/src/Zone/Company/Application/Providers/CompanyServiceProvider.php new file mode 100644 index 0000000..f888aae --- /dev/null +++ b/src/Zone/Company/Application/Providers/CompanyServiceProvider.php @@ -0,0 +1,16 @@ +app->bind( + \Src\Zone\Company\Domain\Repositories\CompanyRepositoryInterface::class, + \Src\Zone\Company\Application\Repositories\Eloquent\CompanyRepository::class + ); + } +} \ No newline at end of file diff --git a/src/Zone/Company/Application/Repositories/Eloquent/CompanyRepository.php b/src/Zone/Company/Application/Repositories/Eloquent/CompanyRepository.php new file mode 100644 index 0000000..da1007c --- /dev/null +++ b/src/Zone/Company/Application/Repositories/Eloquent/CompanyRepository.php @@ -0,0 +1,50 @@ +findOrFail($id); + return CompanyMapper::fromEloquent($companyEloquent); + } + public function findByVat(string $vat): Company + { + $companyEloquent = CompanyEloquentModel::query()->where('vat', $vat)->firstOrFail(); + return CompanyMapper::fromEloquent($companyEloquent); + } + + public function store(Company $company): Company + { + $companyEloquent = CompanyMapper::toEloquent($company); + $companyEloquent->save(); + + return CompanyMapper::fromEloquent($companyEloquent); + } + public function update(Company $company): void + { + $companyArray = $company->toArray(); + $companyEloquent = CompanyEloquentModel::query()->findOrFail($company->id); + $companyEloquent->fill($companyArray); + $companyEloquent->save(); + } + public function delete(int $company_id): void + { + $companyEloquent = CompanyEloquentModel::query()->findOrFail($company_id); + $companyEloquent->delete(); + } +} \ No newline at end of file diff --git a/src/Zone/Company/Application/UseCases/Commands/DestroyCompanyCommand.php b/src/Zone/Company/Application/UseCases/Commands/DestroyCompanyCommand.php new file mode 100644 index 0000000..3c64bb5 --- /dev/null +++ b/src/Zone/Company/Application/UseCases/Commands/DestroyCompanyCommand.php @@ -0,0 +1,27 @@ +repository = app()->make(CompanyRepositoryInterface::class); + $this->policy = new CompanyPolicy(); + } + + public function execute(): void + { + authorize('delete', $this->policy); + $this->repository->delete($this->company_id); + } +} \ No newline at end of file diff --git a/src/Zone/Company/Application/UseCases/Commands/StoreCompanyCommand.php b/src/Zone/Company/Application/UseCases/Commands/StoreCompanyCommand.php new file mode 100644 index 0000000..f1b1559 --- /dev/null +++ b/src/Zone/Company/Application/UseCases/Commands/StoreCompanyCommand.php @@ -0,0 +1,34 @@ +repository = app()->make(CompanyRepositoryInterface::class); + $this->policy = new CompanyPolicy(); + } + + public function execute(): Company + { + authorize('store', $this->policy); + if (CompanyEloquentModel::query()->where('vat', $this->company->vat)->exists()) { + throw new VatAlreadyUsedException(); + } + + return $this->repository->store($this->company); + } +} \ No newline at end of file diff --git a/src/Zone/Company/Application/UseCases/Commands/UpdateCompanyCommand.php b/src/Zone/Company/Application/UseCases/Commands/UpdateCompanyCommand.php new file mode 100644 index 0000000..3472c88 --- /dev/null +++ b/src/Zone/Company/Application/UseCases/Commands/UpdateCompanyCommand.php @@ -0,0 +1,34 @@ +repository = app()->make(CompanyRepositoryInterface::class); + $this->policy = new CompanyPolicy(); + } + + public function execute(): void + { + authorize('update', $this->policy); + if (CompanyEloquentModel::query()->where('vat', $this->company->vat)->where('id', '!=', $this->company->id)->exists()) { + throw new VatAlreadyUsedException(); + } + + $this->repository->update($this->company); + } +} \ No newline at end of file diff --git a/src/Zone/Company/Application/UseCases/Queries/FindAllCompaniesQuery.php b/src/Zone/Company/Application/UseCases/Queries/FindAllCompaniesQuery.php new file mode 100644 index 0000000..e6bb3b0 --- /dev/null +++ b/src/Zone/Company/Application/UseCases/Queries/FindAllCompaniesQuery.php @@ -0,0 +1,25 @@ +repository = app()->make(CompanyRepositoryInterface::class); + $this->policy = new CompanyPolicy(); + } + + public function handle(): array + { + authorize('findAll', $this->policy); + return $this->repository->findAll(); + } +} \ No newline at end of file diff --git a/src/Zone/Company/Application/UseCases/Queries/FindCompanyByIdQuery.php b/src/Zone/Company/Application/UseCases/Queries/FindCompanyByIdQuery.php new file mode 100644 index 0000000..c7c1d4b --- /dev/null +++ b/src/Zone/Company/Application/UseCases/Queries/FindCompanyByIdQuery.php @@ -0,0 +1,28 @@ +repository = app()->make(CompanyRepositoryInterface::class); + $this->policy = new CompanyPolicy(); + } + + public function handle(): Company + { + authorize('findById', $this->policy, ['company_id' => $this->id]); + return $this->repository->findById($this->id); + } +} \ No newline at end of file diff --git a/src/Zone/Company/Application/UseCases/Queries/FindCompanyByVatQuery.php b/src/Zone/Company/Application/UseCases/Queries/FindCompanyByVatQuery.php new file mode 100644 index 0000000..7d92a10 --- /dev/null +++ b/src/Zone/Company/Application/UseCases/Queries/FindCompanyByVatQuery.php @@ -0,0 +1,27 @@ +repository = app()->make(CompanyRepositoryInterface::class); + $this->policy = new CompanyPolicy(); + } + + public function handle(): array + { + authorize('findByVat', $this->policy); + return $this->repository->findByVat($this->vat)->toArray(); + } +} \ No newline at end of file diff --git a/src/Zone/Company/Domain/Exceptions/IncorrectVatFormatException.php b/src/Zone/Company/Domain/Exceptions/IncorrectVatFormatException.php new file mode 100644 index 0000000..e437bae --- /dev/null +++ b/src/Zone/Company/Domain/Exceptions/IncorrectVatFormatException.php @@ -0,0 +1,11 @@ + null, + 'fiscal_name' => fake()->name, + 'social_name' => fake()->company, + 'vat' => fake()->bothify('?#########'), + 'is_active' => true, + ]; + + $attributes = array_replace($defaults, $attributes); + + return new Company( + id: null, + fiscal_name: new FiscalName($attributes['fiscal_name']), + social_name: new SocialName($attributes['social_name']), + vat: new Vat($attributes['vat']), + is_active: $attributes['is_active'], + ); + } +} \ No newline at end of file diff --git a/src/Zone/Company/Domain/Model/Company.php b/src/Zone/Company/Domain/Model/Company.php new file mode 100644 index 0000000..811242b --- /dev/null +++ b/src/Zone/Company/Domain/Model/Company.php @@ -0,0 +1,38 @@ + $this->id, + 'fiscal_name' => $this->fiscal_name, + 'social_name' => $this->social_name, + 'vat' => $this->vat, + 'is_active' => $this->is_active, + ]; + } + + public function jsonSerialize(): array + { + return $this->toArray(); + } +} \ No newline at end of file diff --git a/src/Zone/Company/Domain/Model/ValueObjects/FiscalName.php b/src/Zone/Company/Domain/Model/ValueObjects/FiscalName.php new file mode 100644 index 0000000..85216b4 --- /dev/null +++ b/src/Zone/Company/Domain/Model/ValueObjects/FiscalName.php @@ -0,0 +1,31 @@ +name = $name; + } + + public function __toString(): string + { + return $this->name; + } + + public function jsonSerialize(): string + { + return $this->name; + } +} \ No newline at end of file diff --git a/src/Zone/Company/Domain/Model/ValueObjects/SocialName.php b/src/Zone/Company/Domain/Model/ValueObjects/SocialName.php new file mode 100644 index 0000000..af09154 --- /dev/null +++ b/src/Zone/Company/Domain/Model/ValueObjects/SocialName.php @@ -0,0 +1,31 @@ +name = $name; + } + + public function __toString(): string + { + return $this->name; + } + + public function jsonSerialize(): string + { + return $this->name; + } +} \ No newline at end of file diff --git a/src/Zone/Company/Domain/Model/ValueObjects/Vat.php b/src/Zone/Company/Domain/Model/ValueObjects/Vat.php new file mode 100644 index 0000000..fcce5ae --- /dev/null +++ b/src/Zone/Company/Domain/Model/ValueObjects/Vat.php @@ -0,0 +1,35 @@ +vat = $vat; + } + + public function __toString(): string + { + return $this->vat; + } + + public function jsonSerialize(): string + { + return $this->vat; + } + +} \ No newline at end of file diff --git a/src/Zone/Company/Domain/Policies/CompanyPolicy.php b/src/Zone/Company/Domain/Policies/CompanyPolicy.php new file mode 100644 index 0000000..35d14f7 --- /dev/null +++ b/src/Zone/Company/Domain/Policies/CompanyPolicy.php @@ -0,0 +1,66 @@ +user()->is_admin; + } + + public function findById(string $company_id): bool + { + return auth()->user()->is_admin || auth()->user()->company_id == $company_id; + } + + public function findByVat(): bool + { + return auth()->user()->is_admin; + } + + public function store(): bool + { + return auth()->user()->is_admin; + } + + public function update(): bool + { + return auth()->user()->is_admin; + } + + public function delete(): bool + { + return auth()->user()->is_admin; + } + + public function persistAddresses(): bool + { + return auth()->user()->is_admin; + } + + public function removeAddress(): bool + { + return auth()->user()->is_admin; + } + + public function persistDepartments(): bool + { + return auth()->user()->is_admin; + } + + public function removeDepartment(): bool + { + return auth()->user()->is_admin; + } + + public function persistContacts(): bool + { + return auth()->user()->is_admin; + } + + public function removeContact(): bool + { + return auth()->user()->is_admin; + } +} \ No newline at end of file diff --git a/src/Zone/Company/Domain/Repositories/CompanyRepositoryInterface.php b/src/Zone/Company/Domain/Repositories/CompanyRepositoryInterface.php new file mode 100644 index 0000000..cef2bf1 --- /dev/null +++ b/src/Zone/Company/Domain/Repositories/CompanyRepositoryInterface.php @@ -0,0 +1,16 @@ + + */ + protected $fillable = [ + 'fiscal_name', + 'social_name', + 'vat', + 'is_active', + ]; + + public array $rules = [ + 'fiscal_name' => 'required|string|max:255', + 'social_name' => 'required|string|max:255', + 'vat' => 'required|string|max:255', + 'is_active' => 'required|boolean', + ]; + + /** + * The attributes that should be hidden for serialization. + * + * @var array + */ + protected $hidden = [ + 'created_at', + 'updated_at', + ]; + + /** + * The attributes that should be cast. + * + * @var array + */ + protected $casts = [ + 'is_active' => 'boolean', + ]; +} diff --git a/src/Zone/Company/Presentation/HTTP/CompanyController.php b/src/Zone/Company/Presentation/HTTP/CompanyController.php new file mode 100644 index 0000000..9e03aa3 --- /dev/null +++ b/src/Zone/Company/Presentation/HTTP/CompanyController.php @@ -0,0 +1,72 @@ +json((new FindAllCompaniesQuery())->handle()); + } catch (UnauthorizedUserException $e) { + return response()->json(['error' => $e->getMessage()], Response::HTTP_UNAUTHORIZED); + } + } + + public function show(int $id): JsonResponse + { + try { + return response()->json((new FindCompanyByIdQuery($id))->handle()); + } catch (UnauthorizedUserException $e) { + return response()->json(['error' => $e->getMessage()], Response::HTTP_UNAUTHORIZED); + } + } + + public function store(Request $request): JsonResponse + { + try { + $newCompany = CompanyMapper::fromRequest($request); + $company = (new StoreCompanyCommand($newCompany))->execute(); + return response()->json($company, Response::HTTP_CREATED); + } catch (\DomainException $domainException) { + return response()->json(['error' => $domainException->getMessage()], Response::HTTP_UNPROCESSABLE_ENTITY); + } catch (UnauthorizedUserException $e) { + return response()->json(['error' => $e->getMessage()], Response::HTTP_UNAUTHORIZED); + } + } + + public function update(int $company_id, Request $request): JsonResponse + { + try { + $company = CompanyMapper::fromRequest($request, $company_id); + (new UpdateCompanyCommand($company))->execute(); + return response()->json($company->toArray(), Response::HTTP_OK); + } catch (\DomainException $domainException) { + return response()->json(['error' => $domainException->getMessage()], Response::HTTP_UNPROCESSABLE_ENTITY); + } catch (UnauthorizedUserException $e) { + return response()->json(['error' => $e->getMessage()], Response::HTTP_UNAUTHORIZED); + } + } + + public function destroy(int $company_id): JsonResponse + { + try { + (new DestroyCompanyCommand($company_id))->execute(); + return response()->json(null, Response::HTTP_NO_CONTENT); + } catch (UnauthorizedUserException $e) { + return response()->json(['error' => $e->getMessage()], Response::HTTP_UNAUTHORIZED); + } + } +} \ No newline at end of file diff --git a/src/Zone/Company/Presentation/HTTP/routes.php b/src/Zone/Company/Presentation/HTTP/routes.php new file mode 100644 index 0000000..042d62f --- /dev/null +++ b/src/Zone/Company/Presentation/HTTP/routes.php @@ -0,0 +1,14 @@ + 'company' +], function () { + Route::get('index', [CompanyController::class, 'index']); + Route::get('{id}', [CompanyController::class, 'show']); + Route::post('', [CompanyController::class, 'store']); + Route::put('{id}', [CompanyController::class, 'update']); + Route::delete('{id}', [CompanyController::class, 'destroy']); +}); diff --git a/tests/Feature/CompanyTest.php b/tests/Feature/CompanyTest.php new file mode 100644 index 0000000..3a724a5 --- /dev/null +++ b/tests/Feature/CompanyTest.php @@ -0,0 +1,258 @@ +company_uri = '/company'; + $this->index_uri = $this->company_uri . '/index'; + $this->adminToken = $this->newLoggedAdmin()['token']; + $this->userData = $this->newLoggedUser(); + $this->userToken = $this->userData['token']; + } + + /** @test */ + public function admin_can_retrieve_all_companies() + { + $companiesCount = $this->faker->numberBetween(1, 10); + $this->createRandomCompanies($companiesCount); + + $companies = $this->withHeaders(['Authorization' => 'Bearer ' . $this->adminToken]) + ->get($this->index_uri) + ->assertStatus(Response::HTTP_OK) + ->assertJsonCount($companiesCount); + + $companyInfo = $companies->json()[0]; + $this->assertEquals( + ['id', 'fiscal_name', 'social_name', 'vat', 'is_active'], + array_keys($companyInfo) + ); + } + + /** @test */ + public function user_cannot_retrieve_all_companies() + { + $companiesCount = $this->faker->numberBetween(1, 10); + $this->createRandomCompanies($companiesCount); + + $this->withHeaders(['Authorization' => 'Bearer ' . $this->userToken]) + ->get($this->index_uri) + ->assertStatus(Response::HTTP_UNAUTHORIZED) + ->assertSee(['error' => 'The user is not authorized to access this resource']); + } + + /** @test */ + public function admin_can_get_specific_company_by_id() + { + $companiesCount = $this->faker->numberBetween(1, 10); + $this->createRandomCompanies($companiesCount); + $randomCompanyId = $this->faker->numberBetween(1, $companiesCount); + + $this->withHeaders(['Authorization' => 'Bearer ' . $this->adminToken]) + ->get($this->company_uri . '/' . $randomCompanyId) + ->assertStatus(Response::HTTP_OK) + ->assertJsonStructure(['id', 'fiscal_name', 'social_name', 'vat', 'is_active']); + } + + /** @test */ + public function user_cannot_get_specific_company_by_id_except_if_belongs_to() + { + $companiesCount = $this->faker->numberBetween(1, 10); + $this->createRandomCompanies($companiesCount); + $randomCompanyId = $this->faker->numberBetween(2, $companiesCount + 1); + + // User cannot retrieve company where it is not belonged to + $this->withHeaders(['Authorization' => 'Bearer ' . $this->userToken]) + ->get($this->company_uri . '/' . $randomCompanyId) + ->assertStatus(Response::HTTP_UNAUTHORIZED) + ->assertSee(['error' => 'The user is not authorized to access this resource']); + + // User can retrieve company where it belongs + //todo implement user relationship to company +// $this->withHeaders(['Authorization' => 'Bearer ' . $this->userToken]) +// ->get($this->company_uri . '/' . $companyId) +// ->assertStatus(Response::HTTP_OK) +// ->assertJsonStructure(['id', 'fiscal_name', 'social_name', 'vat', 'is_active']); + } + + /** @test */ + public function admin_can_create_a_company() + { + $requestBody = [ + 'fiscal_name' => $this->faker->name, + 'social_name' => $this->faker->company, + 'vat' => $this->faker->bothify('?#########'), + 'is_active' => $this->faker->boolean, + ]; + + $expectedResponse = [ + 'id' => 1, + 'fiscal_name' => $requestBody['fiscal_name'], + 'social_name' => $requestBody['social_name'], + 'vat' => $requestBody['vat'], + 'is_active' => $requestBody['is_active'] + ]; + + + $this->withHeaders(['Authorization' => 'Bearer ' . $this->adminToken]) + ->post($this->company_uri, $requestBody) + ->assertStatus(Response::HTTP_CREATED) + ->assertJson($expectedResponse); + + // Assert cannot create company with same vat + $this->withHeaders(['Authorization' => 'Bearer ' . $this->adminToken]) + ->post($this->company_uri, $requestBody) + ->assertStatus(Response::HTTP_UNPROCESSABLE_ENTITY) + ->assertJson(['error' => 'Vat is already used']); + } + + /** @test */ + public function user_cannot_create_a_company() + { + $requestBody = [ + 'fiscal_name' => $this->faker->name, + 'social_name' => $this->faker->company, + 'vat' => $this->faker->bothify('?#########'), + 'is_active' => $this->faker->boolean + ]; + + $this->withHeaders(['Authorization' => 'Bearer ' . $this->userToken]) + ->post($this->company_uri, $requestBody) + ->assertStatus(Response::HTTP_UNAUTHORIZED) + ->assertSee(['error' => 'The user is not authorized to access this resource']); + } + + /** @test */ + public function cannot_create_company_with_invalid_vat() + { + $requestBodyInvalidVat = [ + 'fiscal_name' => $this->faker->name, + 'social_name' => $this->faker->company, + 'vat' => 'invalidvat', + 'is_active' => $this->faker->boolean, + ]; + + $this->withHeaders(['Authorization' => 'Bearer ' . $this->adminToken]) + ->post($this->company_uri, $requestBodyInvalidVat) + ->assertStatus(Response::HTTP_UNPROCESSABLE_ENTITY) + ->assertJson(['error' => 'Vat must be valid']); + } + + /** @test */ + public function admin_can_update_a_company() + { + $numberCompanies = $this->faker->numberBetween(1, 10); + $this->createRandomCompanies($numberCompanies); + $randomCompanyId = $this->faker->numberBetween(1, $numberCompanies); + + $this->withHeaders(['Authorization' => 'Bearer ' . $this->adminToken]) + ->get($this->company_uri . '/' . $randomCompanyId) + ->assertStatus(Response::HTTP_OK) + ->assertJsonStructure(['id', 'fiscal_name', 'social_name', 'vat', 'is_active']); + + $requestBody = [ + 'fiscal_name' => $this->faker->name, + 'social_name' => $this->faker->company, + 'vat' => $this->faker->bothify('?#########'), + 'is_active' => $this->faker->boolean, + ]; + + $expectedResponse = [ + 'id' => $randomCompanyId, + 'fiscal_name' => $requestBody['fiscal_name'], + 'social_name' => $requestBody['social_name'], + 'vat' => $requestBody['vat'], + 'is_active' => $requestBody['is_active'] + ]; + + $this->withHeaders(['Authorization' => 'Bearer ' . $this->adminToken]) + ->put($this->company_uri . '/' . $randomCompanyId, $requestBody) + ->assertStatus(Response::HTTP_OK) + ->assertJson($expectedResponse); + + $requestBodyInvalidVat = [ + 'fiscal_name' => $this->faker->name, + 'social_name' => $this->faker->company, + 'vat' => 'invalidvat', + 'is_active' => $this->faker->boolean, + ]; + + $this->withHeaders(['Authorization' => 'Bearer ' . $this->adminToken]) + ->put($this->company_uri . '/' . $randomCompanyId, $requestBodyInvalidVat) + ->assertStatus(Response::HTTP_UNPROCESSABLE_ENTITY) + ->assertJson(['error' => 'Vat must be valid']); + } + + /** @test */ + public function user_cannot_update_a_company() + { + $numberCompanies = $this->faker->numberBetween(1, 10); + $this->createRandomCompanies($numberCompanies); + $randomCompanyId = $this->faker->numberBetween(1, $numberCompanies); + + $company = $this->withHeaders(['Authorization' => 'Bearer ' . $this->adminToken]) + ->get($this->company_uri . '/' . $randomCompanyId) + ->assertStatus(Response::HTTP_OK) + ->assertJsonStructure(['id', 'fiscal_name', 'social_name', 'vat', 'is_active']); + + $requestBody = [ + 'fiscal_name' => $this->faker->name, + 'social_name' => $this->faker->company, + 'vat' => $this->faker->bothify('?#########'), + 'is_active' => $this->faker->boolean + ]; + + $this->withHeaders(['Authorization' => 'Bearer ' . $this->userToken]) + ->put($this->company_uri . '/' . $randomCompanyId, $requestBody) + ->assertStatus(Response::HTTP_UNAUTHORIZED) + ->assertSee(['error' => 'The user is not authorized to access this resource']); + } + + /** @test */ + public function admin_can_delete_a_company() + { + $numberCompanies = $this->faker->numberBetween(1, 10); + $this->createRandomCompanies($numberCompanies); + $randomCompanyId = $this->faker->numberBetween(1, $numberCompanies); + + $this->withHeaders(['Authorization' => 'Bearer ' . $this->adminToken]) + ->delete($this->company_uri . '/' . $randomCompanyId) + ->assertStatus(Response::HTTP_NO_CONTENT); + + $this->withHeaders(['Authorization' => 'Bearer ' . $this->adminToken]) + ->get($this->company_uri . '/' . $randomCompanyId) + ->assertStatus(Response::HTTP_NOT_FOUND); + } + + /** @test */ + public function user_cannot_delete_a_company() + { + $numberCompanies = $this->faker->numberBetween(1, 10); + $this->createRandomCompanies($numberCompanies); + $randomCompanyId = $this->faker->numberBetween(1, $numberCompanies); + + $this->withHeaders(['Authorization' => 'Bearer ' . $this->userToken]) + ->delete($this->company_uri . '/' . $randomCompanyId) + ->assertStatus(Response::HTTP_UNAUTHORIZED) + ->assertSee(['error' => 'The user is not authorized to access this resource']); + } + + /** @test */ + public function cannot_delete_company_if_does_not_exists() + { + $this->withHeaders(['Authorization' => 'Bearer ' . $this->adminToken]) + ->delete($this->company_uri . '/' . 3) + ->assertStatus(Response::HTTP_NOT_FOUND); + } +} diff --git a/tests/Support/WithCompanies.php b/tests/Support/WithCompanies.php new file mode 100644 index 0000000..5514047 --- /dev/null +++ b/tests/Support/WithCompanies.php @@ -0,0 +1,29 @@ +save(); + return CompanyMapper::fromEloquent($companyEloquentModel); + } + + public function createRandomCompanies(int $companiesCount) + { + foreach (range(1, $companiesCount) as $_) { + $this->newCompany(); + } + } + +} \ No newline at end of file