Implement duplicate contract code validation with user confirmation

This commit is contained in:
Luis Medon
2026-10-29 14:37:00 +00:00
parent e488ae3342
commit 54f190b444
3 changed files with 93 additions and 1 deletions

View File

@@ -2,6 +2,7 @@
namespace App\Http\Requests;
use App\Models\Contract;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Validator;
use Carbon\Carbon;
@@ -96,6 +97,31 @@ class ContractRequest extends FormRequest
public function withValidator(Validator $validator)
{
$validator->after(function ($validator) {
if ($this->filled('code') && $this->filled('supply_type')) {
$contractId = $this->route('id');
$existingContract = Contract::query()
->with('client:id,name')
->where('code', $this->input('code'))
->where('supply_type', $this->input('supply_type'))
->when($contractId, fn ($query) => $query->where('id', '!=', $contractId))
->first();
if ($existingContract && ! $this->boolean('confirm_duplicate')) {
$supplyType = strtoupper($this->input('supply_type'));
$clientName = $existingContract->client?->name;
$message = "Já existe um contrato {$supplyType} com este código";
if ($clientName) {
$message .= " associado ao cliente {$clientName}";
}
$validator->errors()->add(
'duplicate_code',
$message . '. Confirme apenas se se trata de uma mudança de titularidade.'
);
}
}
if (! $this->user()?->can('view_contract_summary')) {
return;
}

View File

@@ -635,5 +635,39 @@
applyColor('previous_supplier_select');
});
});
const duplicateCodeMessage = @json($errors->first('duplicate_code'));
if (duplicateCodeMessage) {
const form = document.querySelector('form');
const submitConfirmed = () => {
let confirmation = form.querySelector('input[name="confirm_duplicate"]');
if (!confirmation) {
confirmation = document.createElement('input');
confirmation.type = 'hidden';
confirmation.name = 'confirm_duplicate';
form.appendChild(confirmation);
}
confirmation.value = '1';
form.submit();
};
if (window.Swal) {
Swal.fire({
title: 'CPE/CUI já existente',
text: duplicateCodeMessage,
icon: 'warning',
showCancelButton: true,
confirmButtonText: 'Aceitar e gravar',
cancelButtonText: 'Cancelar',
reverseButtons: true
}).then((result) => {
if (result.isConfirmed) {
submitConfirmed();
}
});
} else if (window.confirm(`${duplicateCodeMessage}\n\nDeseja continuar?`)) {
submitConfirmed();
}
}
</script>
@endsection

View File

@@ -7,6 +7,7 @@ use App\Models\Contract;
use App\Services\ContractService;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\ValidationException;
use Tests\Support\IsolatedDatabaseTestCase;
@@ -15,7 +16,38 @@ class ContractPersistenceTest extends IsolatedDatabaseTestCase
protected function setUp(): void
{
parent::setUp();
Schema::table('contracts', fn (Blueprint $table) => $table->decimal('go_ki')->nullable());
Schema::table('contracts', function (Blueprint $table) {
$table->decimal('go_ki')->nullable();
$table->string('code')->nullable();
$table->string('supply_type')->nullable();
});
}
public function test_duplicate_supply_code_requires_explicit_confirmation(): void
{
$user = $this->authenticate();
Contract::create([
'client_id' => 1,
'code' => 'CPE-123',
'supply_type' => 'cpe',
]);
$request = ContractRequest::create('/contract', 'POST', [
'code' => 'CPE-123',
'supply_type' => 'cpe',
]);
$request->setUserResolver(fn () => $user);
$validator = Validator::make($request->all(), []);
$request->withValidator($validator);
$this->assertFalse($validator->passes());
$this->assertArrayHasKey('duplicate_code', $validator->errors()->messages());
$request->merge(['confirm_duplicate' => '1']);
$confirmedValidator = Validator::make($request->all(), []);
$request->withValidator($confirmedValidator);
$this->assertTrue($confirmedValidator->passes());
}
public function test_update_persists_chargeback_and_deducts_it_from_profit(): void