FEAT: Creacion de RecordController, FileStoreRequest, actualiza modelos y controladores, renombra VehicleRequest, y ajusta configuración y vistas para gestión de expedientes

This commit is contained in:
Juan Felipe Zapata Moreno 2025-10-20 16:29:31 -06:00
parent 71788ddd2e
commit de0ac7a3aa
18 changed files with 1804 additions and 3752 deletions

View File

@ -36,22 +36,6 @@ DB_USERNAME=notsoweb
DB_PASSWORD= DB_PASSWORD=
PMA_PORT=8081 # Puerto para phpMyAdmin PMA_PORT=8081 # Puerto para phpMyAdmin
# MongoDB Atlas Configuración nube
MONGO_DSN="mongodb+srv://"
MONGO_DATABASE=repuve
MONGO_SSL=true
MONGO_AUTH_SOURCE=admin
MONGO_RETRY_WRITES=true
MONGO_W=majority
# MongoDB Local
MONGO_HOST=mongodb
MONGO_PORT=27017
MONGO_DATABASE=holos
MONGO_USERNAME=root
MONGO_PASSWORD=secret
REDIS_PORT=6379 # Puerto para Redis
NGINX_PORT=8080 # Puerto para Nginx NGINX_PORT=8080 # Puerto para Nginx
SESSION_DRIVER=database SESSION_DRIVER=database

View File

@ -0,0 +1,117 @@
<?php
namespace App\Http\Controllers\Repuve;
use App\Http\Controllers\Controller;
use Barryvdh\DomPDF\Facade\Pdf;
use App\Http\Requests\Repuve\FileStoreRequest;
use Notsoweb\ApiResponse\Enums\ApiResponse;
use Illuminate\Support\Facades\Storage;
use App\Models\Record;
use App\Models\File;
class RecordController extends Controller
{
public function generatePdf($id)
{
$record = Record::with('vehicle')->findOrFail($id);
$pdf = Pdf::loadView('pdfs.record', compact('record'))
->setPaper('a4', 'portrait')
->setOptions([
'defaultFont' => 'sans-serif',
'isHtml5ParserEnabled' => true,
'isRemoteEnabled' => true,
]);
return $pdf->stream('record-' . $id . '.pdf');
}
public function uploadFile(FileStoreRequest $request){
try {
// Verificar que existe el record
$record = Record::findOrFail($request->record_id);
// Obtener el archivo
$uploadedFile = $request->file('file');
// Generar nombre único
$fileName = time() . '_' . $uploadedFile->getClientOriginalName();
// Guardar en storage
$path = $uploadedFile->storeAs('records', $fileName, 'public');
// Calcular MD5 del archivo
$md5 = md5_file($uploadedFile->getRealPath());
// Crear registro en la tabla files
$file = File::create([
'name' => $request->name,
'path' => $path,
'md5' => $md5,
'record_id' => $record->id,
]);
return ApiResponse::OK->response([
'message' => 'Archivo subido exitosamente',
'file' => [
'id' => $file->id,
'name' => $file->name,
'path' => $file->path,
'md5' => $file->md5,
'url' => $file->url,
'record_id' => $file->record_id,
'created_at' => $file->created_at->toDateTimeString(),
],
]);
} catch (\Exception $e) {
return ApiResponse::UNPROCESSABLE_CONTENT->response([
'message' => 'Error al subir el archivo',
'error' => $e->getMessage(),
]);
}
}
public function getFile($recordId) {
try {
$record = Record::with('files')->findOrFail($recordId);
return ApiResponse::OK->response([
'record_id' => $record->id,
'files' => $record->files,
'folio' => $record->folio,
]);
}catch(\Exception $e) {
return ApiResponse::NOT_FOUND->response([
'message' => 'No se encontró el expediente o no tiene archivos asociados.',
'error' => $e->getMessage(),
]);
}
}
public function deleteFile($fileId)
{
try {
$file = File::findOrFail($fileId);
// Eliminar archivo físico del storage
if (Storage::disk('public')->exists($file->path)) {
Storage::disk('public')->delete($file->path);
}
// Eliminar registro de la BD
$file->delete();
return ApiResponse::OK->response([
'message' => 'Archivo eliminado exitosamente',
]);
} catch (\Exception $e) {
return ApiResponse::OK->response([
'message' => 'Error al eliminar el archivo',
'error' => $e->getMessage(),
]);
}
}
}

