Files
Investidor-V2/app/Services/PortalAudit.php
T

53 lines
3.1 KiB
PHP

<?php
namespace App\Services;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Illuminate\Validation\ValidationException;
class PortalAudit
{
/** @param array<string, mixed> $data */
public static function save(Model $record, array $data, int $actor, ?int $expectedVersion = null): void
{
DB::transaction(function () use ($record, $data, $actor, $expectedVersion) {
$created = ! $record->exists;
if (! $created) {
$locked = $record->newQuery()->where($record->getKeyName(), $record->getKey())->lockForUpdate()->firstOrFail();
$record->setRawAttributes($locked->getAttributes(), true);
if ($expectedVersion !== null && (int) $locked->getAttribute('version_no') !== $expectedVersion) {
throw ValidationException::withMessages(['version' => 'Este registo foi alterado por outra operação. Compare os dados actuais antes de continuar; as suas alterações foram conservadas.']);
}
}
$versionedCrm = in_array($record->getTable(), ['investors', 'contacts', 'leads', 'tasks'], true);
// Exclude free text and personal data from the immutable event payload.
$fields = ['primary_territory_id', 'territory_version', 'version_no', 'status', 'is_active', 'is_featured', 'sort_order', 'sector_id', 'maturity_level',
'estimated_investment_amount', 'estimated_investment_currency', 'owner_user_id', 'assignee_user_id', 'due_at',
'cluster_id', 'project_id', 'corridor_id', 'dossier_id', 'interest_request_id', 'publication_status', 'editor_id', 'reviewer_id', 'role', 'stage', 'value_chain_id', 'from_value_chain_id', 'to_value_chain_id', 'link_type', 'deleted_at'];
$before = array_intersect_key($record->getAttributes(), array_flip($fields));
$record->fill($data);
if ($versionedCrm && ! $created && ! $record->isDirty()) {
return;
}
if ($versionedCrm && ! array_key_exists('version_no', $data)) {
$record->setAttribute('version_no', $created ? ($record->getAttribute('version_no') ?? 1) : (int) $record->getOriginal('version_no') + 1);
}
$changed = array_keys($record->getDirty());
$record->save();
if (! $changed) {
return;
}
DB::table('audit_events')->insert([
'source_system' => 'portal-management', 'actor_user_id' => $actor,
'entity_type' => $record->getTable(), 'entity_id' => Str::isUuid((string) $record->getKey()) ? $record->getKey() : null,
'action' => $created ? 'created' : 'updated',
'before_data' => json_encode(['record_id' => $record->getKey(), 'values' => $before], JSON_THROW_ON_ERROR),
'after_data' => json_encode(['record_id' => $record->getKey(), 'changed_fields' => $changed,
'values' => array_intersect_key($record->getAttributes(), array_flip($fields))], JSON_THROW_ON_ERROR),
]);
});
}
}