85 خطوط
3.9 KiB
PHP
85 خطوط
3.9 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Api;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Models\Deal;
|
|
use App\Models\DealStage;
|
|
use App\Models\Pipeline;
|
|
use App\Services\DealPipelineService;
|
|
use App\Support\AccessControl;
|
|
use Illuminate\Http\JsonResponse;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Str;
|
|
|
|
class PipelineController extends Controller
|
|
{
|
|
public function __construct(private DealPipelineService $service) {}
|
|
|
|
public function index(Request $request): JsonResponse
|
|
{
|
|
abort_unless($request->user()->can('view_pipelines'), 403);
|
|
$query = Pipeline::with('stages')->where('is_active', true)->orderBy('sort_order');
|
|
if (! $request->user()->hasRole('admin')) {
|
|
$teamIds = AccessControl::teamIds($request->user());
|
|
$query->where(fn ($scope) => $scope->whereNull('team_id')->orWhereIn('team_id', $teamIds));
|
|
}
|
|
|
|
return response()->json($query->get());
|
|
}
|
|
|
|
public function store(Request $request): JsonResponse
|
|
{
|
|
abort_unless($request->user()->can('manage_pipelines'), 403);
|
|
$data = $request->validate([
|
|
'name' => 'required|string|max:120', 'team_id' => 'nullable|exists:teams,id',
|
|
'is_default' => 'boolean', 'stages' => 'required|array|min:2|max:20',
|
|
'stages.*.name' => 'required|string|max:80', 'stages.*.color' => ['nullable', 'regex:/^#[0-9A-Fa-f]{6}$/'],
|
|
'stages.*.probability' => 'required|integer|min:0|max:100', 'stages.*.is_won' => 'boolean', 'stages.*.is_lost' => 'boolean',
|
|
]);
|
|
if (! $request->user()->hasRole('admin') && ! empty($data['team_id'])) {
|
|
abort_unless(in_array((int) $data['team_id'], AccessControl::teamIds($request->user()), true), 403);
|
|
}
|
|
$pipeline = DB::transaction(function () use ($data): Pipeline {
|
|
if ($data['is_default'] ?? false) {
|
|
Pipeline::query()->update(['is_default' => false]);
|
|
}
|
|
$pipeline = Pipeline::create([
|
|
'name' => $data['name'], 'slug' => Str::slug($data['name']).'-'.Str::lower(Str::random(5)),
|
|
'team_id' => $data['team_id'] ?? null, 'is_default' => $data['is_default'] ?? false, 'is_active' => true,
|
|
]);
|
|
foreach ($data['stages'] as $index => $stage) {
|
|
$pipeline->stages()->create($stage + ['slug' => Str::slug($stage['name']).'-'.$index, 'sort_order' => $index, 'is_active' => true]);
|
|
}
|
|
|
|
return $pipeline;
|
|
});
|
|
|
|
return response()->json($pipeline->load('stages'), 201);
|
|
}
|
|
|
|
public function board(Request $request, Pipeline $pipeline): JsonResponse
|
|
{
|
|
abort_unless($request->user()->can('view_pipelines'), 403);
|
|
abort_unless($this->visible($pipeline, $request), 403);
|
|
|
|
return response()->json($this->service->board($pipeline, $request->user(), $request->only(['search', 'owner_id', 'forecast_category', 'status'])));
|
|
}
|
|
|
|
public function move(Request $request, Deal $deal): JsonResponse
|
|
{
|
|
abort_unless($request->user()->can('move_deals'), 403);
|
|
abort_unless(AccessControl::canAccessDeal($request->user(), $deal), 403);
|
|
$data = $request->validate(['deal_stage_id' => 'required|exists:deal_stages,id', 'version' => 'required|integer|min:1', 'reason' => 'nullable|string|max:1000', 'final_amount' => 'nullable|numeric|min:0']);
|
|
$stage = DealStage::findOrFail($data['deal_stage_id']);
|
|
|
|
return response()->json($this->service->move($deal, $stage, $request->user(), $data['version'], $data['reason'] ?? null, isset($data['final_amount']) ? (float) $data['final_amount'] : null));
|
|
}
|
|
|
|
private function visible(Pipeline $pipeline, Request $request): bool
|
|
{
|
|
return $request->user()->hasRole('admin') || $pipeline->team_id === null || in_array($pipeline->team_id, AccessControl::teamIds($request->user()), true);
|
|
}
|
|
}
|