CRM/backend/app/Http/Controllers/Api/CompanyController.php

131 خطوط
5.2 KiB
PHP

<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\Company;
use App\Services\ActivityLogger;
use App\Services\DuplicateService;
use App\Support\AccessControl;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Gate;
class CompanyController extends Controller
{
public function __construct(private DuplicateService $duplicates) {}
public function index(Request $request): JsonResponse
{
Gate::authorize('viewAny', Company::class);
$query = Company::with('owner:id,name')->withCount(['contacts', 'leads', 'deals']);
AccessControl::scopeCompanies($query, auth()->user());
if ($request->search) {
$search = $request->search;
$query->where(fn ($q) => $q->where('name', 'like', "%{$search}%")->orWhere('website', 'like', "%{$search}%")->orWhere('city', 'like', "%{$search}%"));
}
if ($request->status) {
$query->where('status', $request->status);
}
if ($request->owner_id) {
$query->where('owner_id', $request->owner_id);
}
return response()->json($query->latest()->paginate(min((int) $request->get('per_page', 15), 100)));
}
public function store(Request $request): JsonResponse
{
Gate::authorize('create', Company::class);
$validated = $this->validated($request);
$validated['owner_id'] ??= auth()->id();
abort_unless(AccessControl::canAssignUser(auth()->user(), $validated['owner_id']), 403, 'مالک انتخاب‌شده خارج از محدوده مجاز است.');
$suggestions = $this->duplicates->companySuggestions($validated, null, auth()->user());
if ($request->boolean('block_duplicates') && $suggestions) {
return response()->json(['message' => 'شرکت مشابهی در سیستم وجود دارد.', 'duplicates' => $suggestions], 422);
}
$company = Company::create($this->prepare($validated) + ['created_by' => auth()->id()]);
ActivityLogger::log('company_created', "Company {$company->name} created", $company);
$payload = $company->load('owner:id,name')->toArray();
if ($suggestions) {
$payload['duplicate_suggestions'] = $suggestions;
}
return response()->json($payload, 201);
}
public function show(Company $company): JsonResponse
{
Gate::authorize('view', $company);
return response()->json($company->load([
'owner:id,name', 'contacts.phones', 'leads.pipelineStage', 'deals.product', 'notes.user:id,name', 'attachments.uploader:id,name',
]));
}
public function update(Request $request, Company $company): JsonResponse
{
Gate::authorize('update', $company);
$validated = $this->validated($request, true);
if (array_key_exists('owner_id', $validated)) {
abort_unless(AccessControl::canAssignUser(auth()->user(), $validated['owner_id']), 403, 'مالک انتخاب‌شده خارج از محدوده مجاز است.');
}
$company->update($this->prepare($validated));
ActivityLogger::log('company_updated', "Company {$company->name} updated", $company);
return response()->json($company->fresh('owner:id,name'));
}
public function destroy(Company $company): JsonResponse
{
Gate::authorize('delete', $company);
$company->delete();
ActivityLogger::log('company_deleted', "Company {$company->id} deleted");
return response()->json(['message' => 'شرکت حذف شد']);
}
public function merge(Request $request, Company $company): JsonResponse
{
Gate::authorize('update', $company);
abort_unless(auth()->user()?->can('merge_duplicates'), 403, 'شما مجوز ادغام رکوردهای تکراری را ندارید.');
$validated = $request->validate(['target_id' => 'required|exists:companies,id|different:'.$company->id]);
$target = Company::findOrFail($validated['target_id']);
Gate::authorize('update', $target);
return response()->json($this->duplicates->mergeCompanies($company, $target, auth()->id()));
}
private function validated(Request $request, bool $partial = false): array
{
$sometimes = $partial ? 'sometimes|' : '';
return $request->validate([
'name' => $sometimes.'required|string|max:255',
'company_type' => 'nullable|string|max:80',
'industry' => 'nullable|string|max:120',
'city' => 'nullable|string|max:120',
'address' => 'nullable|string',
'website' => 'nullable|string|max:255',
'description' => 'nullable|string',
'status' => 'nullable|string|max:40',
'owner_id' => 'nullable|exists:users,id',
]);
}
private function prepare(array $data): array
{
if (array_key_exists('name', $data)) {
$data['normalized_name'] = DuplicateService::normalizeName($data['name']);
}
if (array_key_exists('website', $data)) {
$data['normalized_website'] = DuplicateService::normalizeWebsite($data['website']);
}
return $data;
}
}