79 lines
4.4 KiB
PHP
79 lines
4.4 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Models\ExistingBusinessObject;
|
|
use App\Models\User;
|
|
use App\Services\Mne\BusinessRepository;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Gate;
|
|
use Illuminate\Support\Facades\Validator;
|
|
|
|
final class ExistingBusinessObjects
|
|
{
|
|
public const KINDS = ['company', 'participation', 'asset', 'property', 'unit', 'improvement', 'agricultural_investment', 'land_right', 'contract', 'license', 'authorization', 'encumbrance', 'valuation', 'capital_request'];
|
|
|
|
/** @return array<string,array<int,string>> */
|
|
public static function fields(): array
|
|
{
|
|
return [
|
|
'label' => ['required', 'string', 'max:200'],
|
|
'declared_holder' => ['nullable', 'string', 'max:500'],
|
|
'document_reference' => ['nullable', 'string', 'max:1000'],
|
|
'source_reference' => ['required', 'string', 'min:10', 'max:2000'],
|
|
'competent_entity' => ['nullable', 'string', 'max:500'],
|
|
'purpose' => ['nullable', 'string', 'max:2000'],
|
|
'location_description' => ['nullable', 'string', 'max:2000'],
|
|
'boundaries_description' => ['nullable', 'string', 'max:2000'],
|
|
'occupancy' => ['nullable', 'string', 'max:2000'],
|
|
'condition' => ['nullable', 'string', 'max:2000'],
|
|
'encumbrances' => ['nullable', 'string', 'max:4000'],
|
|
'restrictions' => ['nullable', 'string', 'max:4000'],
|
|
'required_authorizations' => ['nullable', 'string', 'max:4000'],
|
|
'transfer_condition' => ['nullable', 'string', 'max:4000'],
|
|
'contract_type' => ['nullable', 'in:purchase,sale,lease,operation,management,other'],
|
|
'valid_from' => ['nullable', 'date_format:Y-m-d'],
|
|
'valid_until' => ['nullable', 'date_format:Y-m-d'],
|
|
'area' => ['nullable', 'string', 'regex:/^\d{1,12}(\.\d{1,4})?$/', 'numeric', 'gt:0'],
|
|
'area_unit' => ['nullable', 'required_with:area', 'in:m2,ha,km2'],
|
|
'amount' => ['nullable', 'string', 'regex:/^\d{1,15}(\.\d{1,2})?$/', 'numeric', 'min:0'],
|
|
'currency' => ['nullable', 'required_with:amount', 'regex:/^[A-Z]{3}$/'],
|
|
'value_kind' => ['nullable', 'required_with:amount', 'in:asking,indicative,appraised,proposed,negotiated,confirmed'],
|
|
'participation_percent' => ['nullable', 'numeric', 'between:0,100'],
|
|
];
|
|
}
|
|
|
|
/** @param array<string,mixed> $input */
|
|
public function save(User $actor, string $businessId, array $input, ?string $objectId = null): ExistingBusinessObject
|
|
{
|
|
$rules = self::fields();
|
|
if (! empty($input['payload']['valid_from'])) {
|
|
$rules['valid_until'][] = 'after_or_equal:valid_from';
|
|
}
|
|
$data = Validator::make($input, ['version_no' => ['required', 'integer', 'min:1'],
|
|
'kind' => ['required', 'in:'.implode(',', self::KINDS)], 'reason' => ['required', 'string', 'min:10', 'max:1000'],
|
|
'payload' => ['required', 'array:'.implode(',', array_keys($rules))],
|
|
])->validate();
|
|
// Cross-field rules operate on the payload itself, rather than sibling root fields.
|
|
Validator::make($data['payload'], $rules)->validate();
|
|
|
|
return DB::transaction(function () use ($actor, $businessId, $objectId, $data) {
|
|
$business = app(BusinessRepository::class)->find($businessId, true);
|
|
Gate::forUser($actor)->authorize('update', $business);
|
|
abort_unless($business->version_no === $data['version_no'], 409, 'Versão desactualizada.');
|
|
abort_if(! $objectId && ExistingBusinessObject::where('business_id', $businessId)->count() >= 100, 422, 'Máximo de 100 elementos por negócio.');
|
|
$object = $objectId ? ExistingBusinessObject::where('business_id', $businessId)->whereKey($objectId)->firstOrFail() : new ExistingBusinessObject;
|
|
if ($objectId) {
|
|
abort_unless($object->kind === $data['kind'], 422, 'Crie outro elemento para uma natureza diferente.');
|
|
}
|
|
$object->fill(['business_id' => $businessId, 'kind' => $data['kind'], 'classification' => 'restricted', 'verification_status' => 'pending', 'payload' => $data['payload']]);
|
|
$object->save();
|
|
$business->version_no++;
|
|
$business->save();
|
|
app(ExistingBusinessDrafts::class)->snapshot($business, $actor, $objectId ? 'object_updated' : 'object_added', $data['reason']);
|
|
|
|
return $object;
|
|
});
|
|
}
|
|
}
|