feat: actualizar método de cancelación de constancias para incluir validaciones y soporte de sustitución
This commit is contained in:
parent
908ba8aaf1
commit
44ef2f9306
@ -22,13 +22,21 @@ class CancellationController extends Controller
|
|||||||
/**
|
/**
|
||||||
* Cancelar la constancia/tag
|
* Cancelar la constancia/tag
|
||||||
*/
|
*/
|
||||||
public function cancelarConstancia(CancelConstanciaRequest $request)
|
public function cancelarConstancia(CancelConstanciaRequest $request, $recordId)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
DB::beginTransaction();
|
DB::beginTransaction();
|
||||||
|
|
||||||
// Buscar el expediente con sus relaciones
|
// Buscar el expediente con sus relaciones
|
||||||
$record = Record::with('vehicle.tag.status')->findOrFail($request->record_id);
|
$record = Record::with('vehicle.tag.status')->find($recordId);
|
||||||
|
|
||||||
|
if (!$record) {
|
||||||
|
return ApiResponse::NOT_FOUND->response([
|
||||||
|
'message' => 'El expediente no existe.',
|
||||||
|
'record_id' => $recordId,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
$vehicle = $record->vehicle;
|
$vehicle = $record->vehicle;
|
||||||
$tag = $vehicle->tag;
|
$tag = $vehicle->tag;
|
||||||
|
|
||||||
@ -39,18 +47,41 @@ public function cancelarConstancia(CancelConstanciaRequest $request)
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validar que el tag está en estado activo
|
// Validar que el tag está en estado activo O cancelado (para permitir sustitución posterior)
|
||||||
if (!$tag->isAssigned()) {
|
if (!$tag->isAssigned() && !$tag->isCancelled()) {
|
||||||
return ApiResponse::BAD_REQUEST->response([
|
return ApiResponse::BAD_REQUEST->response([
|
||||||
'message' => 'El tag ya no está activo. Status actual: ' . $tag->status->name
|
'message' => 'El tag debe estar asignado o cancelado. Status actual: ' . $tag->status->name
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Validar que se proporcionen los datos de sustitución
|
||||||
|
if (!$request->filled('new_folio') || !$request->filled('new_tag_number')) {
|
||||||
|
return ApiResponse::BAD_REQUEST->response([
|
||||||
|
'message' => 'Para cancelar la constancia, debe proporcionar: nuevo folio y numero de constancia.',
|
||||||
|
'provided' => [
|
||||||
|
'new_folio' => $request->filled('new_folio'),
|
||||||
|
'new_tag_number' => $request->filled('new_tag_number'),
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validar que el tag_number tenga exactamente 17 caracteres
|
||||||
|
if (strlen($request->new_tag_number) !== 32) {
|
||||||
|
return ApiResponse::BAD_REQUEST->response([
|
||||||
|
'message' => 'El tag_number debe tener exactamente 32 caracteres',
|
||||||
|
'provided_tag_number' => $request->new_tag_number,
|
||||||
|
'length' => strlen($request->new_tag_number),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$isSubstitution = true;
|
||||||
|
|
||||||
// Guardar información del tag anterior ANTES de cancelarlo
|
// Guardar información del tag anterior ANTES de cancelarlo
|
||||||
$oldTagNumber = $tag->tag_number;
|
$oldTagNumber = $tag->tag_number;
|
||||||
$oldFolio = $tag->folio;
|
$oldFolio = $tag->folio;
|
||||||
|
|
||||||
// Crear registro en el log de vehiculos
|
// Crear registro en el log de vehículos
|
||||||
|
if ($tag->isAssigned()) {
|
||||||
$cancellationLog = VehicleTagLog::create([
|
$cancellationLog = VehicleTagLog::create([
|
||||||
'vehicle_id' => $vehicle->id,
|
'vehicle_id' => $vehicle->id,
|
||||||
'tag_id' => $tag->id,
|
'tag_id' => $tag->id,
|
||||||
@ -62,21 +93,29 @@ public function cancelarConstancia(CancelConstanciaRequest $request)
|
|||||||
'performed_by' => Auth::id(),
|
'performed_by' => Auth::id(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Actualizar estado del tag a 'cancelled' y desasignar vehículo
|
// Actualizar estado del tag a 'cancelled'
|
||||||
$tag->markAsCancelled();
|
$tag->markAsCancelled();
|
||||||
|
} else {
|
||||||
|
// Si ya estaba cancelado, buscar el último log de cancelación
|
||||||
|
$cancellationLog = VehicleTagLog::where('vehicle_id', $vehicle->id)
|
||||||
|
->where('tag_id', $tag->id)
|
||||||
|
->where('action_type', 'cancelacion')
|
||||||
|
->latest()
|
||||||
|
->first();
|
||||||
|
}
|
||||||
|
|
||||||
$newTag = null;
|
$newTag = null;
|
||||||
$substitutionLog = null;
|
$substitutionLog = null;
|
||||||
$isSubstitution = $request->filled('new_folio') && $request->filled('new_tag_number');
|
|
||||||
|
|
||||||
if ($isSubstitution) {
|
if ($isSubstitution) {
|
||||||
|
// Buscar el nuevo tag por folio
|
||||||
$newTag = Tag::where('folio', $request->new_folio)->first();
|
$newTag = Tag::where('folio', $request->new_folio)->first();
|
||||||
|
|
||||||
if (!$newTag) {
|
if (!$newTag) {
|
||||||
DB::rollBack();
|
DB::rollBack();
|
||||||
return ApiResponse::NOT_FOUND->response([
|
return ApiResponse::NOT_FOUND->response([
|
||||||
'message' => 'El nuevo tag proporcionado no existe.',
|
'message' => 'El tag con el folio proporcionado no existe.',
|
||||||
'new_tag_number' => $request->new_tag_number,
|
'new_folio' => $request->new_folio,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,17 +123,22 @@ public function cancelarConstancia(CancelConstanciaRequest $request)
|
|||||||
DB::rollBack();
|
DB::rollBack();
|
||||||
return ApiResponse::BAD_REQUEST->response([
|
return ApiResponse::BAD_REQUEST->response([
|
||||||
'message' => 'El nuevo tag no está disponible para asignación',
|
'message' => 'El nuevo tag no está disponible para asignación',
|
||||||
'new_tag_number' => $request->new_tag_number,
|
'new_folio' => $request->new_folio,
|
||||||
'current_status' => $newTag->status->name,
|
'current_status' => $newTag->status->name,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Asignar tag_number al nuevo tag si no lo tiene
|
||||||
if (!$newTag->tag_number) {
|
if (!$newTag->tag_number) {
|
||||||
$existingTag = Tag::where('tag_number', $request->new_tag_number)->first();
|
// Validar que el tag_number no esté usado por otro tag
|
||||||
if ($existingTag && $existingTag->id !== $newTag->id) {
|
$existingTag = Tag::where('tag_number', $request->new_tag_number)
|
||||||
|
->where('id', '!=', $newTag->id)
|
||||||
|
->first();
|
||||||
|
|
||||||
|
if ($existingTag) {
|
||||||
DB::rollBack();
|
DB::rollBack();
|
||||||
return ApiResponse::BAD_REQUEST->response([
|
return ApiResponse::BAD_REQUEST->response([
|
||||||
'message' => 'El nuevo tag_number ya está asignado a otro folio.',
|
'message' => 'El tag_number ya está asignado a otro tag.',
|
||||||
'new_tag_number' => $request->new_tag_number,
|
'new_tag_number' => $request->new_tag_number,
|
||||||
'folio_existente' => $existingTag->folio,
|
'folio_existente' => $existingTag->folio,
|
||||||
]);
|
]);
|
||||||
@ -105,15 +149,19 @@ public function cancelarConstancia(CancelConstanciaRequest $request)
|
|||||||
} elseif ($newTag->tag_number !== $request->new_tag_number) {
|
} elseif ($newTag->tag_number !== $request->new_tag_number) {
|
||||||
DB::rollBack();
|
DB::rollBack();
|
||||||
return ApiResponse::BAD_REQUEST->response([
|
return ApiResponse::BAD_REQUEST->response([
|
||||||
'message' => 'El nuevo tag ya tiene un tag_number diferente asignado.',
|
'message' => 'El tag ya tiene un tag_number diferente asignado.',
|
||||||
'assigned_tag_number' => $newTag->tag_number,
|
'assigned_tag_number' => $newTag->tag_number,
|
||||||
'provided_tag_number' => $request->new_tag_number,
|
'provided_tag_number' => $request->new_tag_number,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Usar el folio del request
|
// Desasignar el tag viejo para evitar conflicto de unique constraint
|
||||||
$newTag->markAsAssigned($vehicle->id, $request->folio);
|
$tag->update(['vehicle_id' => null]);
|
||||||
|
|
||||||
|
// Asignar el nuevo tag al vehículo (usa el folio del tag encontrado)
|
||||||
|
$newTag->markAsAssigned($vehicle->id, $newTag->folio);
|
||||||
|
|
||||||
|
// Crear log de sustitución
|
||||||
$substitutionLog = VehicleTagLog::create([
|
$substitutionLog = VehicleTagLog::create([
|
||||||
'vehicle_id' => $vehicle->id,
|
'vehicle_id' => $vehicle->id,
|
||||||
'tag_id' => $newTag->id,
|
'tag_id' => $newTag->id,
|
||||||
@ -123,7 +171,8 @@ public function cancelarConstancia(CancelConstanciaRequest $request)
|
|||||||
'performed_by' => Auth::id(),
|
'performed_by' => Auth::id(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$record->update(['folio' => $request->folio]);
|
// Actualizar el folio del expediente con el folio del nuevo tag
|
||||||
|
$record->update(['folio' => $newTag->folio]);
|
||||||
}
|
}
|
||||||
|
|
||||||
DB::commit();
|
DB::commit();
|
||||||
@ -132,9 +181,22 @@ public function cancelarConstancia(CancelConstanciaRequest $request)
|
|||||||
? 'Tag cancelado y sustituido exitosamente'
|
? 'Tag cancelado y sustituido exitosamente'
|
||||||
: 'Constancia cancelada exitosamente';
|
: 'Constancia cancelada exitosamente';
|
||||||
|
|
||||||
|
// Agregar alerta si NO hay sustitución
|
||||||
|
$alert = null;
|
||||||
|
if (!$isSubstitution) {
|
||||||
|
$alert = [
|
||||||
|
'type' => 'warning',
|
||||||
|
'message' => 'El tag ha sido cancelado y necesita sustitución',
|
||||||
|
'requires_action' => true,
|
||||||
|
'cancellation_date' => $cancellationLog->cancellation_at->format('d/m/Y H:i:s'),
|
||||||
|
'cancellation_reason' => $cancellationLog->cancellationReason->name,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
return ApiResponse::OK->response([
|
return ApiResponse::OK->response([
|
||||||
'message' => $message,
|
'message' => $message,
|
||||||
'is_substitution' => $isSubstitution,
|
'is_substitution' => $isSubstitution,
|
||||||
|
'alert' => $alert,
|
||||||
'cancellation' => [
|
'cancellation' => [
|
||||||
'id' => $cancellationLog->id,
|
'id' => $cancellationLog->id,
|
||||||
'vehicle' => [
|
'vehicle' => [
|
||||||
@ -144,8 +206,8 @@ public function cancelarConstancia(CancelConstanciaRequest $request)
|
|||||||
],
|
],
|
||||||
'old_tag' => [
|
'old_tag' => [
|
||||||
'id' => $tag->id,
|
'id' => $tag->id,
|
||||||
'folio' => $tag->folio,
|
'folio' => $oldFolio,
|
||||||
'tag_number' => $tag->tag_number,
|
'tag_number' => $oldTagNumber,
|
||||||
'new_status' => 'Cancelado',
|
'new_status' => 'Cancelado',
|
||||||
],
|
],
|
||||||
'new_tag' => $newTag ? [
|
'new_tag' => $newTag ? [
|
||||||
@ -154,7 +216,7 @@ public function cancelarConstancia(CancelConstanciaRequest $request)
|
|||||||
'tag_number' => $newTag->tag_number,
|
'tag_number' => $newTag->tag_number,
|
||||||
'status' => $newTag->status->name,
|
'status' => $newTag->status->name,
|
||||||
] : null,
|
] : null,
|
||||||
'cancellation_reason_id' => $cancellationLog->cancellationReason->name,
|
'cancellation_reason' => $cancellationLog->cancellationReason->name,
|
||||||
'cancellation_observations' => $request->cancellation_observations,
|
'cancellation_observations' => $request->cancellation_observations,
|
||||||
'cancelled_at' => $cancellationLog->cancellation_at->toDateTimeString(),
|
'cancelled_at' => $cancellationLog->cancellation_at->toDateTimeString(),
|
||||||
'cancelled_by' => Auth::user()->name,
|
'cancelled_by' => Auth::user()->name,
|
||||||
@ -164,7 +226,7 @@ public function cancelarConstancia(CancelConstanciaRequest $request)
|
|||||||
DB::rollBack();
|
DB::rollBack();
|
||||||
|
|
||||||
Log::error('Error en cancelarConstancia: ' . $e->getMessage(), [
|
Log::error('Error en cancelarConstancia: ' . $e->getMessage(), [
|
||||||
'record_id' => $request->record_id ?? null,
|
'record_id' => $recordId ?? null,
|
||||||
'cancellation_reason' => $request->cancellation_reason ?? null,
|
'cancellation_reason' => $request->cancellation_reason ?? null,
|
||||||
'trace' => $e->getTraceAsString()
|
'trace' => $e->getTraceAsString()
|
||||||
]);
|
]);
|
||||||
|
|||||||
@ -20,8 +20,7 @@ public function authorize(): bool
|
|||||||
public function rules(): array
|
public function rules(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'record_id' => 'nullable|exists:records,id',
|
'new_folio' => 'required|string',
|
||||||
'folio' => 'required|string',
|
|
||||||
'cancellation_reason_id' => 'required|exists:catalog_cancellation_reasons,id',
|
'cancellation_reason_id' => 'required|exists:catalog_cancellation_reasons,id',
|
||||||
'cancellation_observations' => 'nullable|string',
|
'cancellation_observations' => 'nullable|string',
|
||||||
'new_tag_number' => 'nullable|exists:tags,tag_number',
|
'new_tag_number' => 'nullable|exists:tags,tag_number',
|
||||||
@ -34,8 +33,6 @@ public function rules(): array
|
|||||||
public function messages(): array
|
public function messages(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'record_id.required' => 'El id del expediente es obligatorio.',
|
|
||||||
'record_id.integer' => 'El id del expediente debe ser un número entero.',
|
|
||||||
'record_id.exists' => 'El expediente especificado no existe.',
|
'record_id.exists' => 'El expediente especificado no existe.',
|
||||||
|
|
||||||
'cancellation_reason_id.required' => 'El motivo de cancelación es obligatorio.',
|
'cancellation_reason_id.required' => 'El motivo de cancelación es obligatorio.',
|
||||||
|
|||||||
@ -55,7 +55,7 @@
|
|||||||
|
|
||||||
// Rutas de cancelación de constancias
|
// Rutas de cancelación de constancias
|
||||||
Route::resource('/razones-cancelacion', CatalogController::class);
|
Route::resource('/razones-cancelacion', CatalogController::class);
|
||||||
Route::delete('cancelacion', [CancellationController::class, 'cancelarConstancia']);
|
Route::post('{recordId}/cancelacion', [CancellationController::class, 'cancelarConstancia']);
|
||||||
Route::post('tags/cancelar', [CancellationController::class, 'cancelarTagNoAsignado']);
|
Route::post('tags/cancelar', [CancellationController::class, 'cancelarTagNoAsignado']);
|
||||||
Route::get('excel/constancias-sustituidas', [ExcelController::class, 'constanciasSustituidas']);
|
Route::get('excel/constancias-sustituidas', [ExcelController::class, 'constanciasSustituidas']);
|
||||||
Route::get('excel/constancias-canceladas', [ExcelController::class, 'constanciasCanceladas']);
|
Route::get('excel/constancias-canceladas', [ExcelController::class, 'constanciasCanceladas']);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user