ultimatepos/Modules/AssetExchange/Services/ResearchCaseService.php

236 lines
8.1 KiB
PHP

<?php
namespace Modules\AssetExchange\Services;
use App\Business;
use App\User;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Modules\AssetExchange\Models\Listing;
use Modules\AssetExchange\Models\ResearchCase;
use Modules\AssetExchange\Models\ResearchTask;
use Modules\AssetExchange\Models\ResearchTaskTemplate;
use Modules\AssetExchange\Utils\AssetExchangeUtil;
class ResearchCaseService
{
public function __construct(
protected AssetExchangeUtil $aexUtil,
protected PipelineService $pipelineService
) {
}
public function openCase(Business $business, Listing $listing, array $options = [], ?User $user = null): ResearchCase
{
if (! Schema::hasTable('aex_research_cases')) {
throw new \RuntimeException('جدول پرونده تحقیق موجود نیست.');
}
$existing = ResearchCase::where('business_id', $business->id)
->where('listing_id', $listing->id)
->whereIn('status', ['open', 'in_progress', 'review'])
->first();
if ($existing && empty($options['force_new'])) {
return $existing->load('tasks');
}
return DB::transaction(function () use ($business, $listing, $options, $user) {
$case = ResearchCase::create([
'business_id' => $business->id,
'listing_id' => $listing->id,
'case_code' => $options['case_code'] ?? $this->aexUtil->generateResearchCaseCode($business->id),
'title' => $options['title'] ?? ('پرونده تحقیق — '.$listing->title),
'status' => 'open',
'lead_researcher_id' => $options['lead_researcher_id'] ?? $listing->assigned_broker_user_id,
'started_at' => now(),
'created_by' => $user?->id,
]);
if (! empty($options['spawn_templates'])) {
$this->spawnTasksFromTemplates($business, $case, $options['template_keys'] ?? null);
}
if (! empty($options['tasks']) && is_array($options['tasks'])) {
foreach ($options['tasks'] as $taskData) {
$this->addTask($business, $case, $taskData);
}
}
$this->pipelineService->logEvent(
$business,
ResearchCase::class,
$case->id,
'research_case_opened',
'پرونده تحقیق باز شد',
$user
);
return $case->fresh(['tasks.assignee']);
});
}
public function spawnTasksFromTemplates(Business $business, ResearchCase $case, ?array $templateKeys = null): int
{
$query = ResearchTaskTemplate::query()
->where('is_active', true)
->where(function ($q) use ($business) {
$q->whereNull('business_id')->orWhere('business_id', $business->id);
})
->orderBy('sort_order');
if ($templateKeys) {
$query->whereIn('template_key', $templateKeys);
}
$templates = $query->get();
$created = 0;
foreach ($templates as $tpl) {
$exists = ResearchTask::where('research_case_id', $case->id)
->where('template_key', $tpl->template_key)
->exists();
if ($exists) {
continue;
}
$this->addTask($business, $case, [
'template_key' => $tpl->template_key,
'category' => $tpl->category,
'title' => $tpl->title,
'description' => $tpl->description,
'instructions' => $tpl->instructions,
'priority' => $tpl->default_priority,
'sort_order' => $tpl->sort_order,
]);
$created++;
}
return $created;
}
public function addTask(Business $business, ResearchCase $case, array $data): ResearchTask
{
$task = ResearchTask::create([
'business_id' => $business->id,
'research_case_id' => $case->id,
'template_key' => $data['template_key'] ?? null,
'category' => $data['category'] ?? 'general',
'title' => $data['title'],
'description' => $data['description'] ?? null,
'instructions' => $data['instructions'] ?? null,
'assignee_user_id' => $data['assignee_user_id'] ?? null,
'status' => 'pending',
'priority' => $data['priority'] ?? 'normal',
'due_date' => ! empty($data['due_date'])
? $this->aexUtil->parseInputDate($data['due_date'])
: null,
'sort_order' => (int) ($data['sort_order'] ?? 0),
]);
if (! empty($data['sync_crm_schedule'])) {
$this->syncTaskToCrmSchedule($business, $case, $task);
}
return $task;
}
public function assignTask(ResearchTask $task, int $userId, bool $syncCrm = true): ResearchTask
{
$task->update(['assignee_user_id' => $userId, 'status' => 'in_progress']);
$case = $task->researchCase;
if ($case) {
$business = Business::find($case->business_id);
if ($syncCrm && $business) {
$this->syncTaskToCrmSchedule($business, $case, $task->fresh());
}
}
return $task->fresh(['assignee']);
}
public function completeTask(ResearchTask $task, array $data, ?User $user = null): ResearchTask
{
$task->update([
'status' => 'completed',
'findings' => $data['findings'] ?? $task->findings,
'findings_json' => $data['findings_json'] ?? $task->findings_json,
'completed_at' => now(),
]);
$case = $task->researchCase;
if ($case) {
$open = $case->tasks()->whereNotIn('status', ['completed', 'cancelled'])->count();
if ($open === 0) {
$case->update(['status' => 'review']);
} else {
$case->update(['status' => 'in_progress']);
}
}
return $task->fresh();
}
public function closeCase(ResearchCase $case, ?string $summary = null, ?User $user = null): ResearchCase
{
$case->update([
'status' => 'closed',
'summary' => $summary ?? $case->summary,
'closed_at' => now(),
]);
return $case->fresh(['tasks']);
}
public function syncTaskToCrmSchedule(Business $business, ResearchCase $case, ResearchTask $task): ?int
{
if (! class_exists(\Modules\Crm\Entities\Schedule::class)) {
return null;
}
if (! Schema::hasTable('crm_schedules')) {
return null;
}
$case->loadMissing('listing');
$contactId = $case->listing?->seller_contact_id;
if (! $contactId) {
return null;
}
$start = $task->due_date
? $task->due_date->copy()->setTime(9, 0)->toDateTimeString()
: now()->addDay()->setTime(9, 0)->toDateTimeString();
$schedule = \Modules\Crm\Entities\Schedule::create([
'business_id' => $business->id,
'contact_id' => $contactId,
'title' => '[AEX] '.$task->title,
'description' => trim(($task->description ?? '')."\n".($task->instructions ?? '')),
'start_datetime' => $start,
'end_datetime' => date('Y-m-d H:i:s', strtotime($start.' +1 hour')),
'schedule_type' => 'call',
'status' => 'open',
'followup_additional_info' => [
'aex_research_task_id' => $task->id,
'aex_research_case_id' => $case->id,
'aex_listing_id' => $case->listing_id,
],
'created_by' => auth()->id(),
]);
if ($task->assignee_user_id && Schema::hasTable('crm_schedule_users')) {
DB::table('crm_schedule_users')->insert([
'schedule_id' => $schedule->id,
'user_id' => $task->assignee_user_id,
]);
}
$task->update(['crm_schedule_id' => $schedule->id]);
return $schedule->id;
}
}