View File

@ -1,64 +1,217 @@
<?php namespace App\Http\Controllers\Repuve; <?php namespace App\Http\Controllers\Repuve;
/**
* @copyright (c) 2025 Notsoweb Software (https://notsoweb.com) - All Rights Reserved
*/
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Notsoweb\ApiResponse\Enums\ApiResponse; use Notsoweb\ApiResponse\Enums\ApiResponse;
use App\Http\Requests\Repuve\VehicleRequest; use App\Http\Requests\Repuve\VehicleStoreRequest;
use App\Models\Vehicle; use App\Models\Vehicle;
use App\Models\Record; use App\Models\Record;
use App\Models\Owner;
use App\Models\File;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
class RepuveController extends Controller class RepuveController extends Controller
{ {
public function consultarVehiculo(VehicleRequest $request) public function inscripcionVehiculo(VehicleStoreRequest $request)
{ {
// La validación por el Request try {
// Validar folio
$folio = $request->input('folio'); $folio = $request->input('folio');
// Simular consulta de robo // Simular consulta de robo
$isStolen = (bool) rand(0, 1); $isStolen = $this->checkIfStolen($folio);
$stolenMessage = $isStolen
? 'El vehículo reporta robo'
: 'El vehículo no reporta robo';
// Obtener datos del vehículo // Si está robado, detener el flujo
if ($isStolen) {
return ApiResponse::FORBIDDEN->response([
'folio' => $folio,
'stolen' => true,
'message' => 'El vehículo reporta robo. No se puede continuar con la inscripción.',
]);
}
// Iniciar transacción
DB::beginTransaction();
// Obtener datos del vehículo y propietario
$vehicleData = $this->getVehicle(); $vehicleData = $this->getVehicle();
$ownerData = $this->getOwner();
$vehicle = Vehicle::updateOrCreate( //Crear propietario
['placa' => $vehicleData['PLACA']], $owner = Owner::updateOrCreate(
['rfc' => $ownerData['rfc']],
[ [
'modelo' => $vehicleData['MODELO'], 'name' => $ownerData['name'],
'marca' => $vehicleData['MARCA'], 'paternal' => $ownerData['paternal'],
'nrpv' => $vehicleData['NUMERO_SERIE'], 'maternal' => $ownerData['maternal'],
'curp' => $ownerData['curp'],
'address' => $ownerData['address'],
] ]
); );
// Crear registro con folio + vehicle_id //Crear o actualizar vehículo
$vehicle = Vehicle::updateOrCreate(
['placa' => $vehicleData['PLACA']],
[
'anio_placa' => $vehicleData['ANIO_PLACA'],
'placa' => $vehicleData['PLACA'],
'numero_serie' => $vehicleData['NO_SERIE'],
'rfc' => $vehicleData['RFC'],
'folio' => $vehicleData['FOLIO'],
'vigencia' => $vehicleData['VIGENCIA'],
'fecha_impresion' => $vehicleData['FECHA_IMPRESION'],
'qr_hash' => $vehicleData['QR_HASH'],
'valido' => $vehicleData['VALIDO'],
'foliotemp' => $vehicleData['FOLIOTEMP'],
'nombre' => $vehicleData['NOMBRE'],
'nombre2' => $vehicleData['NOMBRE2'],
'municipio' => $vehicleData['MUNICIPIO'],
'localidad' => $vehicleData['LOCALIDAD'],
'calle' => $vehicleData['CALLE'],
'calle2' => $vehicleData['CALLE2'],
'tipo' => $vehicleData['TIPO'],
'tipo_servicio' => $vehicleData['TIPO_SERVICIO'],
'marca' => $vehicleData['MARCA'],
'linea' => $vehicleData['LINEA'],
'sublinea' => $vehicleData['SUBLINEA'],
'modelo' => $vehicleData['MODELO'],
'numero_motor' => $vehicleData['NUMERO_MOTOR'],
'descripcion_origen' => $vehicleData['DESCRIPCION_ORIGEN'],
'color' => $vehicleData['COLOR'],
'codigo_postal' => $vehicleData['CODIGO_POSTAL'],
'serie_folio' => $vehicleData['SERIE_FOLIO'],
'sfolio' => $vehicleData['SFOLIO'],
'nrpv' => $vehicleData['NUMERO_SERIE'],
'owner_id' => $owner->id,
]
);
//Crear registro (expediente)
$record = Record::create([ $record = Record::create([
'folio' => $folio, 'folio' => $folio,
'vehicle_id' => $vehicle->id, 'vehicle_id' => $vehicle->id,
'user_id' => auth()->id() ?? null, 'user_id' => auth()->id() ?? null,
]); ]);
//Responder al cliente //Procesar y guardar archivos si existen
$uploadedFiles = [];
if ($request->hasFile('files')) {
$files = $request->file('files');
$fileNames = $request->input('file_names', []);
foreach ($files as $index => $file) {
// Generar nombre único
$fileName = time() . '_' . $index . '_' . $file->getClientOriginalName();
// Guardar archivos
$path = $file->storeAs('records', $fileName, 'public');
// Calcular MD5
$md5 = md5_file($file->getRealPath());
// Crear registro en BD
$fileRecord = File::create([
'name' => $fileNames[$index] ?? "Archivo " . ($index + 1),
'path' => $path,
'md5' => $md5,
'record_id' => $record->id,
]);
$uploadedFiles[] = [
'id' => $fileRecord->id,
'name' => $fileRecord->name,
'path' => $fileRecord->path,
'url' => $fileRecord->url,
];
}
}
// Confirmar transacción
DB::commit();
// Responder con éxito
return ApiResponse::OK->response([ return ApiResponse::OK->response([
'folio' => $folio, 'folio' => $folio,
'stolen' => $isStolen, 'stolen' => false,
'message' => $stolenMessage, 'message' => 'Vehículo inscrito exitosamente',
'record' => [
'id' => $record->id,
'folio' => $record->folio,
'vehicle_id' => $vehicle->id,
'user_id' => $record->user_id,
'created_at' => $record->created_at->toDateTimeString(),
],
'vehicle' => [ 'vehicle' => [
'id' => $vehicle->id, 'id' => $vehicle->id,
'placa' => $vehicleData['PLACA'], 'placa' => $vehicle->placa,
'modelo' => $vehicleData['MODELO'], 'numero_serie' => $vehicle->numero_serie,
'marca' => $vehicleData['MARCA'], 'marca' => $vehicle->marca,
'numero_serie' => $vehicleData['NUMERO_SERIE'], 'modelo' => $vehicle->modelo,
'color' => $vehicleData['COLOR'], 'color' => $vehicle->color,
'tipo' => $vehicleData['TIPO'],
'linea' => $vehicleData['LINEA'],
], ],
'record_id' => $record->id, 'owner' => [
'id' => $owner->id,
'full_name' => $owner->full_name,
'rfc' => $owner->rfc,
],
'files' => $uploadedFiles,
'total_files' => count($uploadedFiles),
]);
} catch (\Exception $e) {
// Revertir transacción en caso de error
DB::rollBack();
// Log del error
Log::error('Error en inscripcionVehiculo: ' . $e->getMessage(), [
'folio' => $folio ?? null,
'trace' => $e->getTraceAsString()
]);
return ApiResponse::BAD_REQUEST->response([
'message' => 'Error al procesar la inscripción del vehículo',
'error' => $e->getMessage(),
]);
}
}
private function checkIfStolen(string $folio): bool
{
// Aquí api servicio de REPUVE
// simulamos con random
return (bool) rand(0, 1);
}
public function consultaExpediente(Request $request)
{
$request->validate([
'folio' => 'required|string',
]);
$folio = $request->input('folio');
// Cargar record con todas sus relaciones
$record = Record::where('folio', $folio)
->with(['vehicle.owner', 'files', 'user'])
->first();
if (!$record) {
return ApiResponse::NOT_FOUND->response([
'message' => 'No se encontró ningún expediente con el folio proporcionado.'
]);
}
return ApiResponse::OK->response([
'record' => [
'id' => $record->id,
'folio' => $record->folio,
'vehicle' => $record->vehicle,
'owner' => $record->vehicle->owner,
'files' => $record->files,
'user' => $record->user,
'created_at' => $record->created_at->toDateTimeString(), 'created_at' => $record->created_at->toDateTimeString(),
]
]); ]);
} }
@ -97,5 +250,17 @@ private function getVehicle(): array
]; ];
} }
private function getOwner(): array
{
return [
'name' => 'Nicolas',
'paternal' => 'Hernandez',
'maternal' => 'Castillo',
'rfc' => 'HECN660509HTCRSC01',
'curp' => 'HECN660509HTCRSC01',
'address' => 'Fracc Pomoca, Calle Armadillo MZ9 LT28',
];
}
} }

