Files
Investidor-V2/app/Http/Controllers/SimulationTaxRuleGovernanceController.php
T

130 lines
6.0 KiB
PHP

<?php
namespace App\Http\Controllers;
use App\Services\SimulationFiscalQaPreview;
use App\Services\SimulationTaxParameterResolver;
use App\Services\SimulationTaxRuleExpression;
use App\Services\SimulationTaxRuleGovernance;
use App\Support\IsolatedQaDatabase;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\ValidationException;
use Inertia\Inertia;
use Inertia\Response;
use InvalidArgumentException;
class SimulationTaxRuleGovernanceController extends Controller
{
public function qaReview(Request $request, string $id, SimulationTaxRuleGovernance $governance): Response
{
abort_unless(IsolatedQaDatabase::allowsSchemaChanges(), 404);
$rule = $governance->show($request->user(), $id);
abort_unless($rule->status === 'draft' && $rule->rule_code === 'IVA-GERAL-BASE-LIQUIDA', 422,
'Seleccione o rascunho do primeiro lote fiscal.');
return Inertia::render('management/fiscal-qa-review', ['rule' => [
'id' => $rule->id, 'code' => $rule->rule_code, 'version' => $rule->rule_version,
]]);
}
public function qaPreview(Request $request, string $id, SimulationFiscalQaPreview $preview): JsonResponse
{
abort_unless(IsolatedQaDatabase::allowsSchemaChanges(), 404);
$key = $request->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<string,mixed> */
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;
}
}