Correción Excel Canceladas, Correción Search Record, Creación del Actualización (tagSubstitution)
This commit is contained in:
parent
96f938a279
commit
0be583a088
@ -11,6 +11,7 @@
|
|||||||
use App\Models\VehicleTagLog;
|
use App\Models\VehicleTagLog;
|
||||||
use App\Models\Tag;
|
use App\Models\Tag;
|
||||||
use App\Models\Module;
|
use App\Models\Module;
|
||||||
|
use App\Models\TagCancellationLog;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use Notsoweb\ApiResponse\Enums\ApiResponse;
|
use Notsoweb\ApiResponse\Enums\ApiResponse;
|
||||||
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||||
@ -229,7 +230,7 @@ public function constanciasCanceladas(Request $request)
|
|||||||
$request->validate([
|
$request->validate([
|
||||||
'fecha_inicio' => 'required|date',
|
'fecha_inicio' => 'required|date',
|
||||||
'fecha_fin' => 'required|date|after_or_equal:fecha_inicio',
|
'fecha_fin' => 'required|date|after_or_equal:fecha_inicio',
|
||||||
'module_id' => 'required|exists:modules,id',
|
'module_id' => 'nullable|exists:modules,id',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$fechaInicio = Carbon::parse($request->fecha_inicio)->startOfDay();
|
$fechaInicio = Carbon::parse($request->fecha_inicio)->startOfDay();
|
||||||
@ -237,7 +238,7 @@ public function constanciasCanceladas(Request $request)
|
|||||||
$moduleId = $request->module_id;
|
$moduleId = $request->module_id;
|
||||||
|
|
||||||
// Obtener información del módulo
|
// Obtener información del módulo
|
||||||
$module = Module::findOrFail($moduleId);
|
$module = $moduleId ? Module::find($moduleId) : null;
|
||||||
|
|
||||||
// Obtener logs de cancelación en el rango de fechas
|
// Obtener logs de cancelación en el rango de fechas
|
||||||
$logs = VehicleTagLog::with([
|
$logs = VehicleTagLog::with([
|
||||||
@ -246,14 +247,28 @@ public function constanciasCanceladas(Request $request)
|
|||||||
'cancellationReason'
|
'cancellationReason'
|
||||||
])
|
])
|
||||||
->where('action_type', 'cancelacion')
|
->where('action_type', 'cancelacion')
|
||||||
->whereHas('vehicle.records', function ($query) use ($moduleId) {
|
->when($moduleId, function ($query) use ($moduleId) {
|
||||||
$query->where('module_id', $moduleId);
|
$query->whereHas('vehicle.records', function ($q) use ($moduleId) {
|
||||||
|
$q->where('module_id', $moduleId);
|
||||||
|
});
|
||||||
})
|
})
|
||||||
->whereBetween('cancellation_at', [$fechaInicio, $fechaFin])
|
->whereBetween('cancellation_at', [$fechaInicio, $fechaFin])
|
||||||
->orderBy('cancellation_at', 'asc')
|
->orderBy('cancellation_at', 'asc')
|
||||||
->get();
|
->get();
|
||||||
|
|
||||||
if ($logs->isEmpty()) {
|
$logsT = TagCancellationLog::with([
|
||||||
|
'tag',
|
||||||
|
'cancellationReason'
|
||||||
|
])->when($moduleId, function ($query) use ($moduleId) {
|
||||||
|
$query->whereHas('tag', function ($q) use ($moduleId) {
|
||||||
|
$q->where('module_id', $moduleId);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
->whereBetween('cancellation_at', [$fechaInicio, $fechaFin])
|
||||||
|
->orderBy('cancellation_at', 'asc')
|
||||||
|
->get();
|
||||||
|
|
||||||
|
if ($logs->isEmpty() && $logsT->isEmpty()) {
|
||||||
return ApiResponse::NOT_FOUND->response([
|
return ApiResponse::NOT_FOUND->response([
|
||||||
'message' => 'No se encontraron constancias canceladas en el periodo especificado',
|
'message' => 'No se encontraron constancias canceladas en el periodo especificado',
|
||||||
'fecha_inicio' => $fechaInicio->format('Y-m-d'),
|
'fecha_inicio' => $fechaInicio->format('Y-m-d'),
|
||||||
@ -263,7 +278,8 @@ public function constanciasCanceladas(Request $request)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Preparar datos para el Excel
|
// Preparar datos para el Excel
|
||||||
$data = $this->prepareExcelDataCanceladas($logs);
|
$allLogs = $logs->concat($logsT)->sortBy('cancellation_at');
|
||||||
|
$data = $this->prepareExcelDataCanceladas($allLogs);
|
||||||
|
|
||||||
// Generar archivo Excel
|
// Generar archivo Excel
|
||||||
$fileName = 'Constancias_Canceladas_' . $fechaInicio->format('Ymd') . '_' . $fechaFin->format('Ymd') . '.xlsx';
|
$fileName = 'Constancias_Canceladas_' . $fechaInicio->format('Ymd') . '_' . $fechaFin->format('Ymd') . '.xlsx';
|
||||||
@ -316,7 +332,7 @@ public function constanciasCanceladas(Request $request)
|
|||||||
// MÓDULO
|
// MÓDULO
|
||||||
$sheet->setCellValue('B' . $row, 'MÓDULO:');
|
$sheet->setCellValue('B' . $row, 'MÓDULO:');
|
||||||
$sheet->mergeCells('C' . $row . ':K' . $row);
|
$sheet->mergeCells('C' . $row . ':K' . $row);
|
||||||
$sheet->setCellValue('C' . $row, $module->name ?? 'MÓDULO 1. BASE 4');
|
$sheet->setCellValue('C' . $row, $module?->name ?? 'S/N MODULO');
|
||||||
$sheet->getStyle('B' . $row)->getFont()->setBold(true)->setSize(11);
|
$sheet->getStyle('B' . $row)->getFont()->setBold(true)->setSize(11);
|
||||||
$sheet->getStyle('B' . $row . ':K' . $row)->applyFromArray($borderStyle);
|
$sheet->getStyle('B' . $row . ':K' . $row)->applyFromArray($borderStyle);
|
||||||
$sheet->getStyle('B' . $row . ':K' . $row)->getAlignment()->setWrapText(true);
|
$sheet->getStyle('B' . $row . ':K' . $row)->getAlignment()->setWrapText(true);
|
||||||
@ -461,7 +477,7 @@ private function prepareExcelDataCanceladas($logs)
|
|||||||
$no = 1;
|
$no = 1;
|
||||||
|
|
||||||
foreach ($logs as $log) {
|
foreach ($logs as $log) {
|
||||||
$vehicle = $log->vehicle;
|
$vehicle = $log->vehicle ?? $log->tag->vehicle;
|
||||||
$tag = $log->tag;
|
$tag = $log->tag;
|
||||||
|
|
||||||
$data[] = [
|
$data[] = [
|
||||||
|
|||||||
@ -350,7 +350,9 @@ public function searchRecord(Request $request)
|
|||||||
'action_type' => 'nullable|string|in:inscripcion,actualizacion,sustitucion,cancelacion',
|
'action_type' => 'nullable|string|in:inscripcion,actualizacion,sustitucion,cancelacion',
|
||||||
'status' => 'nullable|string',
|
'status' => 'nullable|string',
|
||||||
], [
|
], [
|
||||||
'required_without_all' => 'Debe proporcionar al menos uno de los siguientes: folio, placa o vin.'
|
'folio.required_without_all' => 'Se requiere al menos un criterio de búsqueda.',
|
||||||
|
'placa.required_without_all' => 'Se requiere al menos un criterio de búsqueda.',
|
||||||
|
'vin.required_without_all' => 'Se requiere al menos un criterio de búsqueda.',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$records = Record::with([
|
$records = Record::with([
|
||||||
@ -376,7 +378,9 @@ public function searchRecord(Request $request)
|
|||||||
'error:id,code,description',
|
'error:id,code,description',
|
||||||
|
|
||||||
// Log de acciones
|
// Log de acciones
|
||||||
'vehicle.vehicleTagLogs:id,vehicle_id,tag_id,action_type,performed_by,created_at'
|
'vehicle.vehicleTagLogs' => function ($q) {
|
||||||
|
$q->orderBy('created_at', 'DESC');
|
||||||
|
},
|
||||||
])->orderBy('id', 'ASC');
|
])->orderBy('id', 'ASC');
|
||||||
|
|
||||||
if ($request->filled('folio')) {
|
if ($request->filled('folio')) {
|
||||||
@ -394,25 +398,36 @@ public function searchRecord(Request $request)
|
|||||||
$q->where('niv', 'LIKE', '%' . $request->input('vin') . '%');
|
$q->where('niv', 'LIKE', '%' . $request->input('vin') . '%');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
// Filtro por módulo
|
||||||
if ($request->filled('module_id')) {
|
if ($request->filled('module_id')) {
|
||||||
$records->where('module_id', $request->input('module_id'));
|
$records->where('module_id', $request->input('module_id'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Filtro por tipo de acción
|
||||||
if ($request->filled('action_type')) {
|
if ($request->filled('action_type')) {
|
||||||
$records->whereHas('vehicle.vehicleTagLogs', function ($q) use ($request) {
|
$records->whereHas('vehicle.vehicleTagLogs', function ($q) use ($request) {
|
||||||
$q->where('action_type', $request->input('action_type'));
|
$q->where('action_type', $request->input('action_type'))
|
||||||
|
->whereRaw('id = (
|
||||||
|
SELECT MAX(id)
|
||||||
|
FROM vehicle_tags_logs
|
||||||
|
WHERE vehicle_id = vehicle.id
|
||||||
|
)');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Filtro por status del tag
|
||||||
if ($request->filled('status')) {
|
if ($request->filled('status')) {
|
||||||
$records->whereHas('vehicle.tag.status', function ($q) use ($request) {
|
$records->whereHas('vehicle.tag.status', function ($q) use ($request) {
|
||||||
$q->where('code', $request->input('status'));
|
$q->where('code', $request->input('status'));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Paginación
|
||||||
$paginatedRecords = $records->paginate(config('app.pagination'));
|
$paginatedRecords = $records->paginate(config('app.pagination'));
|
||||||
|
|
||||||
|
// Transformación de datos
|
||||||
$paginatedRecords->getCollection()->transform(function ($record) {
|
$paginatedRecords->getCollection()->transform(function ($record) {
|
||||||
// Obtener el último log de acción
|
$latestLog = $record->vehicle->vehicleTagLogs->first();
|
||||||
$latestLog = $record->vehicle->vehicleTagLogs->sortByDesc('created_at')->first();
|
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'id' => $record->id,
|
'id' => $record->id,
|
||||||
|
|||||||
@ -14,6 +14,7 @@
|
|||||||
use App\Models\Owner;
|
use App\Models\Owner;
|
||||||
use App\Models\CatalogNameImg;
|
use App\Models\CatalogNameImg;
|
||||||
use App\Models\VehicleTagLog;
|
use App\Models\VehicleTagLog;
|
||||||
|
use App\Models\Tag;
|
||||||
use App\Services\RepuveService;
|
use App\Services\RepuveService;
|
||||||
use App\Services\PadronEstatalService;
|
use App\Services\PadronEstatalService;
|
||||||
use Exception;
|
use Exception;
|
||||||
@ -33,96 +34,155 @@ public function __construct(
|
|||||||
$this->padronEstatalService = $padronEstatalService;
|
$this->padronEstatalService = $padronEstatalService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function vehicleData(Request $request)
|
/**
|
||||||
|
* Sustitución de TAG
|
||||||
|
* Proceso: Buscar TAG actual por folio del expediente, cancelarlo y asignar un nuevo TAG al vehículo
|
||||||
|
*/
|
||||||
|
public function tagSubstitution(Request $request)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$request->validate([
|
$request->validate([
|
||||||
'folio' => 'required|string|exists:records,folio',
|
'folio' => 'required|string|exists:records,folio',
|
||||||
'tag_number' => 'required|string|exists:tags,tag_number',
|
'new_tag_folio' => 'required|string|exists:tags,folio',
|
||||||
'niv' => 'required|string|exists:vehicle,niv'
|
'cancellation_reason_id' => 'nullable|exists:catalog_cancellation_reasons,id',
|
||||||
|
'cancellation_observations' => 'nullable|string|max:500',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$folio = $request->input('folio');
|
$folio = $request->input('folio');
|
||||||
$tagNumber = $request->input('tag_number');
|
$newTagFolio = $request->input('new_tag_folio');
|
||||||
$niv = $request->input('niv');
|
$cancellationReasonId = $request->input('cancellation_reason_id');
|
||||||
|
$cancellationObservations = $request->input('cancellation_observations');
|
||||||
$isStolen = $this->checkIfStolen($niv);
|
|
||||||
|
|
||||||
if ($isStolen) {
|
|
||||||
return ApiResponse::FORBIDDEN->response([
|
|
||||||
'message' => 'El vehículo reporta robo. No se puede continuar con la actualización.',
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Buscar el expediente por folio
|
||||||
$record = Record::with([
|
$record = Record::with([
|
||||||
'vehicle:id,owner_id,placa,niv,marca,linea,modelo,color',
|
'vehicle.tag.status',
|
||||||
'vehicle.owner:id,name,paternal,maternal,rfc',
|
'vehicle.owner',
|
||||||
'vehicle.tag:id,vehicle_id,folio,tag_number,status_id',
|
])->where('folio', $folio)->first();
|
||||||
'files:id,record_id,name_id,path,md5',
|
|
||||||
'files.catalogName:id,name',
|
|
||||||
'user:id,name,email',
|
|
||||||
'error:id,code,description'
|
|
||||||
])
|
|
||||||
->select([
|
|
||||||
'id',
|
|
||||||
'folio',
|
|
||||||
'vehicle_id',
|
|
||||||
'user_id',
|
|
||||||
'error_id',
|
|
||||||
'created_at',
|
|
||||||
'updated_at'
|
|
||||||
])->where('folio', $folio)
|
|
||||||
->first();
|
|
||||||
|
|
||||||
if (!$record) {
|
if (!$record) {
|
||||||
return ApiResponse::NOT_FOUND->response([
|
return ApiResponse::NOT_FOUND->response([
|
||||||
'message' => 'No se encontró el expediente',
|
'message' => 'No se encontró el expediente con el folio proporcionado',
|
||||||
|
'folio' => $folio,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$vehicle = $record->vehicle;
|
$vehicle = $record->vehicle;
|
||||||
$tag = $vehicle->tag;
|
$oldTag = $vehicle->tag;
|
||||||
|
|
||||||
if (!$tag || $tag->tag_number !== $tagNumber) {
|
if (!$oldTag) {
|
||||||
return ApiResponse::BAD_REQUEST->response([
|
return ApiResponse::NOT_FOUND->response([
|
||||||
'message' => 'El tag_number no coincide con el registrado en el expediente',
|
'message' => 'El vehículo no tiene un TAG asignado actualmente',
|
||||||
|
'folio' => $folio,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($vehicle->niv !== $niv) {
|
// Verificar que el TAG antiguo esté asignado
|
||||||
|
if (!$oldTag->isAssigned()) {
|
||||||
return ApiResponse::BAD_REQUEST->response([
|
return ApiResponse::BAD_REQUEST->response([
|
||||||
'message' => 'El NIV no coincide con el registrado en el expediente',
|
'message' => 'El TAG actual no está en estado asignado',
|
||||||
|
'tag_folio' => $oldTag->folio,
|
||||||
|
'current_status' => $oldTag->status->name,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Consultar REPUVE Estatal para obtener datos actualizados
|
// Buscar el nuevo TAG por folio
|
||||||
$vehicleDataEstatal = $this->getVehicle($niv);
|
$newTag = Tag::with('status')
|
||||||
$ownerDataEstatal = $this->getOwner($niv);
|
->where('folio', $newTagFolio)
|
||||||
|
->first();
|
||||||
|
|
||||||
// Guardar en caché por 30 minutos
|
if (!$newTag) {
|
||||||
Cache::put("update_vehicle_{$niv}", $vehicleDataEstatal, 1800);
|
return ApiResponse::NOT_FOUND->response([
|
||||||
Cache::put("update_owner_{$niv}", $ownerDataEstatal, 1800);
|
'message' => 'El nuevo TAG no existe',
|
||||||
|
'new_tag_folio' => $newTagFolio,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
// Detectar si hay cambios entre BD y padrón estatal
|
// Verificar que el nuevo TAG esté disponible
|
||||||
$hasVehicleChanges = $this->detectVehicleChanges($vehicle, $vehicleDataEstatal);
|
if (!$newTag->isAvailable()) {
|
||||||
$hasOwnerChanges = $this->detectOwnerChanges($vehicle->owner, $ownerDataEstatal);
|
return ApiResponse::BAD_REQUEST->response([
|
||||||
|
'message' => 'El nuevo TAG no está disponible para asignación',
|
||||||
|
'new_tag_folio' => $newTagFolio,
|
||||||
|
'current_status' => $newTag->status->name,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verificar robo del vehículo
|
||||||
|
$isStolen = $this->checkIfStolen($vehicle->niv);
|
||||||
|
|
||||||
|
if ($isStolen) {
|
||||||
|
return ApiResponse::FORBIDDEN->response([
|
||||||
|
'message' => 'El vehículo reporta robo. No se puede continuar con la sustitución.',
|
||||||
|
'niv' => $vehicle->niv,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
DB::beginTransaction();
|
||||||
|
|
||||||
|
// Cancelar el TAG anterior
|
||||||
|
$oldTag->markAsCancelled();
|
||||||
|
|
||||||
|
// Registrar log de cancelación del TAG anterior
|
||||||
|
VehicleTagLog::create([
|
||||||
|
'vehicle_id' => $vehicle->id,
|
||||||
|
'tag_id' => $oldTag->id,
|
||||||
|
'action_type' => 'sustitucion',
|
||||||
|
'cancellation_reason_id' => $cancellationReasonId,
|
||||||
|
'cancellation_observations' => $cancellationObservations,
|
||||||
|
'cancellation_at' => now(),
|
||||||
|
'cancelled_by' => Auth::id(),
|
||||||
|
'performed_by' => Auth::id(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Actualizar el folio del record con el folio del nuevo TAG
|
||||||
|
$record->update([
|
||||||
|
'folio' => $newTagFolio
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Asignar el nuevo TAG al vehículo (usa el nuevo folio)
|
||||||
|
$newTag->markAsAssigned($vehicle->id, $newTagFolio);
|
||||||
|
|
||||||
|
// 5. Registrar log de asignación del nuevo TAG
|
||||||
|
VehicleTagLog::create([
|
||||||
|
'vehicle_id' => $vehicle->id,
|
||||||
|
'tag_id' => $newTag->id,
|
||||||
|
'action_type' => 'sustitucion',
|
||||||
|
'performed_by' => Auth::id(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 6. Enviar a REPUVE Nacional
|
||||||
|
$datosCompletos = $this->prepararDatosParaInscripcion($vehicle->niv);
|
||||||
|
ProcessRepuveResponse::dispatch($record->id, $datosCompletos);
|
||||||
|
|
||||||
|
DB::commit();
|
||||||
|
|
||||||
|
// Recargar relaciones para la respuesta
|
||||||
|
$record->load(['vehicle.tag.status', 'vehicle.owner']);
|
||||||
|
|
||||||
return ApiResponse::OK->response([
|
return ApiResponse::OK->response([
|
||||||
'message' => 'Datos del vehículo obtenidos exitosamente',
|
'message' => 'Sustitución de TAG realizada exitosamente',
|
||||||
'current_data' => $record,
|
'substitution_details' => [
|
||||||
'estatal_data' => [
|
'old_folio' => $folio,
|
||||||
'vehicle' => $vehicleDataEstatal,
|
'new_folio' => $newTagFolio,
|
||||||
'owner' => $ownerDataEstatal,
|
'old_tag' => [
|
||||||
],
|
'folio' => $oldTag->folio,
|
||||||
'has_changes' => $hasVehicleChanges || $hasOwnerChanges,
|
'tag_number' => $oldTag->tag_number,
|
||||||
'changes_detail' => [
|
'status' => 'cancelled',
|
||||||
'vehicle' => $hasVehicleChanges,
|
],
|
||||||
'owner' => $hasOwnerChanges,
|
'new_tag' => [
|
||||||
|
'folio' => $newTag->folio,
|
||||||
|
'tag_number' => $newTag->tag_number,
|
||||||
|
'status' => 'assigned',
|
||||||
|
],
|
||||||
|
'performed_by' => Auth::user()->name,
|
||||||
|
'performed_at' => now()->format('Y-m-d H:i:s'),
|
||||||
],
|
],
|
||||||
|
'record' => $record,
|
||||||
]);
|
]);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
return ApiResponse::BAD_REQUEST->response([
|
DB::rollBack();
|
||||||
'message' => 'Error de validación',
|
|
||||||
|
return ApiResponse::INTERNAL_ERROR->response([
|
||||||
|
'message' => 'Error al realizar la sustitución del TAG',
|
||||||
'error' => $e->getMessage(),
|
'error' => $e->getMessage(),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user