View File

@ -0,0 +1,30 @@
<?php
namespace App\Http\Requests\Repuve;
use Illuminate\Foundation\Http\FormRequest;
class FileStoreRequest extends FormRequest
{
public function authorize()
{
return true;
}
public function rules()
{
return [
'name' => 'required|string|max:255',
'file' => 'required|file|mimes:jpeg,png,jpg,pdf|max:10240',
];
}
public function messages()
{
return [
'name.required' => 'El nombre es obligatorio',
'file.required' => 'El archivo es obligatorio',
'file.mimes' => 'El archivo debe ser de tipo: jpeg, png, jpg',
'file.max' => 'El archivo no debe superar los 10MB',
];
}
}

View File

@ -2,7 +2,7 @@
use Illuminate\Foundation\Http\FormRequest; use Illuminate\Foundation\Http\FormRequest;
class VehicleRequest extends FormRequest class VehicleStoreRequest extends FormRequest
{ {
public function authorize(): bool public function authorize(): bool
@ -14,6 +14,10 @@ public function rules(): array
{ {
return [ return [
'folio' => ['required', 'string', 'max:50'], 'folio' => ['required', 'string', 'max:50'],
'files' => ['nullable', 'array', 'min:1'],
'files.*' => ['file', 'mimes:jpeg,png,jpg,pdf', 'max:10240'],
'file_names' => ['nullable', 'array'],
'file_names.*' => ['string', 'max:255'],
]; ];
} }
@ -23,6 +27,10 @@ public function messages(): array
'folio.required' => 'El folio es requerido', 'folio.required' => 'El folio es requerido',
'folio.string' => 'El folio debe ser una cadena de texto', 'folio.string' => 'El folio debe ser una cadena de texto',
'folio.max' => 'El folio no puede exceder 50 caracteres', 'folio.max' => 'El folio no puede exceder 50 caracteres',
'files.array' => 'Los archivos deben ser un array',
'files.*.file' => 'Cada elemento debe ser un archivo válido',
'files.*.mimes' => 'Los archivos deben ser de tipo: jpeg, png, jpg, pdf',
'files.*.max' => 'Cada archivo no debe superar los 10MB',
]; ];
} }
} }

