62 lines
3.1 KiB
PHP
62 lines
3.1 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Models\Opportunity;
|
|
use App\Models\User;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Str;
|
|
|
|
/** Existing CRM tasks, explicit portal binding; no invented CRM opportunity or assignee. */
|
|
class OpportunityWorkflowTasks
|
|
{
|
|
public function ensure(Opportunity $record, string $kind, string $title): string
|
|
{
|
|
$key = 'portal-opportunity:'.$record->id.':'.$kind.':'.($record->workflow_context['content_revision'] ?? 1);
|
|
if (isset($record->workflow_context['review_cycle'])) {
|
|
$key .= ':cycle:'.$record->workflow_context['review_cycle'];
|
|
}
|
|
$existing = DB::table('tasks')->where('source_system', 'opportunity-workflow')->where('external_id', $key)->first();
|
|
if ($existing) {
|
|
return $existing->id;
|
|
}
|
|
$id = (string) Str::uuid();
|
|
DB::table('tasks')->insert(['id' => $id, 'source_system' => 'opportunity-workflow', 'external_id' => $key,
|
|
'correlation_id' => $record->management_creation_key, 'task_type' => $kind, 'title' => $title,
|
|
'status' => 'open', 'due_at' => null, 'assignee_user_id' => null, 'data_classification' => 'restricted']);
|
|
|
|
return $id;
|
|
}
|
|
|
|
public function assign(Opportunity $record, string $taskId, User $subject): void
|
|
{
|
|
abort_unless(DB::table('tasks')->where('id', $taskId)->where('source_system', 'opportunity-workflow')
|
|
->where('external_id', 'like', 'portal-opportunity:'.$record->id.':%')->whereIn('status', ['open', 'in_progress'])->exists(), 409, 'Tarefa não pertence à versão aberta.');
|
|
DB::table('tasks')->where('id', $taskId)->update(['assignee_user_id' => $subject->id, 'status' => 'in_progress', 'version_no' => DB::raw('version_no+1')]);
|
|
}
|
|
|
|
public function closedReviewBinding(Opportunity $record, ?string $id): bool
|
|
{
|
|
return $id !== null && DB::table('tasks')->where('id', $id)->where('source_system', 'opportunity-workflow')
|
|
->where('external_id', 'like', 'portal-opportunity:'.$record->id.':opportunity_review:%')->where('status', 'done')->exists();
|
|
}
|
|
|
|
public function complete(?string $taskId, string $outcome): void
|
|
{
|
|
if ($taskId) {
|
|
// Existing CRM outcome is a varchar(80) summary. The full reason is
|
|
// retained in the versioned workflow decision and its audit event.
|
|
$summary = mb_strlen($outcome) > 80 ? mb_substr($outcome, 0, 79).'…' : $outcome;
|
|
DB::table('tasks')->where('id', $taskId)->where('source_system', 'opportunity-workflow')->whereIn('status', ['open', 'in_progress'])
|
|
->update(['status' => 'done', 'outcome' => $summary, 'completed_at' => now(), 'version_no' => DB::raw('version_no+1')]);
|
|
}
|
|
}
|
|
|
|
/** @return list<\stdClass> */
|
|
public function listing(Opportunity $record): array
|
|
{
|
|
return array_values(DB::table('tasks')->where('source_system', 'opportunity-workflow')->where('external_id', 'like', 'portal-opportunity:'.$record->id.':%')
|
|
->get(['id', 'task_type', 'status', 'title', 'assignee_user_id', 'due_at', 'completed_at', 'outcome'])->all());
|
|
}
|
|
}
|