Skip to content

FOUR-18602 populate cases_started table DB Exception when populating the cases_started table #7445

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Oct 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions ProcessMaker/Console/Commands/CasesSync.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php

namespace ProcessMaker\Console\Commands;

use Illuminate\Console\Command;
use ProcessMaker\Repositories\CaseSyncRepository;

class CasesSync extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'cases:sync
{--request_ids= : Comma-separated list of request IDs to sync}';

/**
* The console command description.
*
* @var string
*/
protected $description = 'Sync requests with the cases tables';

/**
* Execute the console command.
*/
public function handle()
{
$requestIds = $this->option('request_ids');
$requestIds = $requestIds ? explode(',', $requestIds) : [];

if (count($requestIds) > 0) {
$data = CaseSyncRepository::syncCases($requestIds);

foreach ($data['successes'] as $value) {
$this->info('Case started synced ' . $value);
}

foreach ($data['errors'] as $value) {
$this->error('Error syncing case started ' . $value);
}
} else {
$this->error('Please specify a list of request IDs.');
}
}
}
10 changes: 7 additions & 3 deletions ProcessMaker/Repositories/CaseParticipatedRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace ProcessMaker\Repositories;

use Illuminate\Support\Facades\Log;
use ProcessMaker\Models\CaseParticipated;
use ProcessMaker\Models\CaseStarted;
use ProcessMaker\Nayra\Contracts\Bpmn\TokenInterface;
Expand Down Expand Up @@ -44,7 +45,8 @@ public function create(CaseStarted $case, TokenInterface $token): void
'completed_at' => null,
]);
} catch (\Exception $e) {
\Log::error($e->getMessage());
Log::error('CaseException: ' . $e->getMessage());
Log::error('CaseException: ' . $e->getTraceAsString());
}
}

Expand Down Expand Up @@ -73,7 +75,8 @@ public function update(CaseStarted $case, TokenInterface $token)
'participants' => $case->participants,
]);
} catch (\Exception $e) {
\Log::error($e->getMessage());
Log::error('CaseException: ' . $e->getMessage());
Log::error('CaseException: ' . $e->getTraceAsString());
}
}

Expand All @@ -90,7 +93,8 @@ public function updateStatus(int $caseNumber, array $statusData)
CaseParticipated::where('case_number', $caseNumber)
->update($statusData);
} catch (\Exception $e) {
\Log::error($e->getMessage());
Log::error('CaseException: ' . $e->getMessage());
Log::error('CaseException: ' . $e->getTraceAsString());
}
}

Expand Down
45 changes: 25 additions & 20 deletions ProcessMaker/Repositories/CaseRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace ProcessMaker\Repositories;

