header('Idempotency-Key'); abort_unless(is_string($key) && strlen($key) >= 16 && strlen($key) <= 128, 428, 'Idempotency-Key é obrigatório.'); $input = $request->validate([ 'base' => ['required', 'string', 'max:40', 'regex:/^(?:0|[1-9][0-9]*)(?:\.[0-9]+)?$/D'], 'reference_date' => ['required', 'date_format:Y-m-d'], 'currency' => ['required', 'in:MZN'], 'operation' => ['required', 'in:internal_general_net'], ]); $result = $preview->create($request->user(), $id, $input, $key); $simulation = $result['simulation']; return response()->json(['data' => $simulation, 'replayed' => $result['replayed']], $result['replayed'] ? 200 : 202) ->header('Location', url('/api/v1/simulations/'.$simulation->id)); } public function index(Request $request, SimulationTaxRuleGovernance $governance): JsonResponse { $filters = $request->validate([ 'rule_code' => ['nullable', 'string', 'max:64'], 'component' => ['nullable', 'in:IRPC,IVA,ISPC,IRPS,INSS,RETENCOES,DIREITOS_ADUANEIROS,ICE'], 'scope_key' => ['nullable', 'string', 'max:160'], 'status' => ['nullable', 'in:draft,submitted,reviewed,rejected,approved,published,suspended,archived'], 'per_page' => ['nullable', 'integer', 'between:1,100'], ]); return response()->json($governance->listing($request->user(), $filters)); } public function store(Request $request, SimulationTaxRuleGovernance $governance): JsonResponse { $rule = $governance->create($request->user(), $this->validatedRule($request)); return response()->json($rule, 201)->header('Location', url('/api/v2/investment/admin/tax-rules/'.$rule->id)); } public function show(Request $request, SimulationTaxRuleGovernance $governance, string $id): JsonResponse { return response()->json($governance->show($request->user(), $id)); } public function update(Request $request, SimulationTaxRuleGovernance $governance, string $id): JsonResponse { $data = $request->validate(['version_no' => ['required', 'integer', 'min:1']]); return response()->json($governance->update($request->user(), $id, (int) $data['version_no'], $this->validatedRule($request))); } public function transition(Request $request, SimulationTaxRuleGovernance $governance, string $id, string $action): JsonResponse { $data = $request->validate([ 'version_no' => ['required', 'integer', 'min:1'], 'evidence' => ['required', 'string', 'min:20', 'max:2000'], ]); return response()->json($governance->transition($request->user(), $id, (int) $data['version_no'], $action, $data['evidence'])); } /** @return array */ private function validatedRule(Request $request): array { $data = $request->validate([ 'rule_code' => ['required', 'string', 'regex:/^[A-Z0-9][A-Z0-9._-]{2,63}$/'], 'rule_version' => ['required', 'integer', 'min:1'], 'component' => ['required', 'in:IRPC,IVA,ISPC,IRPS,INSS,RETENCOES,DIREITOS_ADUANEIROS,ICE'], 'scope_key' => ['required', 'string', 'min:2', 'max:160'], 'valid_from' => ['required', 'date_format:Y-m-d'], 'valid_until' => ['nullable', 'date_format:Y-m-d', 'after_or_equal:valid_from'], 'legal_source_id' => ['required', 'uuid', 'exists:investment_legal_sources,id'], 'source_sha256' => ['required', 'regex:/^[a-f0-9]{64}$/'], 'rule_definition' => ['required', 'array'], 'parameters' => ['required', 'array'], 'rounding_policy' => ['required', 'array'], ]); foreach (['rule_definition', 'parameters', 'rounding_policy'] as $key) { $json = json_encode($data[$key], JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE); Validator::make(['json' => $json], ['json' => ['max:50000']])->validate(); } if (($data['rule_definition']['language'] ?? null) === 'investmoz.tax.v1') { try { app(SimulationTaxRuleExpression::class)->validate($data['rule_definition']); } catch (InvalidArgumentException $exception) { throw ValidationException::withMessages(['rule_definition' => $exception->getMessage()]); } try { app(SimulationTaxParameterResolver::class)->validateParameters($data['parameters']); } catch (InvalidArgumentException $exception) { throw ValidationException::withMessages(['parameters' => $exception->getMessage()]); } } return $data; } }