236 lines
8.1 KiB
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;
|
|
}
|
|
}
|