Desacople e inyeccion de dependencias

This commit is contained in:
imnavajas
2025-07-22 16:01:34 +02:00
parent a1aaa095d4
commit 9ed397e9ad
9 changed files with 391 additions and 154 deletions

View File

@ -6,21 +6,22 @@ use CodeIgniter\Config\BaseConfig;
class PresupuestoSFTP extends BaseConfig
{
public string $host;
public int $port;
public string $username;
public string $password;
public string $base_dir; # FTP server directory
public string $base_dir;
public int $id_offset;
public function __construct() {
public function __construct()
{
parent::__construct();
$this->host = env("HIDRIVE_FILES_HOST","sftp.hidrive.ionos.com");
$this->port = env("HIDRIVE_FILES_PORT",22);
$this->host = env("HIDRIVE_FILES_HOST", "sftp.hidrive.ionos.com");
$this->port = (int) env("HIDRIVE_FILES_PORT", 22);
$this->username = env("HIDRIVE_FILES_USER");
$this->password = env("HIDRIVE_FILES_PASS");
$this->base_dir = env("HIDRIVE_FILES_PATH_ROOT"); # FTP server directory
$this->id_offset = env("BUDGET_FILES_OFFSET_ID",1000000);
$this->id_offset = (int) env("BUDGET_FILES_OFFSET_ID", 1000000);
$domain = parse_url(env("app.baseURL"), PHP_URL_HOST);
$this->base_dir = "/users/{$this->username}/{$domain}";
}
}

View File

@ -473,7 +473,6 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
'errors' => $errors
);
return $this->respond($data);
} else {
return $this->failUnauthorized('Invalid request', 403);
}
@ -615,7 +614,7 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
return $this->failServerError(
$return_data['exception'] . ' - ' .
$return_data['file'] . ' - ' . $return_data['line']
$return_data['file'] . ' - ' . $return_data['line']
);
}
@ -733,7 +732,6 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
} else {
return $return_data;
}
} catch (Exception $e) {
if ($this->request) {
if ($this->request->isAJAX())
@ -742,7 +740,6 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
return "Error: " . $e->getMessage();
}
}
}
@ -849,11 +846,9 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
$maxSolapa = (865 - floor($anchoTotal)) / 2;
$maxSolapa = min($maxSolapa, 0.95 * $datosPedido->ancho);
return $this->respond($maxSolapa);
} else {
return $this->failUnauthorized('Invalid request', 403);
}
}
@ -874,7 +869,6 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
'menu' => $data,
$csrfTokenName => $newTokenHash
]);
} else {
return $this->failUnauthorized('Invalid request', 403);
}
@ -1301,7 +1295,6 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
$coste_envio += ($coste_direccion->coste / $tirada[$i]);
$resultado_presupuesto['info']['totales'][$i]['coste_envio'] += $coste_direccion->coste - $coste_direccion->margen;
$resultado_presupuesto['info']['totales'][$i]['margen_envio'] += $coste_direccion->margen;
}
}
$resultado_presupuesto['coste_envio'][$i] = round($coste_envio, 2);
@ -1336,7 +1329,6 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
} else {
$resumen_totales = $resultado_presupuesto['info']['totales'][$i];
$resumen_totales['precio_unidad'] = round($resultado_presupuesto['precio_u'][$i], 4);
}
}
@ -1575,7 +1567,6 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
if (count($direccionesFP1) > 0) {
$this->guardarLineaEnvio($id, $direccionesFP1, $peso_libro, true, true, 1);
}
if (count($direccionesFP2) > 0) {
$this->guardarLineaEnvio($id, $direccionesFP2, $peso_libro, true, true, 2);
@ -1732,7 +1723,7 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
$data['resumen']['base'] = $presupuesto->total_antes_descuento;
$data['resumen']['total_envio'] = round(
floatval($presupuesto->total_coste_envios) +
floatval($presupuesto->total_margen_envios),
floatval($presupuesto->total_margen_envios),
2
);
$data['resumen']['precio_unidad'] = $presupuesto->total_precio_unidad;
@ -1758,39 +1749,37 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
public function get_files()
{
// Check if the request is a POST request
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$presupuesto_id = $this->request->getPost()['presupuesto_id'] ?? 0;
$model = model('App\Models\Presupuestos\PresupuestoFicheroModel');
$files = $model->getFiles($presupuesto_id);
$result = [];
foreach ($files as $file) {
$size = filesize($file->file_path);
$splitPath = explode("presupuestos/", $file->file_path);
// se crea un objeto con el nombre del fichero y el tamaño
$obj = (object) array(
'name' => $file->nombre,
'size' => $size,
'hash' => $splitPath[1] ?? $file->file_path
);
// se añade el objeto al array
array_push($result, $obj);
}
return json_encode($result);
// Aceptar solo POST (puedes cambiar a GET si lo necesitas)
if ($this->request->getMethod(true) !== 'POST') {
return $this->response->setStatusCode(405)->setJSON(['message' => 'Método no permitido']);
}
$presupuesto_id = $this->request->getPost('presupuesto_id') ?? 0;
$model = model('App\Models\Presupuestos\PresupuestoFicheroModel');
$files = $model->getFiles($presupuesto_id);
$result = [];
foreach ($files as $file) {
$relativePath = $file->file_path;
$fullPath = WRITEPATH . ltrim($relativePath, '/');
$relativePath = $file->file_path;
$basename = basename($relativePath); // solo el nombre del archivo
$result[] = (object) [
'name' => $file->nombre,
'size' => file_exists(WRITEPATH . $relativePath) ? filesize(WRITEPATH . $relativePath) : 0,
'hash' => $basename
];
}
return $this->response->setJSON($result);
}
public function upload_files()
public function upload_files_old()
{
$model = model('App\Models\Presupuestos\PresupuestoFicheroModel');
@ -1843,6 +1832,74 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
return json_encode(['message' => 'Archivos subidos correctamente']);
}
public function upload_files()
{
$request = service('request');
$model = model('App\Models\Presupuestos\PresupuestoFicheroModel');
$files = $request->getFiles()['file'] ?? [];
$presupuesto_id = $request->getPost('presupuesto_id');
$old_files = json_decode($request->getPost('oldFiles') ?? '[]');
if (!is_array($files)) {
$files = [$files];
}
// Instanciar servicio con dependencias inyectadas manualmente
$service = new \App\Services\PresupuestoUploaderService(
new \App\Libraries\SftpClientWrapper(config('PresupuestoSFTP')),
$model,
config('PresupuestoSFTP')
);
// Borrar antiguos del SFTP y de la BD (pero no del disco local)
$service->removeFromRemote($presupuesto_id);
$model->deleteMissingFiles($presupuesto_id, $old_files);
$results = [];
foreach ($files as $file) {
if (!$file->isValid()) {
$results[] = ['name' => $file->getName(), 'status' => 'invalid'];
continue;
}
$newName = $model->saveFileInBBDD(
$presupuesto_id,
$file->getClientName(),
$file->getClientExtension(),
auth()->id()
);
$uploadPath = WRITEPATH . 'uploads/presupuestos/' . $newName;
$file->move(dirname($uploadPath), basename($uploadPath));
$results[] = ['name' => $file->getClientName(), 'status' => 'uploaded'];
}
// Subida al SFTP
$sftpResult = $service->uploadToRemote($presupuesto_id);
// Preparar notificación
if (!$sftpResult['success']) {
return $this->response->setJSON([
'message' => 'Error al subir uno o más archivos al SFTP.',
'details' => [
'local' => $results,
'sftp' => $sftpResult['files']
]
])->setStatusCode(500);
}
return $this->response->setJSON([
'message' => 'Archivos subidos correctamente al sistema y al SFTP.',
'details' => [
'local' => $results,
'sftp' => $sftpResult['files']
]
]);
}
@ -1936,6 +1993,7 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
{
if ($tipo == 'encuadernacion') {
$model = new PresupuestoEncuadernacionesModel();
$data = [
@ -2212,7 +2270,6 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
$totalImpresion,
$margenImpresion
);
}
}
@ -2274,7 +2331,6 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
$totalImpresion,
$margenImpresion
);
}
}
}
@ -2345,7 +2401,7 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
return $return_data;
}
$cantidad_total = intval($datosPedido->tirada);// + intval($datosPedido->merma);
$cantidad_total = intval($datosPedido->tirada); // + intval($datosPedido->merma);
// Acabado Cubierta
if (intval($datos_entrada['cubierta']['acabado']) != 0) {
@ -2385,7 +2441,6 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
$margenServicios += round(floatval($acabadoCubierta[0]->total - $base), 2);
}
}
}
if ($lomoRedondo) {
@ -2422,7 +2477,6 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
$base = round(floatval($base / $cantidad_total), 2) * $cantidad_total;
$totalServicios += $base;
$margenServicios += round(floatval($resultado[0]->total - $base), 2);
}
}
@ -2460,7 +2514,6 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
$totalImpresion,
$margenImpresion
);
}
if ($coste_sobrecubierta <= 0) {
@ -2674,7 +2727,6 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
$base = round(floatval($base / $cantidad_total), 2) * $cantidad_total;
$totalServicios += $base;
$margenServicios += round(floatval($acabadoFaja[0]->total - $base), 2);
}
}
}
@ -2729,7 +2781,6 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
$base = round(floatval($base / $cantidad_total), 2) * $cantidad_total;
$totalServicios += $base;
$margenServicios += round(floatval($servicio->total - $base), 2);
}
$servDefectoMan = PresupuestoCLienteService::getServiciosManipuladoDefault([
@ -2872,7 +2923,6 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
$base = round(floatval($base / $cantidad_total), 2) * $cantidad_total;
$totalServicios += $base;
$margenServicios += round(floatval($resultado[0]->total - $base), 2);
} else if ($servicio->nombre == "ferro" || $servicio->nombre == "prototipo") {
// Extra
$resultado = PresupuestoCLienteService::getServiciosExtra([
@ -2905,7 +2955,6 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
$base = round(floatval($base / $cantidad_total), 2) * $cantidad_total;
$totalServicios += $base;
$margenServicios += round(floatval($resultado[0]->total - $base), 2);
} else if ($servicio->nombre == 'solapas_cubierta' || $servicio->nombre == 'solapas_sobrecubierta' || $servicio->nombre == 'solapas_faja') {
// Servicios manipulado
$resultado = PresupuestoCLienteService::getServiciosManipulado([
@ -2982,7 +3031,6 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
$totalServicios += $base;
$margenServicios += round(floatval($resultado[0]->precio - $base), 2);
}
}
// Plegado de solapas grandes
@ -3222,7 +3270,6 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
$margenImpresion += round($linea['margen_impresion_horas'], 2);
$margenImpresion += round($linea['margen_click_pedido'], 2);
$margenImpresion = round($margenImpresion, 2);
}
protected function calcular_lomo($lineas, $lomo_inicial)
@ -3342,8 +3389,7 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
$color = 'negro';
$model = model('App\Models\Presupuestos\PresupuestoLineaModel');
$data = $model->where('presupuesto_id', $presupuestoId)->findAll();
;
$data = $model->where('presupuesto_id', $presupuestoId)->findAll();;
foreach ($data as $linea) {
if (strpos($linea->tipo, "hq") !== false) { // $linea->tipo contains the substring "hq"
@ -3696,7 +3742,4 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
return $this->response->setStatusCode(500)->setBody('Error interno');
}
}
}

View File

@ -15,25 +15,24 @@ use App\Models\Catalogo\CatalogoLibroModel;
use App\Services\PresupuestoService;
use CodeIgniter\Shield\Entities\User;
use App\Libraries\SftpClientWrapper;
use Config\PresupuestoSFTP;
class Test extends BaseController
{
function __construct()
{
}
function __construct() {}
public function echo()
{
echo "echo";
}
public function index()
{
}
@ -75,10 +74,8 @@ class Test extends BaseController
// Insert it
$tel_model->insert($tarifasLinea);
}
}
}
@ -224,7 +221,6 @@ class Test extends BaseController
} else {
$values = [];
}
}