use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use ProcessMaker\Contracts\CaseRepositoryInterface;
use ProcessMaker\Models\CaseStarted;
use ProcessMaker\Nayra\Contracts\Bpmn\TokenInterface;
Expand All @@ -12,15 +13,20 @@ class CaseRepository implements CaseRepositoryInterface
{
const CASE_STATUS_ACTIVE = 'ACTIVE';

/**
* @var CaseParticipatedRepository
*/
protected CaseParticipatedRepository $caseParticipatedRepository;
/**
* This property is used to store an instance of `CaseStarted`
* when a case started is updated.
* @var CaseStarted|null
*/
protected ?CaseStarted $case;

public function __construct(protected CaseParticipatedRepository $caseParticipatedRepository)
public function __construct()
{
$this->caseParticipatedRepository = new CaseParticipatedRepository();
}
/**
* Store a new case started.
Expand All @@ -31,8 +37,7 @@ public function __construct(protected CaseParticipatedRepository $caseParticipat
public function create(ExecutionInstanceInterface $instance): void
{
if (is_null($instance->case_number)) {
\Log::error('Case number is required. instance: ' . $instance->getKey());

Log::error('case number is required, method=create, instance=' . $instance->getKey());
return;
}

Expand All @@ -58,8 +63,8 @@ public function create(ExecutionInstanceInterface $instance): void
'completed_at' => null,
]);
} catch (\Exception $e) {
\Log::error($e->getMessage());
\Log::error($e->getTraceAsString());
Log::error('CaseException: ' . $e->getMessage());
Log::error('CaseException: ' . $e->getTraceAsString());
}
}

Expand All @@ -72,19 +77,12 @@ public function create(ExecutionInstanceInterface $instance): void
*/
public function update(ExecutionInstanceInterface $instance, TokenInterface $token): void
{
if (is_null($instance->case_number)) {
\Log::error('Case number is required. instance: ' . $instance->getKey());

if (!$this->checkIfCaseStartedExist($instance->case_number)) {
Log::error('case started not found, method=update, instance=' . $instance->getKey());
return;
}

try {
if (!$this->checkIfCaseStartedExist($instance->case_number)) {
\Log::error('Case number not found. instance: ' . $instance->id);

return;
}

$this->case->case_title = $instance->case_title;
$this->case->case_status = $instance->status === self::CASE_STATUS_ACTIVE ? 'IN_PROGRESS' : $instance->status;
$this->case->request_tokens = CaseUtils::storeRequestTokens($token->getKey(), $this->case->request_tokens);
Expand All @@ -94,7 +92,8 @@ public function update(ExecutionInstanceInterface $instance, TokenInterface $tok

$this->case->saveOrFail();
} catch (\Exception $e) {
\Log::error($e->getMessage());
Log::error('CaseException: ' . $e->getMessage());
Log::error('CaseException: ' . $e->getTraceAsString());
}
}

Expand Down Expand Up @@ -124,7 +123,8 @@ public function updateStatus(ExecutionInstanceInterface $instance): void
CaseStarted::where('case_number', $instance->case_number)->update($data);
$this->caseParticipatedRepository->updateStatus($instance->case_number, $data);
} catch (\Exception $e) {
\Log::error($e->getMessage());
Log::error('CaseException: ' . $e->getMessage());
Log::error('CaseException: ' . $e->getTraceAsString());
}
}

Expand Down Expand Up @@ -163,11 +163,15 @@ private function updateParticipants(TokenInterface $token): void
/**
* Check if the case started exist.
*
* @param int $caseNumber
* @param int|null $caseNumber
* @return bool
*/
private function checkIfCaseStartedExist(int $caseNumber): bool
private function checkIfCaseStartedExist(int | null $caseNumber): bool
{
if (is_null($caseNumber)) {
return false;
}

$this->case = CaseStarted::where('case_number', $caseNumber)->first();

return !is_null($this->case);
Expand All @@ -191,8 +195,9 @@ private function updateSubProcesses(ExecutionInstanceInterface $instance): void
$this->case->requests = CaseUtils::storeRequests($instance, $this->case->requests);

$this->case->saveOrFail();
} catch (\Exception $th) {
\Log::error($th->getMessage());
} catch (\Exception $e) {
Log::error('CaseException: ' . $e->getMessage());
Log::error('CaseException: ' . $e->getTraceAsString());
}
}
}
190 changes: 190 additions & 0 deletions ProcessMaker/Repositories/CaseSyncRepository.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
<?php

namespace ProcessMaker\Repositories;

use Illuminate\Support\Collection;
use ProcessMaker\Models\CaseParticipated;
use ProcessMaker\Models\CaseStarted;
use ProcessMaker\Models\ProcessRequest;

