company module

This commit is contained in:
omair saleh
2022-10-04 20:58:33 +08:00
parent ff87ecde19
commit ddd0db84b8
26 changed files with 1020 additions and 0 deletions
+1
View File
@@ -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...
@@ -0,0 +1,35 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('companies', function (Blueprint $table) {
$table->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');
}
};
@@ -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');
});
});
}
@@ -0,0 +1,11 @@
<?php
namespace Src\Zone\Company\Application\Exceptions;
final class VatAlreadyUsedException extends \DomainException
{
public function __construct()
{
parent::__construct('Vat is already used');
}
}
@@ -0,0 +1,48 @@
<?php
namespace Src\Zone\Company\Application\Mappers;
use Illuminate\Http\Request;
use Src\Zone\Company\Domain\Model\Company;
use Src\Zone\Company\Domain\Model\ValueObjects\FiscalName;
use Src\Zone\Company\Domain\Model\ValueObjects\SocialName;
use Src\Zone\Company\Domain\Model\ValueObjects\Vat;
use Src\Zone\Company\Infrastructure\EloquentModels\CompanyEloquentModel;
class CompanyMapper
{
public static function fromRequest(Request $request, ?int $company_id = null): Company
{
return new Company(
id: $company_id,
fiscal_name: new FiscalName($request->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;
}
}
@@ -0,0 +1,16 @@
<?php
namespace Src\Zone\Company\Application\Providers;
use Illuminate\Support\ServiceProvider;
class CompanyServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->bind(
\Src\Zone\Company\Domain\Repositories\CompanyRepositoryInterface::class,
\Src\Zone\Company\Application\Repositories\Eloquent\CompanyRepository::class
);
}
}
@@ -0,0 +1,50 @@
<?php
namespace Src\Zone\Company\Application\Repositories\Eloquent;
use Src\Zone\Company\Application\Mappers\CompanyMapper;
use Src\Zone\Company\Domain\Model\Company;
use Src\Zone\Company\Domain\Repositories\CompanyRepositoryInterface;
use Src\Zone\Company\Infrastructure\EloquentModels\CompanyEloquentModel;
class CompanyRepository implements CompanyRepositoryInterface
{
public function findAll(): array
{
$companies = [];
foreach (CompanyEloquentModel::all() as $companyEloquent) {
$companies[] = CompanyMapper::fromEloquent($companyEloquent);
}
return $companies;
}
public function findById(string $id): Company
{
$companyEloquent = CompanyEloquentModel::query()->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();
}
}
@@ -0,0 +1,27 @@
<?php
namespace Src\Zone\Company\Application\UseCases\Commands;
use Src\Zone\Company\Domain\Policies\CompanyPolicy;
use Src\Zone\Company\Domain\Repositories\CompanyRepositoryInterface;
use Src\Common\Domain\CommandInterface;
class DestroyCompanyCommand implements CommandInterface
{
private CompanyRepositoryInterface $repository;
private CompanyPolicy $policy;
public function __construct(
private readonly int $company_id
)
{
$this->repository = app()->make(CompanyRepositoryInterface::class);
$this->policy = new CompanyPolicy();
}
public function execute(): void
{
authorize('delete', $this->policy);
$this->repository->delete($this->company_id);
}
}
@@ -0,0 +1,34 @@
<?php
namespace Src\Zone\Company\Application\UseCases\Commands;
use Src\Zone\Company\Application\Exceptions\VatAlreadyUsedException;
use Src\Zone\Company\Domain\Model\Company;
use Src\Zone\Company\Domain\Policies\CompanyPolicy;
use Src\Zone\Company\Domain\Repositories\CompanyRepositoryInterface;
use Src\Zone\Company\Infrastructure\EloquentModels\CompanyEloquentModel;
use Src\Common\Domain\CommandInterface;
class StoreCompanyCommand implements CommandInterface
{
private CompanyRepositoryInterface $repository;
private CompanyPolicy $policy;
public function __construct(
private readonly Company $company
)
{
$this->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);
}
}
@@ -0,0 +1,34 @@
<?php
namespace Src\Zone\Company\Application\UseCases\Commands;
use Src\Zone\Company\Application\Exceptions\VatAlreadyUsedException;
use Src\Zone\Company\Domain\Model\Company;
use Src\Zone\Company\Domain\Policies\CompanyPolicy;
use Src\Zone\Company\Domain\Repositories\CompanyRepositoryInterface;
use Src\Zone\Company\Infrastructure\EloquentModels\CompanyEloquentModel;
use Src\Common\Domain\CommandInterface;
class UpdateCompanyCommand implements CommandInterface
{
private CompanyRepositoryInterface $repository;
private CompanyPolicy $policy;
public function __construct(
private readonly Company $company
)
{
$this->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);
}
}
@@ -0,0 +1,25 @@
<?php
namespace Src\Zone\Company\Application\UseCases\Queries;
use Src\Zone\Company\Domain\Policies\CompanyPolicy;
use Src\Zone\Company\Domain\Repositories\CompanyRepositoryInterface;
use Src\Common\Domain\QueryInterface;
class FindAllCompaniesQuery implements QueryInterface
{
private CompanyRepositoryInterface $repository;
private CompanyPolicy $policy;
public function __construct()
{
$this->repository = app()->make(CompanyRepositoryInterface::class);
$this->policy = new CompanyPolicy();
}
public function handle(): array
{
authorize('findAll', $this->policy);
return $this->repository->findAll();
}
}
@@ -0,0 +1,28 @@
<?php
namespace Src\Zone\Company\Application\UseCases\Queries;
use Src\Zone\Company\Domain\Model\Company;
use Src\Zone\Company\Domain\Policies\CompanyPolicy;
use Src\Zone\Company\Domain\Repositories\CompanyRepositoryInterface;
use Src\Common\Domain\QueryInterface;
class FindCompanyByIdQuery implements QueryInterface
{
private CompanyRepositoryInterface $repository;
private CompanyPolicy $policy;
public function __construct(
private readonly int $id
)
{
$this->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);
}
}
@@ -0,0 +1,27 @@
<?php
namespace Src\Zone\Company\Application\UseCases\Queries;
use Src\Zone\Company\Domain\Policies\CompanyPolicy;
use Src\Zone\Company\Domain\Repositories\CompanyRepositoryInterface;
use Src\Common\Domain\QueryInterface;
class FindCompanyByVatQuery implements QueryInterface
{
private CompanyRepositoryInterface $repository;
private CompanyPolicy $policy;
public function __construct(
private readonly string $vat
)
{
$this->repository = app()->make(CompanyRepositoryInterface::class);
$this->policy = new CompanyPolicy();
}
public function handle(): array
{
authorize('findByVat', $this->policy);
return $this->repository->findByVat($this->vat)->toArray();
}
}
@@ -0,0 +1,11 @@
<?php
namespace Src\Zone\Company\Domain\Exceptions;
class IncorrectVatFormatException extends \DomainException
{
public function __construct()
{
parent::__construct('Vat must be valid');
}
}
@@ -0,0 +1,34 @@
<?php
namespace Src\Zone\Company\Domain\Factories;
use Src\Zone\Company\Domain\Model\Company;
use Src\Zone\Company\Domain\Model\ValueObjects\FiscalName;
use Src\Zone\Company\Domain\Model\ValueObjects\SocialName;
use Src\Zone\Company\Domain\Model\ValueObjects\Vat;
class CompanyFactory
{
public static function new(array $attributes = null): Company
{
$attributes = $attributes ?: [];
$defaults = [
'id' => 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'],
);
}
}
+38
View File
@@ -0,0 +1,38 @@
<?php
declare(strict_types=1);
namespace Src\Zone\Company\Domain\Model;
use Src\Zone\Company\Domain\Model\ValueObjects\FiscalName;
use Src\Zone\Company\Domain\Model\ValueObjects\SocialName;
use Src\Zone\Company\Domain\Model\ValueObjects\Vat;
use Src\Common\Domain\AggregateRoot;
use Src\Common\Domain\Exceptions\EntityNotFoundException;
class Company extends AggregateRoot implements \JsonSerializable
{
public function __construct(
public readonly ?int $id,
public readonly FiscalName $fiscal_name,
public readonly SocialName $social_name,
public readonly Vat $vat,
public readonly bool $is_active = true
) {}
public function toArray(): array
{
return [
'id' => $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();
}
}
@@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace Src\Zone\Company\Domain\Model\ValueObjects;
use Src\Common\Domain\Exceptions\RequiredException;
final class FiscalName implements \JsonSerializable
{
private string $name;
public function __construct(?string $name)
{
if (!$name) {
throw new RequiredException('razón social');
}
$this->name = $name;
}
public function __toString(): string
{
return $this->name;
}
public function jsonSerialize(): string
{
return $this->name;
}
}
@@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace Src\Zone\Company\Domain\Model\ValueObjects;
use Src\Common\Domain\Exceptions\RequiredException;
final class SocialName implements \JsonSerializable
{
private string $name;
public function __construct(?string $name)
{
if (!$name) {
throw new RequiredException('nombre comercial');
}
$this->name = $name;
}
public function __toString(): string
{
return $this->name;
}
public function jsonSerialize(): string
{
return $this->name;
}
}
@@ -0,0 +1,35 @@
<?php
namespace Src\Zone\Company\Domain\Model\ValueObjects;
use Src\Zone\Company\Domain\Exceptions\IncorrectVatFormatException;
use Src\Common\Domain\Exceptions\RequiredException;
final class Vat implements \JsonSerializable
{
private string $vat;
public function __construct(?string $vat)
{
if (!$vat) {
throw new RequiredException('vat');
}
if (!preg_match('/([a-z]|[A-Z]|[0-9])[0-9]{7}([a-z]|[A-Z]|[0-9])/', $vat)) {
throw new IncorrectVatFormatException();
}
$this->vat = $vat;
}
public function __toString(): string
{
return $this->vat;
}
public function jsonSerialize(): string
{
return $this->vat;
}
}
@@ -0,0 +1,66 @@
<?php
namespace Src\Zone\Company\Domain\Policies;
class CompanyPolicy
{
public function findAll(): bool
{
return auth()->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;
}
}
@@ -0,0 +1,16 @@
<?php
namespace Src\Zone\Company\Domain\Repositories;
use Src\Zone\Company\Domain\Model\Company;
interface CompanyRepositoryInterface
{
public function findAll(): array;
public function findById(string $id): Company;
public function findByVat(string $vat): Company;
public function store(Company $company): Company;
public function update(Company $company): void;
public function delete(int $company_id): void;
}
@@ -0,0 +1,48 @@
<?php
namespace Src\Zone\Company\Infrastructure\EloquentModels;
use Illuminate\Database\Eloquent\Model;
class CompanyEloquentModel extends Model
{
protected $table = 'companies';
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
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<int, string>
*/
protected $hidden = [
'created_at',
'updated_at',
];
/**
* The attributes that should be cast.
*
* @var array<string, string>
*/
protected $casts = [
'is_active' => 'boolean',
];
}
@@ -0,0 +1,72 @@
<?php
namespace Src\Zone\Company\Presentation\HTTP;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Src\Zone\Company\Application\Mappers\CompanyMapper;
use Src\Zone\Company\Application\UseCases\Commands\DestroyCompanyCommand;
use Src\Zone\Company\Application\UseCases\Commands\StoreCompanyCommand;
use Src\Zone\Company\Application\UseCases\Commands\UpdateCompanyCommand;
use Src\Zone\Company\Application\UseCases\Queries\FindAllCompaniesQuery;
use Src\Zone\Company\Application\UseCases\Queries\FindCompanyByIdQuery;
use Src\Common\Domain\Exceptions\UnauthorizedUserException;
use Symfony\Component\HttpFoundation\Response;
class CompanyController
{
public function index(): JsonResponse
{
try {
return response()->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);
}
}
}
@@ -0,0 +1,14 @@
<?php
use Illuminate\Support\Facades\Route;
use Src\Zone\Company\Presentation\HTTP\CompanyController;
Route::group([
'prefix' => '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']);
});
+258
View File
@@ -0,0 +1,258 @@
<?php
namespace Tests\Feature;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Symfony\Component\HttpFoundation\Response;
use Tests\TestCase;
use Tests\Support\WithLogin;
use Tests\Support\WithCompanies;
class CompanyTest extends TestCase
{
use RefreshDatabase, WithLogin, WithCompanies;
protected function setUp(): void
{
parent::setUp();
$this->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);
}
}
+29
View File
@@ -0,0 +1,29 @@
<?php
namespace Tests\Support;
use Illuminate\Foundation\Testing\WithFaker;
use Src\Zone\Company\Application\Mappers\CompanyMapper;
use Src\Zone\Company\Domain\Factories\CompanyFactory;
use Src\Zone\Company\Domain\Model\Company;
trait WithCompanies
{
use WithFaker;
public function newCompany(): Company
{
$company = CompanyFactory::new();
$companyEloquentModel = CompanyMapper::toEloquent($company);
$companyEloquentModel->save();
return CompanyMapper::fromEloquent($companyEloquentModel);
}
public function createRandomCompanies(int $companiesCount)
{
foreach (range(1, $companiesCount) as $_) {
$this->newCompany();
}
}
}