feat: companies CRUD with person dialog integration and navigation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-10 11:16:01 +02:00
parent 169a078a92
commit 4388811be9
14 changed files with 984 additions and 73 deletions

View File

@@ -20,7 +20,10 @@ final class CompanyController extends Controller
{
Gate::authorize('viewAny', [Company::class, $organisation]);
$companies = $organisation->companies()->get();
$companies = $organisation->companies()
->withCount('persons')
->ordered()
->get();
return CompanyResource::collection($companies);
}
@@ -34,6 +37,15 @@ final class CompanyController extends Controller
return $this->created(new CompanyResource($company));
}
public function show(Organisation $organisation, Company $company): JsonResponse
{
Gate::authorize('view', [$company, $organisation]);
$company->loadCount('persons');
return $this->success(new CompanyResource($company));
}
public function update(UpdateCompanyRequest $request, Organisation $organisation, Company $company): JsonResponse
{
Gate::authorize('update', [$company, $organisation]);

View File

@@ -17,10 +17,10 @@ final class StoreCompanyRequest extends FormRequest
public function rules(): array
{
return [
'name' => ['required', 'string', 'max:255'],
'name' => ['required', 'string', 'max:100'],
'type' => ['required', 'in:supplier,partner,agency,venue,other'],
'contact_name' => ['nullable', 'string', 'max:255'],
'contact_email' => ['nullable', 'email', 'max:255'],
'contact_name' => ['nullable', 'string', 'max:100'],
'contact_email' => ['nullable', 'email', 'max:100'],
'contact_phone' => ['nullable', 'string', 'max:30'],
];
}

View File

@@ -17,10 +17,10 @@ final class UpdateCompanyRequest extends FormRequest
public function rules(): array
{
return [
'name' => ['sometimes', 'string', 'max:255'],
'name' => ['sometimes', 'string', 'max:100'],
'type' => ['sometimes', 'in:supplier,partner,agency,venue,other'],
'contact_name' => ['nullable', 'string', 'max:255'],
'contact_email' => ['nullable', 'email', 'max:255'],
'contact_name' => ['nullable', 'string', 'max:100'],
'contact_email' => ['nullable', 'email', 'max:100'],
'contact_phone' => ['nullable', 'string', 'max:30'],
];
}

View File

@@ -19,6 +19,7 @@ final class CompanyResource extends JsonResource
'contact_name' => $this->contact_name,
'contact_email' => $this->contact_email,
'contact_phone' => $this->contact_phone,
'persons_count' => $this->whenCounted('persons'),
'created_at' => $this->created_at->toIso8601String(),
];
}

View File

@@ -7,6 +7,7 @@ namespace App\Models;
use Illuminate\Database\Eloquent\Concerns\HasUlids;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\SoftDeletes;
@@ -35,4 +36,10 @@ final class Company extends Model
{
return $this->hasMany(Person::class);
}
/** @param Builder<self> $query */
public function scopeOrdered(Builder $query): Builder
{
return $query->orderBy('name');
}
}

View File

@@ -16,6 +16,16 @@ final class CompanyPolicy
|| $organisation->users()->where('user_id', $user->id)->exists();
}
public function view(User $user, Company $company, Organisation $organisation): bool
{
if ($company->organisation_id !== $organisation->id) {
return false;
}
return $user->hasRole('super_admin')
|| $organisation->users()->where('user_id', $user->id)->exists();
}
public function create(User $user, Organisation $organisation): bool
{
return $this->canManageOrganisation($user, $organisation);