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:
parent
71788ddd2e
commit
de0ac7a3aa
16
.env.example
16
.env.example
@ -36,22 +36,6 @@ DB_USERNAME=notsoweb
|
||||
DB_PASSWORD=
|
||||
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
|
||||
|
||||
SESSION_DRIVER=database
|
||||
|
||||
117
app/Http/Controllers/Repuve/RecordController.php
Normal file
117
app/Http/Controllers/Repuve/RecordController.php
Normal 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(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,64 +1,217 @@
|
||||
<?php namespace App\Http\Controllers\Repuve;
|
||||
/**
|
||||
* @copyright (c) 2025 Notsoweb Software (https://notsoweb.com) - All Rights Reserved
|
||||
*/
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
use Notsoweb\ApiResponse\Enums\ApiResponse;
|
||||
use App\Http\Requests\Repuve\VehicleRequest;
|
||||
use App\Http\Requests\Repuve\VehicleStoreRequest;
|
||||
use App\Models\Vehicle;
|
||||
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
|
||||
{
|
||||
public function consultarVehiculo(VehicleRequest $request)
|
||||
public function inscripcionVehiculo(VehicleStoreRequest $request)
|
||||
{
|
||||
// La validación por el Request
|
||||
$folio = $request->input('folio');
|
||||
try {
|
||||
// Validar folio
|
||||
$folio = $request->input('folio');
|
||||
|
||||
// Simular consulta de robo
|
||||
$isStolen = (bool) rand(0, 1);
|
||||
$stolenMessage = $isStolen
|
||||
? 'El vehículo reporta robo'
|
||||
: 'El vehículo no reporta robo';
|
||||
// Simular consulta de robo
|
||||
$isStolen = $this->checkIfStolen($folio);
|
||||
|
||||
// Obtener datos del vehículo
|
||||
$vehicleData = $this->getVehicle();
|
||||
// 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.',
|
||||
]);
|
||||
}
|
||||
|
||||
$vehicle = Vehicle::updateOrCreate(
|
||||
['placa' => $vehicleData['PLACA']],
|
||||
[
|
||||
'modelo' => $vehicleData['MODELO'],
|
||||
'marca' => $vehicleData['MARCA'],
|
||||
'nrpv' => $vehicleData['NUMERO_SERIE'],
|
||||
]
|
||||
);
|
||||
// Iniciar transacción
|
||||
DB::beginTransaction();
|
||||
|
||||
// Crear registro con folio + vehicle_id
|
||||
$record = Record::create([
|
||||
'folio' => $folio,
|
||||
'vehicle_id' => $vehicle->id,
|
||||
'user_id' => auth()->id() ?? null,
|
||||
// Obtener datos del vehículo y propietario
|
||||
$vehicleData = $this->getVehicle();
|
||||
$ownerData = $this->getOwner();
|
||||
|
||||
//Crear propietario
|
||||
$owner = Owner::updateOrCreate(
|
||||
['rfc' => $ownerData['rfc']],
|
||||
[
|
||||
'name' => $ownerData['name'],
|
||||
'paternal' => $ownerData['paternal'],
|
||||
'maternal' => $ownerData['maternal'],
|
||||
'curp' => $ownerData['curp'],
|
||||
'address' => $ownerData['address'],
|
||||
]
|
||||
);
|
||||
|
||||
//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([
|
||||
'folio' => $folio,
|
||||
'vehicle_id' => $vehicle->id,
|
||||
'user_id' => auth()->id() ?? null,
|
||||
]);
|
||||
|
||||
//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([
|
||||
'folio' => $folio,
|
||||
'stolen' => false,
|
||||
'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' => [
|
||||
'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,
|
||||
],
|
||||
'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',
|
||||
]);
|
||||
|
||||
//Responder al cliente
|
||||
$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([
|
||||
'folio' => $folio,
|
||||
'stolen' => $isStolen,
|
||||
'message' => $stolenMessage,
|
||||
'vehicle' => [
|
||||
'id' => $vehicle->id,
|
||||
'placa' => $vehicleData['PLACA'],
|
||||
'modelo' => $vehicleData['MODELO'],
|
||||
'marca' => $vehicleData['MARCA'],
|
||||
'numero_serie' => $vehicleData['NUMERO_SERIE'],
|
||||
'color' => $vehicleData['COLOR'],
|
||||
'tipo' => $vehicleData['TIPO'],
|
||||
'linea' => $vehicleData['LINEA'],
|
||||
],
|
||||
'record_id' => $record->id,
|
||||
'created_at' => $record->created_at->toDateTimeString(),
|
||||
'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(),
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
@ -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',
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
30
app/Http/Requests/Repuve/FileStoreRequest.php
Normal file
30
app/Http/Requests/Repuve/FileStoreRequest.php
Normal 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',
|
||||
];
|
||||
}
|
||||
}
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class VehicleRequest extends FormRequest
|
||||
class VehicleStoreRequest extends FormRequest
|
||||
{
|
||||
|
||||
public function authorize(): bool
|
||||
@ -14,6 +14,10 @@ public function rules(): array
|
||||
{
|
||||
return [
|
||||
'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.string' => 'El folio debe ser una cadena de texto',
|
||||
'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',
|
||||
];
|
||||
}
|
||||
}
|
||||
@ -22,4 +22,16 @@ class File extends Model
|
||||
'url',
|
||||
];
|
||||
|
||||
|
||||
public function record()
|
||||
{
|
||||
return $this->belongsTo(Record::class);
|
||||
}
|
||||
|
||||
public function url(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: fn () => Storage::url($this->path),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -22,4 +22,11 @@ class Owner extends Model
|
||||
protected $appends = [
|
||||
'full_name',
|
||||
];
|
||||
|
||||
protected function fullName(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: fn() => trim("{$this->name} {$this->paternal} {$this->maternal}")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,4 +16,18 @@ class Record extends Model
|
||||
'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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -12,11 +12,40 @@ class Vehicle extends Model
|
||||
protected $table = 'vehicle';
|
||||
|
||||
protected $fillable = [
|
||||
'anio_placa',
|
||||
'placa',
|
||||
'modelo',
|
||||
'numero_serie',
|
||||
'rfc',
|
||||
'vigencia',
|
||||
'fecha_impresion',
|
||||
'qr_hash',
|
||||
'valido',
|
||||
'foliotemp',
|
||||
'nombre',
|
||||
'nombre2',
|
||||
'municipio',
|
||||
'localidad',
|
||||
'calle',
|
||||
'calle2',
|
||||
'tipo',
|
||||
'tipo_servicio',
|
||||
'marca',
|
||||
'linea',
|
||||
'sublinea',
|
||||
'modelo',
|
||||
'numero_motor',
|
||||
'descripcion_origen',
|
||||
'color',
|
||||
'codigo_postal',
|
||||
'serie_folio',
|
||||
'sfolio',
|
||||
'nrpv',
|
||||
'owner_id',
|
||||
];
|
||||
|
||||
public function owner()
|
||||
{
|
||||
return $this->belongsTo(Owner::class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -7,12 +7,12 @@
|
||||
"license": "MIT",
|
||||
"require": {
|
||||
"php": "^8.3",
|
||||
"barryvdh/laravel-dompdf": "*",
|
||||
"laravel/framework": "^12.0",
|
||||
"laravel/passport": "^12.4",
|
||||
"laravel/pulse": "^1.4",
|
||||
"laravel/reverb": "^1.4",
|
||||
"laravel/tinker": "^2.10",
|
||||
"mongodb/laravel-mongodb": "^5.0",
|
||||
"notsoweb/laravel-core": "dev-main",
|
||||
"spatie/laravel-permission": "^6.16",
|
||||
"tightenco/ziggy": "^2.5"
|
||||
|
||||
1781
composer.lock
generated
1781
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@ -112,22 +112,6 @@
|
||||
// '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'),
|
||||
],
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
/*
|
||||
|
||||
@ -15,6 +15,7 @@ services:
|
||||
- /var/www/repuve-v1/vendor
|
||||
networks:
|
||||
- repuve-network
|
||||
mem_limit: 400m
|
||||
depends_on:
|
||||
mysql:
|
||||
condition: service_healthy
|
||||
@ -28,6 +29,7 @@ services:
|
||||
- ./Docker/nginx/nginx.conf:/etc/nginx/conf.d/default.conf
|
||||
networks:
|
||||
- repuve-network
|
||||
mem_limit: 400m
|
||||
depends_on:
|
||||
- repuve-backend
|
||||
|
||||
@ -44,25 +46,12 @@ services:
|
||||
- mysql_data:/var/lib/mysql
|
||||
networks:
|
||||
- repuve-network
|
||||
mem_limit: 400m
|
||||
healthcheck:
|
||||
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
|
||||
timeout: 15s
|
||||
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:
|
||||
image: phpmyadmin/phpmyadmin
|
||||
environment:
|
||||
@ -74,14 +63,11 @@ services:
|
||||
- mysql
|
||||
networks:
|
||||
- repuve-network
|
||||
mem_limit: 400m
|
||||
|
||||
volumes:
|
||||
mysql_data:
|
||||
driver: local
|
||||
mongodb_data:
|
||||
driver: local
|
||||
mongodb_config:
|
||||
driver: local
|
||||
|
||||
networks:
|
||||
repuve-network:
|
||||
|
||||
@ -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 pecl install mongodb && docker-php-ext-enable mongodb
|
||||
|
||||
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
|
||||
|
||||
COPY composer.json composer.lock ./
|
||||
|
||||
2948
package-lock.json
generated
2948
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
19
package.json
19
package.json
@ -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"
|
||||
}
|
||||
}
|
||||
269
resources/views/pdfs/record.blade.php
Normal file
269
resources/views/pdfs/record.blade.php
Normal 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>
|
||||
@ -1,6 +1,7 @@
|
||||
<?php
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use App\Http\Controllers\Repuve\RepuveController;
|
||||
use App\Http\Controllers\Repuve\RecordController;
|
||||
|
||||
/**
|
||||
* Rutas del núcleo de la aplicación.
|
||||
@ -19,7 +20,13 @@
|
||||
/** Rutas protegidas (requieren autenticación) */
|
||||
Route::middleware('auth:api')->group(function() {
|
||||
// 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 */
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user