$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 $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)]); } }