View File

@ -22,4 +22,16 @@ class File extends Model
'url', 'url',
]; ];
public function record()
{
return $this->belongsTo(Record::class);
}
public function url(): Attribute
{
return Attribute::make(
get: fn () => Storage::url($this->path),
);
}
} }

View File

@ -22,4 +22,11 @@ class Owner extends Model
protected $appends = [ protected $appends = [
'full_name', 'full_name',
]; ];
protected function fullName(): Attribute
{
return Attribute::make(
get: fn() => trim("{$this->name} {$this->paternal} {$this->maternal}")
);
}
} }

View File

@ -16,4 +16,18 @@ class Record extends Model
'error_id', 'error_id',
]; ];
public function vehicle()
{
return $this->belongsTo(Vehicle::class);
}
public function user()
{
return $this->belongsTo(User::class);
}
public function files()
{
return $this->hasMany(File::class);
}
} }

View File

@ -12,11 +12,40 @@ class Vehicle extends Model
protected $table = 'vehicle'; protected $table = 'vehicle';
protected $fillable = [ protected $fillable = [
'anio_placa',
'placa', 'placa',
'modelo', 'numero_serie',
'rfc',
'vigencia',
'fecha_impresion',
'qr_hash',
'valido',
'foliotemp',
'nombre',
'nombre2',
'municipio',
'localidad',
'calle',
'calle2',
'tipo',
'tipo_servicio',
'marca', 'marca',
'linea',
'sublinea',
'modelo',
'numero_motor',
'descripcion_origen',
'color',
'codigo_postal',
'serie_folio',
'sfolio',
'nrpv', 'nrpv',
'owner_id', 'owner_id',
]; ];
public function owner()
{
return $this->belongsTo(Owner::class);
}
} }

