Files
Investidor-V2/app/Services/OpportunityCanonicalResponse.php
T
nala 20971d523f
tests / ci (push) Canceled after 0s
oportunidades 6
2026-10-10 21:17:46 +02:00

71 lines
3.9 KiB
PHP

<?php
namespace App\Services;
use App\Models\Opportunity;
use App\Models\User;
/** Read adapter only: preserve persisted identifiers and make unresolved metadata explicit. */
class OpportunityCanonicalResponse
{
public const VERSION = 'opportunity-response-existing-ids-20261010-1';
/** @return array<string,mixed> */
public function read(User $actor, Opportunity $record): array
{
$access = app(PortalProfileAccess::class);
$access->authorize($actor, 'view', $record);
$payload = app(OpportunityManagement::class)->values($record)['canonical'] ?? [];
$context = $record->workflow_context ?? [];
$data = [...$payload, 'id' => $record->id, 'opportunity_code' => $record->reference,
'opportunity_category' => $record->opportunity_category, 'status' => $access->state($record),
'version' => (int) $record->management_version, 'is_deleted' => $record->trashed(),
'deleted_at' => $record->deleted_at?->toIso8601String()];
foreach (['submitted' => 'submission', 'approved' => 'approval', 'published' => 'publication'] as $prefix => $key) {
$data[$prefix.'_by'] = $context[$key]['actor_id'] ?? null;
$data[$prefix.'_at'] = $context[$key]['at'] ?? null;
}
$references = [];
foreach (OpportunityResources::KINDS as $kind) {
$references[$kind] = $payload[$kind] ?? [];
$rows = [];
if (app(OpportunityResources::class)->installed()) {
foreach (app(OpportunityResources::class)->listing($record->id, $kind) as $row) {
$rows[$row->id] = $row;
}
}
$data[$kind] = array_map(function (string $id) use ($rows, $kind): array {
$row = $rows[$id] ?? null;
if ($row === null) {
return ['id' => $id, 'availability' => 'unavailable'];
}
$value = [...$row->payload, 'id' => $row->id, 'version' => (int) $row->version,
'is_deleted' => $row->deleted_at !== null, 'deleted_at' => $row->deleted_at,
'created_by' => $row->created_by, 'created_at' => $row->created_at, 'updated_at' => $row->updated_at];
if ($kind !== 'locations') {
$value['original_name'] = $row->file?->file_name;
$value['mime_type'] = $row->file?->media_type;
$value['sha256'] = $row->file?->sha256;
$value['scan_recorded_status'] = $row->file?->malware_scan_status;
}
return $value;
}, $references[$kind]);
}
return ['adapter_version' => self::VERSION,
'source_schema_sha256' => hash_file('sha256', resource_path('data/investmoz-opportunity-modular.schema.json')),
'data' => $data, 'resource_references' => $references,
'validation_result' => ['scope' => 'recorded_submission_only', 'submission_hash' => $context['submission']['hash'] ?? null,
'submitted_content_revision' => $context['submission']['content_revision'] ?? null,
'current_content_revision' => $context['content_revision'] ?? 1,
'revalidated_on_read' => false, 'external_decision' => 'not_inferred'],
'publication' => $record->publicationPresentation(),
'compatibility' => ['normative_response_complete' => false, 'opportunity_actor_sector_ids' => 'existing bigint, not converted to UUID',
'opportunity_code' => 'existing reference preserved; no INV-MZ code invented',
'states' => 'existing workflow values preserved; no implicit stage equivalence',
'inline_modules' => 'management_draft canonical JSON with audited revisions; no parallel specialized tables',
'metadata_gaps' => ['completion_percentage algorithm', 'inline item IDs and mutation metadata', 'resource updated_by/deleted_by recovery']]];
}
}