2025-10-29 15:58:07 -06:00

390 lines
14 KiB
PHP

<?php
namespace App\Http\Controllers\Repuve;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Http\Requests\Repuve\VehicleUpdateRequest;
use Notsoweb\ApiResponse\Enums\ApiResponse;
use Illuminate\Support\Facades\DB;
use App\Models\Record;
use App\Models\File;
use App\Models\Owner;
use App\Models\Tag;
use App\Models\Error;
use Exception;
class UpdateController extends Controller
{
public function vehicleData(Request $request)
{
try {
$request->validate([
'folio' => 'required','string','exists:records,folio',
'tag_number' => 'required','string','exists:tags,tag_number',
'vin' => 'required','string','exists:vehicles,vin'
]);
$folio = $request->input('folio');
$tagNumber = $request->input('tag_number');
$vin = $request->input('vin');
$isStolen = $this->checkIfStolen($vin);
if ($isStolen) {
return ApiResponse::FORBIDDEN->response([
'vin' => $vin,
'stolen' => true,
'message' => 'El vehículo reporta robo. No se puede continuar con la actualización.',
]);
}
$record = Record::with(['vehicle.owner', 'vehicle.tag', 'files', 'error'])
->where('folio', $folio)
->first();
if (!$record) {
return ApiResponse::BAD_REQUEST->response([
'message' => 'No se encontró el expediente',
'folio' => $folio,
]);
}
$vehicle = $record->vehicle;
$tag = $vehicle->tag;
if (!$tag || $tag->tag_number !== $tagNumber) {
return ApiResponse::BAD_REQUEST->response([
'message' => 'El tag_number no coincide con el registrado en el expediente',
]);
}
if ($vehicle->numero_serie !== $vin) {
return ApiResponse::BAD_REQUEST->response([
'message' => 'El VIN no coincide con el registrado en el expediente',
]);
}
$owner = $vehicle->owner;
return ApiResponse::OK->response([
'message' => 'Datos del vehículo obtenidos exitosamente',
'record' => [
'id' => $record->id,
'folio' => $record->folio,
'created_at' => $record->created_at->toDateTimeString(),
'updated_at' => $record->updated_at->toDateTimeString(),
],
'vehicle' => [
'id' => $vehicle->id,
'placa' => $vehicle->placa,
'anio_placa' => $vehicle->anio_placa,
'numero_serie' => $vehicle->numero_serie,
'vigencia' => $vehicle->vigencia,
'fecha_impresion' => $vehicle->fecha_impresion,
'qr_hash' => $vehicle->qr_hash,
'valido' => $vehicle->valido,
'nombre' => $vehicle->nombre,
'nombre2' => $vehicle->nombre2,
'marca' => $vehicle->marca,
'linea' => $vehicle->linea,
'sublinea' => $vehicle->sublinea,
'modelo' => $vehicle->modelo,
'color' => $vehicle->color,
'tipo' => $vehicle->tipo,
'tipo_servicio' => $vehicle->tipo_servicio,
'numero_motor' => $vehicle->numero_motor,
'descripcion_origen' => $vehicle->descripcion_origen,
'municipio' => $vehicle->municipio,
'localidad' => $vehicle->localidad,
'calle' => $vehicle->calle,
'calle2' => $vehicle->calle2,
'codigo_postal' => $vehicle->codigo_postal,
'serie_folio' => $vehicle->serie_folio,
'nrpv' => $vehicle->nrpv,
],
'owner' => [
'id' => $owner->id,
'name' => $owner->name,
'paternal' => $owner->paternal,
'maternal' => $owner->maternal,
'full_name' => $owner->full_name,
'rfc' => $owner->rfc,
'curp' => $owner->curp,
'address' => $owner->address,
],
'tag' => [
'id' => $tag->id,
'folio' => $tag->folio,
'tag_number' => $tag->tag_number,
'status' => $tag->status,
'package_id' => $tag->package_id,
],
'existing_files' => $record->files->map(function ($file) {
return [
'id' => $file->id,
'name' => $file->name,
'path' => $file->path,
'url' => $file->url,
'created_at' => $file->created_at->toDateTimeString(),
];
}),
'total_files' => $record->files->count(),
]);
} catch (Exception $e) {
return ApiResponse::BAD_REQUEST->response([
'message' => 'Error de validación',
'error' => $e->getMessage(),
]);
}
}
public function vehicleUpdate(VehicleUpdateRequest $request)
{
try {
$folio = $request->input('folio');
$tagNumber = $request->input('tag_number');
$vin = $request->input('vin');
$isStolen = $this->checkIfStolen($vin);
if ($isStolen) {
return ApiResponse::FORBIDDEN->response([
'vin' => $vin,
'stolen' => true,
'message' => 'El vehículo reporta robo. No se puede continuar con la actualización.',
]);
}
$record = Record::with(['vehicle.owner', 'vehicle.tag', 'files', 'error'])
->where('folio', $folio)
->first();
if (!$record) {
return ApiResponse::NOT_FOUND->response([
'message' => 'No se encontró el expediente',
'folio' => $folio,
]);
}
$vehicle = $record->vehicle;
$tag = $vehicle->tag;
if (!$tag || $tag->tag_number !== $tagNumber) {
return ApiResponse::BAD_REQUEST->response([
'message' => 'El tag_number no coincide con el registrado en el expediente',
]);
}
if ($vehicle->numero_serie !== $vin) {
return ApiResponse::BAD_REQUEST->response([
'message' => 'El VIN no coincide con el registrado en el expediente',
]);
}
DB::beginTransaction();
$ownerData = $this->getOwner();
$owner = Owner::updateOrCreate(
['rfc' => $ownerData['rfc']],
[
'name' => $ownerData['name'],
'paternal' => $ownerData['paternal'],
'maternal' => $ownerData['maternal'],
'curp' => $ownerData['curp'],
'address' => $ownerData['address'],
]
);
$uploadedFiles = [];
if ($request->hasFile('files')) {
$files = $request->file('files');
$fileNames = $request->input('names', []);
foreach ($files as $indx => $file) {
$customName = $fileNames[$indx] ?? "archivo_" . ($indx + 1);
$customName = str_replace(' ', '_', $customName);
$extension = $file->getClientOriginalExtension();
$fileName = $customName . '_' . time() . '.' . $extension;
$path = $file->storeAs('records', $fileName, 'public');
$md5 = md5_file($file->getRealPath());
$fileRecord = File::create([
'record_id' => $record->id,
'name' => $fileName,
'path' => $path,
'md5' => $md5,
]);
$uploadedFiles[] = [
'id' => $fileRecord->id,
'name' => $fileRecord->name,
'path' => $fileRecord->path,
'url' => $fileRecord->url,
];
}
}
//Envio de datos
$apiResponse = $this->sendToRepuveNacional($vin);
$apiResponse["repuve_response"]["folio_ci"] = $record->folio;
$apiResponse["repuve_response"]["identificador_ci"] = $tag->tag_number;
if (isset($apiResponse['has_error']) && $apiResponse['has_error']) {
$error = Error::where('code', $apiResponse['error_code'])->first();
if (!$error) {
DB::rollBack();
return ApiResponse::INTERNAL_ERROR->response([
'message' => 'Código de error no encontrado en el catálogo',
'error_code' => $apiResponse['error_code'],
'error_message' => $apiResponse['error_message'],
]);
}
$record->update([
'error_id' => $error->id,
'api_response' => $apiResponse,
'error_occurred_at' => now(),
]);
DB::commit();
return ApiResponse::NOT_ACCEPTABLE->response([
'message' => 'Datos guardados con error. Corrija y vuelva a enviar.',
'has_error' => true,
'can_retry' => true,
'error' => [
'code' => $error->code,
'description' => $error->description,
'occurred_at' => $record->error_occurred_at->toDateTimeString(),
],
'record' => [
'id' => $record->id,
'folio' => $record->folio,
],
]);
}
$record->update([
'error_id' => null,
'api_response' => $apiResponse,
'error_occurred_at' => null,
]);
DB::commit();
return ApiResponse::OK->response([
'message' => 'Vehículo actualizado exitosamente',
'has_error' => false,
'record' => [
'id' => $record->id,
'folio' => $record->folio,
'updated_at' => $record->updated_at->toDateTimeString(),
],
'vehicle' => [
'id' => $vehicle->id,
'placa' => $vehicle->placa,
'numero_serie' => $vehicle->numero_serie,
'marca' => $vehicle->marca,
'modelo' => $vehicle->modelo,
'color' => $vehicle->color,
],
'owner' => [
'id' => $owner->id,
'full_name' => $owner->full_name,
'rfc' => $owner->rfc,
],
'tag' => [
'id' => $tag->id,
'tag_number' => $tag->tag_number,
'status' => $tag->status,
],
'new_files' => $uploadedFiles,
'total_files' => $record->files->count() + count($uploadedFiles),
]);
} catch (Exception $e) {
return ApiResponse::INTERNAL_ERROR->response([
'message' => 'Error al actualizar el vehículo',
'error' => $e->getMessage(),
]);
}
}
private function checkIfStolen(string $folio): bool
{
// Aquí api servicio de REPUVE Nacional
// simulamos con random
return (bool) rand(0, 1);
}
private function sendToRepuveNacional(string $vin): array
{
// Enviar datos a API Repuve Nacional
// Aquí se haría la llamada real a la API de Repuve Nacional
// Por ahora simulamos con mock igual que InscriptionController
// Respuesta exitosa mockup REPUVE
$mockResponse = "OK:SIN INFORMACION|OTROS|SIN INFORMACION|10/07/2023|CENTRO|$vin|WSA548B|HR16777934V|2023|BLANCO|ADVANCE|TABASCO|NISSAN|MARCH|PARTICULAR|AUTOMOVIL|ACTIVO|null||null|0|null|0|10337954|E2003412012BB0C130FAD04D|Sin observaciones&#xd;";
// Parsear la cadena a JSON usando los campos oficiales
$fields = [
'marca',
'submarca',
'tipo_vehiculo',
'fecha_expedicion',
'oficina',
'niv',
'placa',
'motor',
'modelo',
'color',
'version',
'entidad',
'marca_padron',
'submarca_padron',
'tipo_uso_padron',
'tipo_vehiculo_padron',
'estatus_registro',
'aduana',
'nombre_aduana',
'patente',
'pedimento',
'fecha_pedimento',
'clave_importador',
'folio_ci',
'identificador_ci',
'observaciones'
];
$values = explode('|', str_replace('OK:', '', $mockResponse));
$jsonResponse = [];
foreach ($fields as $i => $field) {
$jsonResponse[$field] = $values[$i] ?? null;
}
return [
'has_error' => false,
'error_code' => null,
'error_message' => null,
'timestamp' => now()->toDateTimeString(),
'vin' => $vin,
'repuve_response' => $jsonResponse,
];
}
private function getOwner(): array
{
return [
'name' => 'Nicolas',
'paternal' => 'Hernandez',
'maternal' => 'Castillo',
'rfc' => 'HECN660509HTCRSC01',
'curp' => 'HECN660509HTCRSC01',
'address' => 'Fracc Pomoca, Calle Armadillo MZ9 LT28',
];
}
}