View File

@ -0,0 +1,43 @@
<?php
namespace App\Libraries;
use phpseclib3\Net\SFTP;
use Config\PresupuestoSFTP;
class SftpClientWrapper
{
protected SFTP $client;
public function __construct(PresupuestoSFTP $config)
{
$this->client = new SFTP($config->host, $config->port);
$this->client->login($config->username, $config->password);
}
public function upload(string $local, string $remote): bool
{
return $this->client->put($remote, $local, SFTP::SOURCE_LOCAL_FILE);
}
public function delete(string $remote): bool
{
return $this->client->delete($remote);
}
public function exists(string $remote): bool
{
return $this->client->file_exists($remote);
}
public function mkdir(string $remote): bool
{
return $this->client->mkdir($remote, true);
}
public function chmod(string $path, int $permissions): bool
{
return $this->client->chmod($permissions, $path);
}
}

View File

@ -32,7 +32,7 @@ class PresupuestoFicheroModel extends \App\Models\BaseModel
$this->db->table($this->table . " t1")
->set('presupuesto_id', $presupuesto_id)
->set('nombre', $filename)
->set('file_path', WRITEPATH . 'uploads/presupuestos/' . $new_filename)
->set('file_path', 'uploads/presupuestos/' . $new_filename)
->set('upload_by', $user_id)
->set('upload_at', date('Y-m-d H:i:s'))
->insert();
@ -54,8 +54,9 @@ class PresupuestoFicheroModel extends \App\Models\BaseModel
// se comprueba que el $file->nombre no sea igual a ninguno de los elementos del array $old_files
if (!in_array($file->nombre, $old_files)) {
if (file_exists($file->file_path)) {
unlink($file->file_path);
$fullPath = WRITEPATH . $file->file_path;
if (file_exists($fullPath)) {
unlink($fullPath);
}
$this->db
@ -76,20 +77,23 @@ class PresupuestoFicheroModel extends \App\Models\BaseModel
->table($this->table . " t1")
->where('presupuesto_id', $presupuesto_id_origen)->get()->getResult();
if ($files) {
foreach ($files as $file) {
$hash = $this->generateFileHash($file->nombre);
// se copia el fichero a la nueva ubicación
if (!file_exists(WRITEPATH . $file->file_path)) {
copy($file->file_path, WRITEPATH . 'uploads/presupuestos/' . $hash);
$originalPath = WRITEPATH . $file->file_path;
$newPath = 'uploads/presupuestos/' . $hash;
if (file_exists($originalPath)) {
copy($originalPath, WRITEPATH . $newPath);
}
$this->db->table($this->table . " t1")
->set('presupuesto_id', $presupuesto_id_destino)
->set('nombre', $file->nombre)
->set('file_path', WRITEPATH . 'uploads/presupuestos/' . $hash)
->set('file_path', $newPath)
->set('upload_by', auth()->user()->id)
->set('upload_at', date('Y-m-d H:i:s'))
->insert();
@ -105,6 +109,25 @@ class PresupuestoFicheroModel extends \App\Models\BaseModel
->where('presupuesto_id', $presupuesto_id)->get()->getResult();
}
public function deleteMissingFiles(int $presupuesto_id, array $keepNames = [])
{
$files = $this->getFiles($presupuesto_id);
foreach ($files as $file) {
if (!in_array($file->nombre, $keepNames)) {
$fullPath = WRITEPATH . $file->file_path;
if (file_exists($fullPath)) {
unlink($fullPath);
}
$this->db->table($this->table)
->where('presupuesto_id', $presupuesto_id)
->where('nombre', $file->nombre)
->delete();
}
}
}
/**
* Función para convertir el nombre y extensión de un fichero en un hash único
@ -117,6 +140,4 @@ class PresupuestoFicheroModel extends \App\Models\BaseModel
{
return hash('sha256', $filename);
}
}

View File

@ -0,0 +1,76 @@
<?php
namespace App\Services;
use App\Models\Presupuestos\PresupuestoFicheroModel;
use App\Models\Pedidos\PedidoLineaModel;
use App\Libraries\SftpClientWrapper;
use Config\PresupuestoSFTP;
class PresupuestoUploaderService
{
public function __construct(
protected SftpClientWrapper $ftp,
protected PresupuestoFicheroModel $fileModel,
protected PresupuestoSFTP $config
) {}
public function uploadToRemote(int $presupuestoId): array
{
$remoteDir = "{$this->config->base_dir}/ficheros/" . ($presupuestoId + $this->config->id_offset);
if (!$this->ftp->exists($remoteDir)) {
if (!$this->ftp->mkdir($remoteDir, true)) {
return [
'success' => false,
'message' => "No se pudo crear el directorio remoto: $remoteDir"
];
}
$this->ftp->chmod($remoteDir, 0755);
}
$files = $this->fileModel->getFiles($presupuestoId);
$results = [];
foreach ($files as $file) {
$remotePath = $remoteDir . '/' . basename($file->file_path);
$localPath = WRITEPATH . $file->file_path;
$ok = $this->ftp->upload($localPath, $remotePath);
$results[] = [
'file' => $file->nombre,
'remotePath' => $remotePath,
'success' => $ok
];
}
$allOk = !in_array(false, array_column($results, 'success'));
return [
'success' => $allOk,
'files' => $results
];
}
public function removeFromRemote(int $presupuestoId): void
{
$remoteDir = "{$this->config->base_dir}/pedidos_files/" . ($presupuestoId + $this->config->id_offset);
$files = $this->fileModel->getFiles($presupuestoId);
foreach ($files as $file) {
$this->ftp->delete($remoteDir . '/' . basename($file->file_path));
}
}
public function removeMissingFromRemote(int $presupuestoId, array $keepFileNames): void
{
$remoteDir = "{$this->config->base_dir}/pedidos_files/" . ($presupuestoId + $this->config->id_offset);
$files = $this->fileModel->getFiles($presupuestoId);
foreach ($files as $file) {
if (!in_array($file->nombre, $keepFileNames)) {
$this->ftp->delete($remoteDir . '/' . basename($file->file_path));
}
}
}
}