repuve-backend-v1/app/Http/Controllers/Repuve/CancellationController.php

316 lines
13 KiB
PHP

<?php
namespace App\Http\Controllers\Repuve;
use App\Http\Controllers\Controller;
use App\Http\Requests\Repuve\CancelConstanciaRequest;
use App\Models\CatalogCancellationReason;
use App\Models\Record;
use App\Models\Tag;
use App\Models\TagCancellationLog;
use App\Models\VehicleTagLog;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Notsoweb\ApiResponse\Enums\ApiResponse;
use Barryvdh\DomPDF\Facade\Pdf;
class CancellationController extends Controller
{
/**
* Cancelar la constancia/tag
*/
public function cancelarConstancia(CancelConstanciaRequest $request)
{
try {
DB::beginTransaction();
// Buscar el expediente con sus relaciones
$record = Record::with('vehicle.tag.status')->findOrFail($request->record_id);
$vehicle = $record->vehicle;
$tag = $vehicle->tag;
// Validar que el vehículo tiene un tag asignado
if (!$tag) {
return ApiResponse::BAD_REQUEST->response([
'message' => 'El vehículo no tiene un tag/constancia asignada.'
]);
}
// Validar que el tag está en estado activo
if (!$tag->isAssigned()) {
return ApiResponse::BAD_REQUEST->response([
'message' => 'El tag ya no está activo. Status actual: ' . $tag->status->name
]);
}
// Guardar información del tag anterior ANTES de cancelarlo
$oldTagNumber = $tag->tag_number;
$oldFolio = $tag->folio;
// Crear registro en el log de vehiculos
$cancellationLog = VehicleTagLog::create([
'vehicle_id' => $vehicle->id,
'tag_id' => $tag->id,
'action_type' => 'cancelacion',
'cancellation_reason_id' => $request->cancellation_reason_id,
'cancellation_observations' => $request->cancellation_observations,
'cancellation_at' => now(),
'cancelled_by' => Auth::id(),
'performed_by' => Auth::id(),
]);
// Actualizar estado del tag a 'cancelled' y desasignar vehículo
$tag->markAsCancelled();
$newTag = null;
$substitutionLog = null;
$isSubstitution = $request->filled('new_folio') && $request->filled('new_tag_number');
if ($isSubstitution) {
$newTag = Tag::where('folio', $request->new_folio)->first();
if (!$newTag) {
DB::rollBack();
return ApiResponse::NOT_FOUND->response([
'message' => 'El nuevo tag proporcionado no existe.',
'new_tag_number' => $request->new_tag_number,
]);
}
if (!$newTag->isAvailable()) {
DB::rollBack();
return ApiResponse::BAD_REQUEST->response([
'message' => 'El nuevo tag no está disponible para asignación',
'new_tag_number' => $request->new_tag_number,
'current_status' => $newTag->status->name,
]);
}
if (!$newTag->tag_number) {
$existingTag = Tag::where('tag_number', $request->new_tag_number)->first();
if ($existingTag && $existingTag->id !== $newTag->id) {
DB::rollBack();
return ApiResponse::BAD_REQUEST->response([
'message' => 'El nuevo tag_number ya está asignado a otro folio.',
'new_tag_number' => $request->new_tag_number,
'folio_existente' => $existingTag->folio,
]);
}
$newTag->tag_number = $request->new_tag_number;
$newTag->save();
} elseif ($newTag->tag_number !== $request->new_tag_number) {
DB::rollBack();
return ApiResponse::BAD_REQUEST->response([
'message' => 'El nuevo tag ya tiene un tag_number diferente asignado.',
'assigned_tag_number' => $newTag->tag_number,
'provided_tag_number' => $request->new_tag_number,
]);
}
// Usar el folio del request
$newTag->markAsAssigned($vehicle->id, $request->folio);
$substitutionLog = VehicleTagLog::create([
'vehicle_id' => $vehicle->id,
'tag_id' => $newTag->id,
'action_type' => 'sustitucion',
'cancellation_reason_id' => $request->cancellation_reason_id,
'cancellation_observations' => 'Tag sustituido. Tag anterior: ' . $oldTagNumber . ' (Folio: ' . $oldFolio . '). Motivo: ' . ($request->cancellation_observations ?? ''),
'performed_by' => Auth::id(),
]);
$record->update(['folio' => $request->folio]);
}
DB::commit();
$message = $isSubstitution
? 'Tag cancelado y sustituido exitosamente'
: 'Constancia cancelada exitosamente';
return ApiResponse::OK->response([
'message' => $message,
'is_substitution' => $isSubstitution,
'cancellation' => [
'id' => $cancellationLog->id,
'vehicle' => [
'id' => $vehicle->id,
'placa' => $vehicle->placa,
'niv' => $vehicle->niv,
],
'old_tag' => [
'id' => $tag->id,
'folio' => $tag->folio,
'tag_number' => $tag->tag_number,
'new_status' => 'Cancelado',
],
'new_tag' => $newTag ? [
'id' => $newTag->id,
'folio' => $newTag->folio,
'tag_number' => $newTag->tag_number,
'status' => $newTag->status->name,
] : null,
'cancellation_reason_id' => $cancellationLog->cancellationReason->name,
'cancellation_observations' => $request->cancellation_observations,
'cancelled_at' => $cancellationLog->cancellation_at->toDateTimeString(),
'cancelled_by' => Auth::user()->name,
]
]);
} catch (\Exception $e) {
DB::rollBack();
Log::error('Error en cancelarConstancia: ' . $e->getMessage(), [
'record_id' => $request->record_id ?? null,
'cancellation_reason' => $request->cancellation_reason ?? null,
'trace' => $e->getTraceAsString()
]);
return ApiResponse::BAD_REQUEST->response([
'message' => 'Error al cancelar la constancia',
'error' => $e->getMessage()
]);
}
}
public function cancelarTagNoAsignado(Request $request)
{
try {
$request->validate([
'folio' => 'required|string|exists:tags,folio',
'cancellation_reason_id' => 'required|exists:catalog_cancellation_reasons,id',
'cancellation_observations' => 'nullable|string',
'id_chip' => 'nullable|string|max:255',
'module_id' => 'nullable|exists:modules,id',
]);
DB::beginTransaction();
$tag = Tag::where('folio', $request->folio)->first();
if (!$tag) {
DB::rollBack();
return ApiResponse::NOT_FOUND->response([
'message' => 'No se encontró el tag con el folio proporcionado.',
'folio' => $request->folio,
]);
}
// Validar que el tag NO esté asignado
if ($tag->isAssigned()) {
return ApiResponse::BAD_REQUEST->response([
'message' => 'Este tag está asignado a un vehículo. Usa el endpoint de cancelación de constancia.',
'tag_status' => $tag->status->name,
]);
}
// Validar que no esté ya cancelado
if ($tag->isCancelled()) {
return ApiResponse::BAD_REQUEST->response([
'message' => 'El tag ya está cancelado.',
]);
}
$additionalInfo = [];
if ($request->filled('id_chip')) {
$additionalInfo[] = "ID CHIP: {$request->id_chip}";
}
$observations = $request->cancellation_observations;
if (!empty($additionalInfo)) {
$observations = ($observations ? $observations . ' | ' : '') . implode(' | ', $additionalInfo);
}
$cancellationLog = TagCancellationLog::create([
'tag_id' => $tag->id,
'cancellation_reason_id' => $request->cancellation_reason_id,
'cancellation_observations' => $observations,
'cancellation_at' => now(),
'cancelled_by' => Auth::id(),
]);
// Actualizar el módulo del tag si se proporciona
if ($request->filled('module_id')) {
$tag->module_id = $request->module_id;
$tag->save();
}
// Cancelar el tag
$tag->markAsDamaged();
DB::commit();
try {
// Recargar el tag con sus relaciones actualizadas
$tag->load(['status', 'cancellationLogs.cancellationReason', 'cancellationLogs.cancelledBy', 'module']);
// Obtener datos de cancelación del último log
$lastCancellation = $tag->cancellationLogs()
->with(['cancellationReason', 'cancelledBy'])
->latest()
->first();
// Preparar datos para el PDF
$cancellationData = [
'fecha' => $lastCancellation ? $lastCancellation->cancellation_at->format('d/m/Y') : now()->format('d/m/Y'),
'folio' => $tag->folio ?? '',
'id_chip' => $request->id_chip ?? '',
'motivo' => $lastCancellation && $lastCancellation->cancellationReason
? $lastCancellation->cancellationReason->name
: 'No especificado',
'operador' => $lastCancellation && $lastCancellation->cancelledBy
? $lastCancellation->cancelledBy->name
: 'Sistema',
'modulo' => $tag->module ? $tag->module->name : 'No especificado',
'ubicacion' => $tag->module ? $tag->module->address : 'No especificado',
];
$pdf = Pdf::loadView('pdfs.tag', [
'cancellation' => $cancellationData,
])
->setPaper('a4', 'portrait')
->setOptions([
'defaultFont' => 'sans-serif',
'isHtml5ParserEnabled' => true,
'isRemoteEnabled' => true,
]);
return $pdf->stream('constancia_cancelada_' . ($tag->tag_number ?? $tag->folio) . '.pdf');
} catch (\Exception $e) {
// Si falla la generación del PDF, devolver respuesta JSON
Log::error('Error al generar PDF de tag cancelado: ' . $e->getMessage());
return ApiResponse::OK->response([
'message' => 'Tag cancelado exitosamente (Error al generar PDF)',
'tag' => [
'id' => $tag->id,
'tag_number' => $tag->tag_number,
'folio' => $tag->folio,
'previous_status' => 'Disponible',
'new_status' => 'Dañado',
],
'cancellation' => [
'id' => $cancellationLog->id,
'reason' => $cancellationLog->cancellationReason->name,
'observations' => $cancellationLog->cancellation_observations,
'cancelled_at' => $cancellationLog->cancellation_at->toDateTimeString(),
'cancelled_by' => Auth::user()->name,
],
'pdf_error' => $e->getMessage(),
]);
}
} catch (\Exception $e) {
DB::rollBack();
return ApiResponse::BAD_REQUEST->response([
'message' => 'Error al cancelar el tag',
'error' => $e->getMessage(),
]);
}
}
}