Big changes added events for decisions
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use App\Models\Activity;
|
||||
use App\Models\Contract;
|
||||
use App\Models\FieldJob;
|
||||
use App\Models\FieldJobSetting;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class EndFieldJob implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
public function __construct(
|
||||
public int $activityId,
|
||||
public ?int $contractId = null,
|
||||
public array $config = []
|
||||
) {}
|
||||
|
||||
public function handle(): void
|
||||
{
|
||||
$activity = Activity::query()->find($this->activityId);
|
||||
|
||||
// Determine target contract ID
|
||||
$contractId = $this->contractId;
|
||||
if (! $contractId && $activity) {
|
||||
$contractId = $activity->contract_id;
|
||||
}
|
||||
if (! $contractId) {
|
||||
\Log::warning('EndFieldJob: missing contract id', ['activity_id' => $this->activityId]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Use latest FieldJobSetting as the source of action/decision/segments
|
||||
$setting = FieldJobSetting::query()->latest('id')->first();
|
||||
|
||||
$triggeredByEvent = (bool) $activity; // this job is invoked from a decision event when an Activity exists
|
||||
|
||||
DB::transaction(function () use ($contractId, $setting, $triggeredByEvent): void {
|
||||
// Find active field job for this contract
|
||||
$job = FieldJob::query()
|
||||
->where('contract_id', $contractId)
|
||||
->whereNull('completed_at')
|
||||
->whereNull('cancelled_at')
|
||||
->latest('id')
|
||||
->first();
|
||||
|
||||
if ($job) {
|
||||
// Complete the job (updated hook moves segment appropriately)
|
||||
$job->completed_at = now();
|
||||
$job->save();
|
||||
|
||||
// Optionally log a completion activity.
|
||||
// By default, we SKIP creating an extra activity when triggered by a decision event (to avoid duplicates).
|
||||
// To force creation from an event, set config['create_activity_from_event'] = true on the decision event.
|
||||
// For non-event triggers, set config['create_activity'] = true to allow creation.
|
||||
$shouldCreateActivity = $triggeredByEvent
|
||||
? (bool) ($this->config['create_activity_from_event'] ?? false)
|
||||
: (bool) ($this->config['create_activity'] ?? false);
|
||||
|
||||
if ($shouldCreateActivity) {
|
||||
$job->loadMissing('contract');
|
||||
$actionId = optional($job->setting)->action_id ?? optional($setting)->action_id;
|
||||
$decisionId = optional($job->setting)->complete_decision_id ?? optional($setting)->complete_decision_id;
|
||||
if ($actionId && $decisionId && $job->contract) {
|
||||
Activity::create([
|
||||
'due_date' => null,
|
||||
'amount' => null,
|
||||
'note' => 'Terensko opravilo zaključeno',
|
||||
'action_id' => $actionId,
|
||||
'decision_id' => $decisionId,
|
||||
'client_case_id' => $job->contract->client_case_id,
|
||||
'contract_id' => $job->contract_id,
|
||||
]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// No active job: still move contract to the configured return segment if available
|
||||
if ($setting && $setting->return_segment_id) {
|
||||
$tmp = new FieldJob;
|
||||
$tmp->contract_id = $contractId;
|
||||
$tmp->moveContractToSegment($setting->return_segment_id);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
\Log::info('EndFieldJob executed', [
|
||||
'activity_id' => $this->activityId,
|
||||
'contract_id' => $contractId,
|
||||
'config' => $this->config,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use App\Models\Activity;
|
||||
use App\Models\Event as DecisionEventModel;
|
||||
use App\Services\DecisionEvents\DecisionEventContext;
|
||||
use App\Services\DecisionEvents\Registry;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class RunDecisionEvent implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
public function __construct(
|
||||
public int $activityId,
|
||||
public int $eventId,
|
||||
public string $eventKey,
|
||||
public array $config = [],
|
||||
) {}
|
||||
|
||||
public function handle(): void
|
||||
{
|
||||
// Basic idempotency key per activity+event
|
||||
$idempotencyKey = sha1($this->activityId.'|'.$this->eventId.'|'.$this->eventKey);
|
||||
|
||||
// Ensure log table record and uniqueness
|
||||
$exists = DB::table('decision_event_logs')->where('idempotency_key', $idempotencyKey)->first();
|
||||
if ($exists && ($exists->status ?? null) === 'succeeded') {
|
||||
return; // already processed successfully
|
||||
}
|
||||
try {
|
||||
$activity = Activity::with(['decision', 'contract', 'clientCase.client', 'user'])->findOrFail($this->activityId);
|
||||
|
||||
if (! $exists) {
|
||||
DB::table('decision_event_logs')->insert([
|
||||
'decision_id' => optional($activity->decision)->id,
|
||||
'event_id' => $this->eventId,
|
||||
'activity_id' => $this->activityId,
|
||||
'handler' => $this->eventKey,
|
||||
'status' => 'queued',
|
||||
'idempotency_key' => $idempotencyKey,
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
$exists = (object) ['status' => 'queued'];
|
||||
}
|
||||
|
||||
DB::table('decision_event_logs')->where('idempotency_key', $idempotencyKey)->update([
|
||||
'status' => 'running',
|
||||
'started_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
$event = DecisionEventModel::findOrFail($this->eventId);
|
||||
|
||||
$handler = Registry::resolve($this->eventKey);
|
||||
$context = new DecisionEventContext(
|
||||
activity: $activity,
|
||||
decision: $activity->decision,
|
||||
contract: $activity->contract,
|
||||
clientCase: $activity->clientCase,
|
||||
client: optional($activity->clientCase)->client,
|
||||
user: $activity->user,
|
||||
);
|
||||
|
||||
$handler->handle($context, $this->config);
|
||||
|
||||
DB::table('decision_event_logs')->where('idempotency_key', $idempotencyKey)->update([
|
||||
'status' => 'succeeded',
|
||||
'finished_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
} catch (\Throwable $e) {
|
||||
DB::table('decision_event_logs')->where('idempotency_key', $idempotencyKey)->update([
|
||||
'status' => 'failed',
|
||||
'message' => substr($e->getMessage(), 0, 2000),
|
||||
'finished_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
throw $e; // allow retry
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user