107 lines
6.5 KiB
PHP
107 lines
6.5 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Models\ExistingBusiness;
|
|
use App\Models\ExistingBusinessObject;
|
|
use App\Models\User;
|
|
use App\Services\Mne\BusinessRepository;
|
|
use Illuminate\Support\Facades\Crypt;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Gate;
|
|
use Illuminate\Support\Facades\Validator;
|
|
use Illuminate\Support\Str;
|
|
use Illuminate\Validation\Rule;
|
|
|
|
final class ExistingBusinessDrafts
|
|
{
|
|
public const MODALITIES = ['company_sale', 'company_purchase', 'participation_sale', 'capital_increase', 'financial_investor', 'strategic_partner', 'buyer_search', 'position_assignment', 'franchise', 'asset_sale', 'asset_lease', 'business_unit_transfer', 'joint_venture', 'succession', 'recovery', 'expansion', 'internationalization', 'real_estate', 'agricultural_investment', 'land_right', 'mining_license', 'forestry_license', 'investment_project', 'business_partnership', 'financing_request', 'concession_opportunity', 'supply_opportunity'];
|
|
|
|
/** @param array<string,mixed> $input */
|
|
public function save(User $actor, array $input, ?string $id = null): ExistingBusiness
|
|
{
|
|
$data = Validator::make($input, [
|
|
'modality' => ['required', 'in:'.implode(',', self::MODALITIES)],
|
|
'sector_id' => ['sometimes', 'nullable', 'integer', Rule::exists('sectors', 'id')->whereNull('deleted_at')->where('is_active', true)],
|
|
'public_title' => ['sometimes', 'nullable', 'string', 'max:180'],
|
|
'activity_code' => ['sometimes', 'nullable', 'string', 'max:60'],
|
|
'stage' => ['sometimes', 'nullable', 'string', 'max:40'],
|
|
'objective' => ['sometimes', 'nullable', 'string', 'max:5000'],
|
|
'currency' => ['sometimes', 'nullable', 'regex:/^[A-Z]{3}$/', 'required_with:amount_min,amount_max'],
|
|
'amount_min' => ['sometimes', 'nullable', 'numeric', 'min:0', 'max:999999999999999999.99'],
|
|
'amount_max' => ['sometimes', 'nullable', 'numeric', 'min:0', 'gte:amount_min', 'max:999999999999999999.99'],
|
|
'available_percentage' => ['sometimes', 'nullable', 'numeric', 'between:0,100'],
|
|
'funds_use' => ['sometimes', 'nullable', 'string', 'max:10000'],
|
|
'classification' => ['required', 'in:internal,confidential,restricted'],
|
|
'version_no' => [$id ? 'required' : 'prohibited', 'integer', 'min:1'],
|
|
'reason' => ['required', 'string', 'min:10', 'max:1000'],
|
|
'payload' => ['required', 'array:'.implode(',', [...array_keys(BusinessFormSchema::fields()), 'wizard_version', 'wizard_step'])],
|
|
'payload.title' => ['required', 'string', 'max:200'],
|
|
'payload.description' => ['nullable', 'string', 'max:10000'],
|
|
'payload.declared_reason' => ['nullable', 'string', 'max:2000'],
|
|
'payload.source_reference' => ['nullable', 'string', 'max:2000'],
|
|
'payload.valid_until' => ['nullable', 'date_format:Y-m-d'],
|
|
...BusinessFormSchema::rules(is_array($input['payload'] ?? null) ? $input['payload'] : []),
|
|
])->validate();
|
|
|
|
return DB::transaction(function () use ($actor, $id, $data) {
|
|
if ($id) {
|
|
$business = app(BusinessRepository::class)->find($id, true);
|
|
Gate::forUser($actor)->authorize('update', $business);
|
|
abort_unless($business->version_no === $data['version_no'], 409, 'O rascunho foi alterado. Recarregue antes de gravar.');
|
|
$business->version_no++;
|
|
} else {
|
|
Gate::forUser($actor)->authorize('create', ExistingBusiness::class);
|
|
if (! $actor->exists || $actor->id < 1) {
|
|
abort(403, 'A conta deve estar registada.');
|
|
}
|
|
$business = new ExistingBusiness;
|
|
$business->code = 'MNE-'.Str::uuid();
|
|
$business->owner_user_id = $actor->id;
|
|
$business->version_no = 1;
|
|
$business->status = 'draft';
|
|
}
|
|
$business->fill(['modality' => $data['modality'], 'classification' => $data['classification'], 'payload' => $data['payload']]);
|
|
foreach (['public_title', 'activity_code', 'stage', 'objective', 'currency', 'amount_min', 'amount_max', 'available_percentage', 'funds_use'] as $field) {
|
|
if (array_key_exists($field, $data)) {
|
|
$business->{$field} = $data[$field];
|
|
}
|
|
}
|
|
if (array_key_exists('sector_id', $data)) {
|
|
$business->sector_id = $data['sector_id'];
|
|
}
|
|
$business->save();
|
|
$this->snapshot($business, $actor, $id ? 'updated' : 'created', $data['reason']);
|
|
|
|
return $business;
|
|
});
|
|
}
|
|
|
|
public function archive(User $actor, string $id, int $version, string $reason): void
|
|
{
|
|
Validator::make(['reason' => $reason], ['reason' => ['required', 'string', 'min:10', 'max:1000']])->validate();
|
|
DB::transaction(function () use ($actor, $id, $version, $reason) {
|
|
$business = app(BusinessRepository::class)->find($id, true);
|
|
Gate::forUser($actor)->authorize('delete', $business);
|
|
abort_unless($business->version_no === $version, 409);
|
|
$business->version_no++;
|
|
$business->save();
|
|
$business->delete();
|
|
$this->snapshot($business, $actor, 'archived', $reason);
|
|
});
|
|
}
|
|
|
|
/** @param array<string,mixed> $context */
|
|
public function snapshot(ExistingBusiness $business, User $actor, string $action, string $reason, array $context = []): void
|
|
{
|
|
$snapshot = json_encode(['context' => $context, 'record' => $business->attributesToArray(), 'payload' => $business->payload,
|
|
'locations' => DB::table('existing_business_locations')->where('existing_business_id', $business->id)->orderBy('id')->select('*')->selectRaw('ST_AsEWKT(geom) AS geometry_snapshot')->get()->map(fn ($row) => (array) $row)->all(),
|
|
'objects' => ExistingBusinessObject::where('business_id', $business->id)->orderBy('id')->get()
|
|
->map(fn ($object) => [...$object->attributesToArray(), 'payload' => $object->payload])->all(),
|
|
], JSON_THROW_ON_ERROR);
|
|
DB::table('existing_business_revisions')->insert(['id' => (string) Str::uuid(), 'business_id' => $business->id,
|
|
'version_no' => $business->version_no, 'actor_id' => $actor->id, 'action' => $action,
|
|
'reason' => Crypt::encryptString($reason), 'snapshot' => Crypt::encryptString($snapshot), 'sha256' => hash('sha256', $snapshot)]);
|
|
}
|
|
}
|