View File

@ -7,12 +7,12 @@
"license": "MIT", "license": "MIT",
"require": { "require": {
"php": "^8.3", "php": "^8.3",
"barryvdh/laravel-dompdf": "*",
"laravel/framework": "^12.0", "laravel/framework": "^12.0",
"laravel/passport": "^12.4", "laravel/passport": "^12.4",
"laravel/pulse": "^1.4", "laravel/pulse": "^1.4",
"laravel/reverb": "^1.4", "laravel/reverb": "^1.4",
"laravel/tinker": "^2.10", "laravel/tinker": "^2.10",
"mongodb/laravel-mongodb": "^5.0",
"notsoweb/laravel-core": "dev-main", "notsoweb/laravel-core": "dev-main",
"spatie/laravel-permission": "^6.16", "spatie/laravel-permission": "^6.16",
"tightenco/ziggy": "^2.5" "tightenco/ziggy": "^2.5"

1779
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -112,22 +112,6 @@
// 'trust_server_certificate' => env('DB_TRUST_SERVER_CERTIFICATE', 'false'), // 'trust_server_certificate' => env('DB_TRUST_SERVER_CERTIFICATE', 'false'),
], ],
'mongodb' => [
'driver' => 'mongodb',
'dsn' => env('MONGO_DSN', null),
'host' => env('MONGO_HOST', '127.0.0.1'),
'port' => env('MONGO_PORT', '27017'),
'database' => env('MONGO_DATABASE', 'holos'),
'username' => env('MONGO_USERNAME', null),
'password' => env('MONGO_PASSWORD', null),
'options' => [
'ssl' => env('MONGO_SSL', true),
'authSource' => env('MONGO_AUTH_SOURCE', 'admin'),
'retryWrites' => env('MONGO_RETRY_WRITES', true),
'w' => env('MONGO_W', 'majority'),
],
],
], ],
/* /*

View File

@ -15,6 +15,7 @@ services:
- /var/www/repuve-v1/vendor - /var/www/repuve-v1/vendor
networks: networks:
- repuve-network - repuve-network
mem_limit: 400m
depends_on: depends_on:
mysql: mysql:
condition: service_healthy condition: service_healthy
@ -28,6 +29,7 @@ services:
- ./Docker/nginx/nginx.conf:/etc/nginx/conf.d/default.conf - ./Docker/nginx/nginx.conf:/etc/nginx/conf.d/default.conf
networks: networks:
- repuve-network - repuve-network
mem_limit: 400m
depends_on: depends_on:
- repuve-backend - repuve-backend
@ -44,25 +46,12 @@ services:
- mysql_data:/var/lib/mysql - mysql_data:/var/lib/mysql
networks: networks:
- repuve-network - repuve-network
mem_limit: 400m
healthcheck: healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"] test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
timeout: 15s timeout: 15s
retries: 10 retries: 10
mongodb:
image: mongo:7.0
environment:
MONGO_INITDB_ROOT_USERNAME: ${MONGO_USERNAME}
MONGO_INITDB_ROOT_PASSWORD: ${MONGO_PASSWORD}
MONGO_INITDB_DATABASE: ${MONGO_DATABASE}
ports:
- "${MONGO_PORT}:27017"
volumes:
- mongodb_data:/data/db
- mongodb_config:/data/configdb
networks:
- repuve-network
phpmyadmin: phpmyadmin:
image: phpmyadmin/phpmyadmin image: phpmyadmin/phpmyadmin
environment: environment:
@ -74,14 +63,11 @@ services:
- mysql - mysql
networks: networks:
- repuve-network - repuve-network
mem_limit: 400m
volumes: volumes:
mysql_data: mysql_data:
driver: local driver: local
mongodb_data:
driver: local
mongodb_config:
driver: local
networks: networks:
repuve-network: repuve-network:

View File

@ -21,8 +21,6 @@ RUN apt-get update && apt-get install -y\
RUN docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd zip RUN docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd zip
RUN pecl install mongodb && docker-php-ext-enable mongodb
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
COPY composer.json composer.lock ./ COPY composer.json composer.lock ./

2948
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,19 +0,0 @@
{
"private": true,
"type": "module",
"scripts": {
"build": "vite build",
"dev": "vite"
},
"devDependencies": {
"autoprefixer": "^10.4.20",
"axios": "^1.7.4",
"concurrently": "^9.0.1",
"laravel-echo": "^1.17.1",
"laravel-vite-plugin": "^1.0",
"postcss": "^8.4.47",
"pusher-js": "^8.4.0-rc2",
"tailwindcss": "^3.4.13",
"vite": "^5.0"
}
}

View File

@ -0,0 +1,269 @@
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title>Registro Público Vehicular</title>
<style>
@page {
margin: 1.5cm;
}
body {
font-family: Arial, Helvetica, sans-serif;
font-size: 11pt;
line-height: 1.4;
color: #000;
margin: 0;
padding: 0;
}
.container {
width: 100%;
margin: 0 auto;
}
.header {
text-align: center;
border-bottom: 2px solid #000;
padding-bottom: 15px;
margin-bottom: 25px;
}
.header img {
max-height: 110px;
width: auto;
}
.logos-container {
display: table;
width: 100%;
margin-bottom: 20px;
}
.logo-left {
display: table-cell;
width: 25%;
text-align: left;
vertical-align: middle;
}
.logo-right {
display: table-cell;
width: 25%;
text-align: right;
vertical-align: middle;
}
.logo-center {
display: table-cell;
width: 50%;
text-align: center;
vertical-align: middle;
}
.government-section {
margin-bottom: 20px;
}
.government-section h2,
.government-section h3 {
font-size: 11pt;
font-weight: bold;
margin: 2px 0;
text-align: left;
}
.legal-text {
text-align: justify;
font-size: 10pt;
line-height: 1.5;
margin-bottom: 25px;
}
.legal-text p {
margin: 10px 0;
}
.vehicle-number {
font-weight: normal;
font-size: 10pt;
}
.vehicle-number span {
font-weight: bold;
}
.owner-section {
margin: 25px 0;
border: 1px solid #000;
padding: 15px;
}
.owner-section h3 {
font-size: 10pt;
font-weight: bold;
margin-bottom: 12px;
border-bottom: 1px solid #000;
padding-bottom: 5px;
}
.data-row {
margin-bottom: 10px;
font-size: 10pt;
}
.data-label {
font-weight: bold;
display: inline-block;
width: 100px;
}
.address-row {
margin-bottom: 10px;
font-size: 10pt;
}
.date-section {
text-align: center;
margin: 40px 0 80px 0;
font-size: 10pt;
}
.date-section .underline {
text-decoration: underline;
padding: 0 5px;
}
.signatures {
margin-top: 100px;
}
.signature-table {
width: 100%;
border-collapse: collapse;
}
.signature-cell {
width: 50%;
text-align: center;
vertical-align: bottom;
padding: 0 20px;
}
.signature-line {
border-top: 2px solid #000;
width: 250px;
margin: 0 auto 8px auto;
}
.signature-name {
font-size: 10pt;
font-weight: bold;
margin: 3px 0;
}
.signature-role {
font-size: 10pt;
font-weight: bold;
}
</style>
</head>
<body>
<div class="container">
<!-- Header con logo centrado -->
<div class="header">
<?php
$imagePath = storage_path('app/images/logo-seguridad.png');
$imageData = base64_encode(file_get_contents($imagePath));
$imageSrc = 'data:image/png;base64,' . $imageData;
?>
<img src="{{ $imageSrc }}" alt="Logo Seguridad">
</div>
<!-- Encabezados gubernamentales -->
<div class="government-section">
<h2>GOBIERNO DEL ESTADO DE TABASCO</h2>
<h3>SECRETARÍA DE FINANZAS</h3>
<h3>DIRECCIÓN DE INGRESOS</h3>
</div>
<!-- Texto legal -->
<div class="legal-text">
<p>
CON FUNDAMENTO EN LOS ARTÍCULOS 1 Y 7 DE LA LEY DEL REGISTRO PÚBLICO VEHICULAR PUBLICADA EN EL DIARIO
OFICIAL DE LA FEDERACIÓN DE FECHA 1 DE SEPTIEMBRE DE 2004, Y ARTÍCULO 22 DEL REGLAMENTO INTERIOR DE LA
SECRETARÍA DE FINANZAS DEL GOBIERNO DEL ESTADO DE TABASCO, PUBLICADO EN EL PERIÓDICO OFICIAL DEL
ESTADO DE TABASCO DEL 2 DE JUNIO DE 2010, DOY MI MÁS AMPLIO CONSENTIMIENTO A ESTA DEPENDENCIA PARA
QUE SEA VERIFICADO FÍSICAMENTE MI VEHÍCULO CON PLACAS DE CIRCULACIÓN:
</p>
<p class="vehicle-number">
PLACA <span>{{ $record->vehicle->placa }}</span> / NÚMERO DE SERIE <span>{{ $record->vehicle->nrpv }}</span>
</p>
<p>
,ACEPTANDO LAS CONSECUENCIAS QUE DE ESTA VERIFICACIÓN SURJAN, CON OBJETO DE QUE SE ME OTORGUE
CONSTANCIA DE INSCRIPCIÓN Y SE ADHIERA EN MI VEHÍCULO EL HOLOGRAMA DEL REGISTRO PÚBLICO VEHICULAR.
</p>
</div>
<!-- Datos del propietario -->
<div class="owner-section">
<h3>DATOS DE PROPIETARIO</h3>
<div class="data-row">
<span class="data-label">RFC:</span>
<span>{{ $record->vehicle->owner->rfc }}</span>
</div>
<div class="data-row">
<span class="data-label">NOMBRE:</span>
<span>{{$record->vehicle->owner->full_name }} </span>
</div>
<div class="address-row">
<span class="data-label">CALLE:</span>
<span>{{ $record->vehicle->owner->address }}</span>
</div>
<div class="data-row">
<span class="data-label">COLONIA:</span>
<span>{{ $record->vehicle->owner->address }}</span>
</div>
<div class="data-row">
<span class="data-label">MUNICIPIO:</span>
<span>{{ $record->vehicle->municipio }}</span>
</div>
</div>
<!-- Fecha y lugar -->
<div class="date-section">
<p>
VILLAHERMOSA, TAB
<span class="underline">{{ now()->format('d') }}</span> de
<span class="underline">{{ ucfirst(now()->translatedFormat('F')) }}</span> de
<span class="underline">{{ now()->format('Y') }}</span>
</p>
</div>
<!-- Firmas -->
<div class="signatures">
<table class="signature-table">
<tr>
<td class="signature-cell">
<div class="signature-line"></div>
<p class="signature-name">{{ $record->vehicle->owner->full_name }}</p>
<p class="signature-role">Propietario</p>
</td>
<td class="signature-cell">
<div class="signature-line">{{ $record->user->full_name }}</div>
<p class="signature-role">Operador</p>
</td>
</tr>
</table>
</div>
</div>
</body>
</html>

View File

@ -1,6 +1,7 @@
<?php <?php
use Illuminate\Support\Facades\Route; use Illuminate\Support\Facades\Route;
use App\Http\Controllers\Repuve\RepuveController; use App\Http\Controllers\Repuve\RepuveController;
use App\Http\Controllers\Repuve\RecordController;
/** /**
* Rutas del núcleo de la aplicación. * Rutas del núcleo de la aplicación.
@ -19,7 +20,13 @@
/** Rutas protegidas (requieren autenticación) */ /** Rutas protegidas (requieren autenticación) */
Route::middleware('auth:api')->group(function() { Route::middleware('auth:api')->group(function() {
// Tus rutas protegidas // Tus rutas protegidas
Route::post('consultar', [RepuveController::class, 'consultarVehiculo']); Route::post('inscripcion', [RepuveController::class, 'inscripcionVehiculo']);
Route::post('consulta', [RepuveController::class, 'consultaExpediente']);
Route::get('expediente/{id}/pdf', [RecordController::class, 'generatePdf']);
Route::get('expediente/{recordId}/documentos', [RecordController::class, 'getFile']);
Route::post('expediente/documentos', [RecordController::class, 'uploadFile']);
Route::delete('expediente/documentos/{fileId}', [RecordController::class, 'deleteFile']);
}); });
/** Rutas públicas */ /** Rutas públicas */