class CaseSyncRepository
{
/**
* Sync the cases started.
*
* @param array $requestIds
* @return array
*/
public static function syncCases(array $requestIds): array
{
$requests = ProcessRequest::with([
'tokens', 'process', 'childRequests.process', 'childRequests.tokens', 'participants',
])
->whereIn('id', $requestIds)
->get();

$successes = [];
$errors = [];

foreach ($requests as $instance) {
try {
if (!is_null($instance->parent_request_id)) {
continue;
}

$csProcesses = CaseUtils::storeProcesses($instance, collect());
$csRequests = CaseUtils::storeRequests($instance, collect());
$csRequestTokens = collect();
$csTasks = collect();
$participants = $instance->participants->map->only('id', 'fullName', 'title', 'avatar');
$status = $instance->status === CaseRepository::CASE_STATUS_ACTIVE ? 'IN_PROGRESS' : $instance->status;

$cpData = self::prepareCaseStartedData($instance, $status, $participants);

self::processTokens($instance, $cpData, $csRequestTokens, $csTasks);

self::processChildRequests($instance, $cpData, $csProcesses, $csRequests, $participants, $csRequestTokens, $csTasks);

$caseStarted = CaseStarted::updateOrCreate(
['case_number' => $instance->case_number],
[
'user_id' => $instance->user_id,
'case_title' => $instance->case_title,
'case_title_formatted' => $instance->case_title_formatted,
'case_status' => $status,
'processes' => $csProcesses,
'requests' => $csRequests,
'request_tokens' => $csRequestTokens,
'tasks' => $csTasks,
'participants' => $participants,
'initiated_at' => $instance->initiated_at,
'completed_at' => $instance->completed_at,
],
);

$successes[] = $caseStarted->case_number;
} catch (\Exception $e) {
$errors[] = $instance->case_number . ' ' . $e->getMessage();
}
}

return [
'successes' => $successes,
'errors' => $errors,
];
}

/**
* Prepare the case started data.
*
* @param ProcessRequest $instance
* @param string $status
* @param Collection $participants
* @return array
*/
private static function prepareCaseStartedData($instance, $status, $participants)
{
return [
'case_title' => $instance->case_title,
'case_title_formatted' => $instance->case_title_formatted,
'case_status' => $status,
'processes' => CaseUtils::storeProcesses($instance, collect()),
'requests' => CaseUtils::storeRequests($instance, collect()),
'request_tokens' => collect(),
'tasks' => collect(),
'participants' => $participants,
'initiated_at' => $instance->initiated_at,
'completed_at' => $instance->completed_at,
];
}

/**
* Process the tokens.
*
* @param ProcessRequest $instance
* @param array $cpData
* @param Collection $csRequestTokens
* @param Collection $csTasks
* @return void
*/
private static function processTokens($instance, &$cpData, &$csRequestTokens, &$csTasks)
{
foreach ($instance->tokens as $token) {
if (in_array($token->element_type, CaseUtils::ALLOWED_REQUEST_TOKENS)) {
$cpData['processes'] = CaseUtils::storeProcesses($instance, $cpData['processes']);
$cpData['requests'] = CaseUtils::storeRequests($instance, $cpData['requests']);
$cpData['request_tokens'] = CaseUtils::storeRequestTokens($token->getKey(), $cpData['request_tokens']);
$cpData['tasks'] = CaseUtils::storeTasks($token, $cpData['tasks']);

$csRequestTokens = CaseUtils::storeRequestTokens($token->getKey(), $csRequestTokens);
$csTasks = CaseUtils::storeTasks($token, $csTasks);

self::syncCasesParticipated($instance->case_number, $token->user_id, $cpData);
}
}
}

/**
* Process the child requests.
*
* @param ProcessRequest $instance
* @param array $cpData
* @param Collection $csProcesses
* @param Collection $csRequests
* @param Collection $participants
* @param Collection $csRequestTokens
* @param Collection $csTasks
* @return void
*/
private static function processChildRequests(
$instance, &$cpData, &$csProcesses, &$csRequests, &$participants, &$csRequestTokens, &$csTasks
)
{
foreach ($instance->childRequests as $subProcess) {
$cpData['processes'] = CaseUtils::storeProcesses($subProcess, collect());
$cpData['requests'] = CaseUtils::storeRequests($subProcess, collect());
$cpData['request_tokens'] = collect();
$cpData['tasks'] = collect();

$csProcesses = CaseUtils::storeProcesses($subProcess, $csProcesses);
$csRequests = CaseUtils::storeRequests($subProcess, $csRequests);

$participants = $participants
->merge($subProcess->participants->map->only('id', 'fullName', 'title', 'avatar'))
->unique('id')
->values();

foreach ($subProcess->tokens as $spToken) {
if (in_array($spToken->element_type, CaseUtils::ALLOWED_REQUEST_TOKENS)) {
$cpData['processes'] = CaseUtils::storeProcesses($subProcess, $cpData['processes']);
$cpData['requests'] = CaseUtils::storeRequests($subProcess, $cpData['requests']);
$cpData['request_tokens'] = CaseUtils::storeRequestTokens($spToken->getKey(), $cpData['request_tokens']);
$cpData['tasks'] = CaseUtils::storeTasks($spToken, $cpData['tasks']);

$csRequestTokens = CaseUtils::storeRequestTokens($spToken->getKey(), $csRequestTokens);
$csTasks = CaseUtils::storeTasks($spToken, $csTasks);

self::syncCasesParticipated($instance->case_number, $spToken->user_id, $cpData);
}
}
}
}

/**
* Sync the cases participated.
*
* @param CaseStarted $caseStarted
* @param TokenInterface $token
* @return void
*/
private static function syncCasesParticipated($caseNumber, $userId, $data)
{
CaseParticipated::updateOrCreate(
[
'case_number' => $caseNumber,
'user_id' => $userId,
],
$data,
);
}
}
Loading
Loading