| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161 |
- <?php
- namespace App\Rules;
- use App\Models\ClassPackageUnit;
- use App\Models\ClassPackageUnitVariation;
- use Closure;
- // confere se os valores e parcelas do contrato sao compativeis com a
- // proposta (variation) escolhida do pacote da unidade.
- // usada no studentcontractrequest e no booted do studentcontract, para que
- // nenhum fluxo grave um contrato incongruente com a proposta.
- class StudentContractVariationConsistency
- {
- // vinculo entre os campos do contrato e as colunas da proposta
- private const ITEMS = [
- [
- 'value' => 'tax_register',
- 'installments' => 'installments',
- 'proposal_value' => 'register_value',
- 'proposal_min' => 'register_installments_min',
- 'proposal_max' => 'register_installments_max',
- ],
- [
- 'value' => 'package_value',
- 'installments' => 'package_installments',
- 'proposal_value' => 'package_value',
- 'proposal_min' => 'package_installments_min',
- 'proposal_max' => 'package_installments_max',
- ],
- [
- 'value' => 'material_value',
- 'installments' => 'material_installments',
- 'proposal_value' => 'material_value',
- 'proposal_min' => 'material_installments_min',
- 'proposal_max' => 'material_installments_max',
- ],
- ];
- public function __construct(
- private readonly ?Closure $packageUnitResolver = null,
- ) {}
- // retorna [campo => [mensagens]]; vazio quando esta tudo consistente.
- public function errors(array $data): array
- {
- if (empty($data['class_package_unit_id'])) {
- return [];
- }
- $packageUnit = $this->packageUnitResolver
- ? ($this->packageUnitResolver)((int) $data['class_package_unit_id'])
- : ClassPackageUnit::with('variations')->find($data['class_package_unit_id']);
- if (! $packageUnit) {
- return [];
- }
- // proposta fixa selecionada: valores e parcelas vem dela
- if (! empty($data['class_package_unit_variation_id'])) {
- $proposal = $packageUnit->variations->firstWhere('id', (int) $data['class_package_unit_variation_id']);
- if (! $proposal) {
- return ['class_package_unit_variation_id' => [__('validation.student_contract_variation_unavailable')]];
- }
- return $this->fixedProposalErrors($data, $proposal);
- }
- // sem proposta o contrato e custom: limites entre irrecusavel e pavao
- return $this->customProposalErrors(
- $data,
- $packageUnit->variations->firstWhere('type', ClassPackageUnitVariation::TYPE_PAVAO),
- $packageUnit->variations->firstWhere('type', ClassPackageUnitVariation::TYPE_IRRECUSAVEL),
- );
- }
- //
- private function fixedProposalErrors(array $data, ClassPackageUnitVariation $proposal): array
- {
- $errors = [];
- // qualquer valor diferente da proposta caracteriza custom
- foreach (self::ITEMS as $item) {
- if (round((float) ($data[$item['value']] ?? 0), 2) !== round((float) $proposal->{$item['proposal_value']}, 2)) {
- $errors[$item['value']][] = __('validation.student_contract_variation_value_mismatch');
- }
- $this->addInstallmentsError($errors, $item, $data, $proposal->{$item['proposal_min']}, $proposal->{$item['proposal_max']});
- }
- return $errors;
- }
- private function customProposalErrors(
- array $data,
- ?ClassPackageUnitVariation $pavao,
- ?ClassPackageUnitVariation $irrecusavel,
- ): array {
- // sem as duas propostas configuradas nao existem limites para conferir
- if (! $pavao || ! $irrecusavel) {
- return [];
- }
- $errors = [];
- // o montante final fica entre o total da irrecusavel e o total da pavao
- $total = round(
- (float) ($data['tax_register'] ?? 0)
- + (float) ($data['package_value'] ?? 0)
- + (float) ($data['material_value'] ?? 0),
- 2,
- );
- $min = $irrecusavel->totalValue();
- $max = $pavao->totalValue();
- if ($total < $min || $total > $max) {
- $errors['package_value'][] = __('validation.student_contract_custom_total_range', [
- 'min' => number_format($min, 2, ',', '.'),
- 'max' => number_format($max, 2, ',', '.'),
- ]);
- }
- // as parcelas ficam entre o minimo da irrecusavel e o maximo da pavao
- foreach (self::ITEMS as $item) {
- $this->addInstallmentsError($errors, $item, $data, $irrecusavel->{$item['proposal_min']}, $pavao->{$item['proposal_max']});
- }
- return $errors;
- }
- //
- private function addInstallmentsError(array &$errors, array $item, array $data, int $min, int $max): void
- {
- $installments = $data[$item['installments']] ?? null;
- if ($installments === null) {
- return;
- }
- if ((int) $installments < $min || (int) $installments > $max) {
- $errors[$item['installments']][] = __('validation.student_contract_installments_range', [
- 'min' => $min,
- 'max' => $max,
- ]);
- }
- }
- }
|