Files
Investidor-V2/app/Models/Opportunity.php
2026-10-23 11:22:39 +02:00

116 lines
4.9 KiB
PHP

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Facades\Schema;
/**
* @property int|null $owner_user_id
* @property string|null $organization_id
* @property array<string,mixed>|null $workflow_context
* @property string|null $primary_territory_id
* @property int $territory_version
* @property int $management_version
* @property string|null $management_draft
* @property string|null $management_creation_key
* @property string|null $first_submitted_at
* @property bool $management_closed_once
* @property string|null $opportunity_category
* @property string|null $estimated_investment_currency
*/
class Opportunity extends Model
{
use SoftDeletes;
protected $hidden = ['management_draft', 'management_creation_key', 'management_version', 'first_submitted_at', 'management_closed_once', 'owner_user_id', 'organization_id', 'workflow_context'];
protected $appends = ['maturity_catalogue_version'];
public function toArray(): array
{
$data = parent::toArray();
if (isset($data['description'])) $data['description'] = \App\Services\OpportunityPublicText::description($this, $data['description']);
return $data;
}
public function getMaturityCatalogueVersionAttribute(): ?string
{
// Only published metadata is public; never expose the current private draft.
$version = data_get($this->workflow_context, 'publication.maturity.catalogue_version');
return in_array($version, [\App\Services\OpportunityMaturity::VERSION, \App\Services\OpportunityMaturity::LEGACY], true)
? $version : null;
}
protected $fillable = [
'sector_id', 'reference', 'title', 'slug', 'summary', 'description',
'province', 'district', 'promoter_name', 'promoter_type',
'maturity_level', 'maturity_label', 'estimated_investment_amount',
'estimated_investment_currency', 'financing_modality',
'expected_impact', 'status', 'is_featured', 'published_at',
'last_validated_at',
'primary_territory_id', 'territory_version',
'geography_scope',
];
protected $casts = [
'workflow_context' => 'array',
'is_featured' => 'boolean',
'territory_version' => 'integer',
'published_at' => 'datetime',
'last_validated_at' => 'datetime',
'estimated_investment_amount' => 'decimal:2',
];
/** @return array{scope:string,label:string,public_catalog:bool} */
public function publicationPresentation(): array
{
$public = $this->exists && self::query()->whereKey($this->id)->published()->exists();
$visible = ! $this->trashed() && $this->status === 'published' && $this->published_at !== null && $this->published_at->lte(now());
$scope = $public ? 'public' : ($visible && $this->owner_user_id !== null ? 'restricted' : 'unpublished');
return ['scope' => $scope, 'public_catalog' => $public, 'label' => match ($scope) {
'public' => data_get($this->workflow_context, 'publication.purpose') === 'promotional_preparation'
? 'Resumo divulgado — Em preparação; não autoriza execução' : 'Publicada no catálogo público',
'restricted' => 'Disponibilizada com acesso restrito — perfis e organização autorizados',
default => 'Sem versão disponibilizada; aprovação interna é uma etapa distinta',
}];
}
/** @return BelongsTo<Sector, $this> */
public function sector(): BelongsTo
{
return $this->belongsTo(Sector::class);
}
/** @return BelongsTo<GeoLocation, $this> */
public function primaryTerritory(): BelongsTo
{
return $this->belongsTo(GeoLocation::class, 'primary_territory_id');
}
/** @return BelongsToMany<GeoLocation, $this> */
public function additionalTerritories(): BelongsToMany
{
return $this->belongsToMany(GeoLocation::class, 'opportunity_locations', 'opportunity_id', 'geo_location_id');
}
/** @param Builder<Opportunity> $query
* @return Builder<Opportunity>
*/
public function scopePublished(Builder $query): Builder
{
if (Schema::hasColumn('opportunities', 'workflow_context')) {
$query->where(fn ($q) => $q->whereNull('owner_user_id')->orWhere('workflow_context->publication->visibility', 'public'));
}
return $query->where('status', 'published')->whereNotNull('published_at')->where('published_at', '<=', now())
->whereRaw("COALESCE((SELECT origin.after_data->>'classification' FROM audit_events origin WHERE origin.source_system='opportunity-origin-review' AND origin.after_data->>'opportunity_id'=opportunities.id::text ORDER BY origin.occurred_at DESC,origin.id DESC LIMIT 1),'undetermined') <> 'example'");
}
}