61 Commits

Author SHA1 Message Date
f44da0c2b7 Merge branch 'feat/config_cabezada' into 'main'
Feat/config cabezada

See merge request jjimenez/safekat!893
2025-07-25 12:14:50 +00:00
2a3cab872b Correccion de bugs 2025-07-25 14:14:21 +02:00
e642f0520a Añadido configurador 2025-07-25 13:41:40 +02:00
200e45c898 Merge branch 'feat/iskn_presupuestos' into 'main'
Feat/iskn presupuestos

See merge request jjimenez/safekat!892
2025-07-25 10:37:25 +00:00
266241b260 Añadida a vista de presupuesto admin iskn. Asignacion automatica al confirmar presupuesto 2025-07-25 12:33:30 +02:00
94222790df Añadimos ISKN 2025-07-25 11:39:20 +02:00
e43a7b7304 Merge branch 'mod/remove_xml_export' into 'main'
Mod/remove xml export

See merge request jjimenez/safekat!891
2025-07-23 12:08:12 +00:00
5e954ae350 Implementado en Bubok 2025-07-23 14:02:59 +02:00
afe9f6e0e3 Corregida rutas 2025-07-23 11:58:18 +02:00
e65e942e58 Refactorizacion 2025-07-23 11:56:43 +02:00
065903be2f Cambio de naming en labels 2025-07-22 22:53:07 +02:00
9ed397e9ad Desacople e inyeccion de dependencias 2025-07-22 16:01:34 +02:00
a1aaa095d4 Eliminado mecanismo de pasar a XML pedido 2025-07-21 21:55:27 +02:00
41ac08fcd8 Merge branch 'fix/production_environment_calcular_pre_cliente' into 'main'
arreglado que el presupuesto de cliente en produccion añada precios de todo

See merge request jjimenez/safekat!889
2025-07-21 11:53:56 +00:00
709a802db4 arreglado que el presupuesto de cliente en produccion añada precios de todo 2025-07-21 13:53:32 +02:00
5e8a36a345 Merge branch 'fix/problema_calcular' into 'main'
prueba

See merge request jjimenez/safekat!888
2025-07-21 10:07:12 +00:00
54816180df prueba 2025-07-21 12:05:39 +02:00
0a8ecdb939 Merge branch 'feat/delete_permission' into 'main'
Implementado control de permiso de borrado

See merge request jjimenez/safekat!887
2025-07-19 19:54:42 +00:00
e3c4cf48ed Implementado control de permiso de borrado 2025-07-19 21:54:09 +02:00
1d7f2e044f Merge branch 'fix/add_group' into 'main'
Fix/add group

See merge request jjimenez/safekat!886
2025-07-19 07:11:56 +00:00
702e6bf77c Permisos items configuracion 2025-07-19 09:11:27 +02:00
599fce7f2f Permisos paises 2025-07-18 21:15:56 +02:00
e01b824045 Avances 2025-07-18 16:31:46 +02:00
cc757b5db3 Blindado rol root en seguridad 2025-07-18 12:36:22 +02:00
df21b5ba05 Merge branch 'feat/costes_colapsables' into 'main'
Añadida fucionalidad de tener por defecto el detalle de costes cerrados

See merge request jjimenez/safekat!885
2025-07-18 09:02:52 +00:00
2639fe705e Añadida fucionalidad de tener por defecto el detalle de costes cerrados 2025-07-18 10:54:56 +02:00
3f65c9e92a Merge branch 'fix/ot_zip_naming' into 'main'
Diferenciar naming en base a donde se invoca la descarga, OT vs PRESUPUESTO

See merge request jjimenez/safekat!884
2025-07-17 12:18:12 +00:00
e804aa3768 Diferenciar naming en base a donde se invoca la descarga, OT vs PRESUPUESTO 2025-07-17 14:17:42 +02:00
f73472c729 Merge branch 'feat/users_per_rol' into 'main'
Implementado listado visual de los usuarios que pertenecen a un rol

See merge request jjimenez/safekat!883
2025-07-16 09:06:15 +00:00
4ffd280302 Implementado listado visual de los usuarios que pertenecen a un rol 2025-07-16 11:05:13 +02:00
d1cbb8eb24 Merge branch 'feat/actualizador_clientes' into 'main'
Creado importador por CLI para actualizar clientes desde el ERP antiguo

See merge request jjimenez/safekat!882
2025-07-15 13:16:49 +00:00
3f6037de76 Creado importador por CLI para actualizar clientes desde el ERP antiguo 2025-07-15 15:03:39 +02:00
619fd9beba Merge branch 'mod/tipo_papel_generico' into 'main'
Mod/tipo papel generico

See merge request jjimenez/safekat!881
2025-07-15 09:01:29 +00:00
e69503c273 añadida funcionalidad tipo papel generico 2025-07-15 11:00:44 +02:00
6a3a825b26 incluida la migración del papel generico 2025-07-15 09:52:15 +02:00
1ef6d476fe Merge branch 'mod/ot_pdf_numero' into 'main'
Cambiada la logica de descargas multiples/simple de OTs

See merge request jjimenez/safekat!880
2025-07-14 13:25:56 +00:00
2f6e27d4ca Cambiada la logica de descargas multiples/simple de OTs 2025-07-14 15:15:16 +02:00
38f6656842 Merge branch 'fix/backups_restore_dev' into 'main'
Fix/backups restore dev

See merge request jjimenez/safekat!879
2025-07-14 12:23:24 +00:00
d31830cf1a Cambiados datos de conexion para BKs 2025-07-14 14:22:38 +02:00
f40e88ed6e Avances 2025-07-10 15:02:55 +02:00
7e7b39fc38 Merge branch 'fix/new_chat_users' into 'main'
Arreglado problema al listar usuarios con select

See merge request jjimenez/safekat!878
2025-07-09 11:22:03 +00:00
6c94858d8c Arreglado problema al listar usuarios con select 2025-07-09 11:48:27 +02:00
c79ae6245c Merge branch 'fix/api_calcular_presu_prod' into 'main'
Solucionado extra_info

See merge request jjimenez/safekat!877
2025-07-08 11:36:39 +00:00
107e66a2be Solucionado extra_info 2025-07-08 13:35:52 +02:00
be3e9a47c2 Merge branch 'mod/direcciones_ferro_prototipo' into 'main'
funcionalidad completa de ferro prototipo en cliente a excepción de guardar...

See merge request jjimenez/safekat!876
2025-07-04 11:11:33 +00:00
45ec831f8f terminado a falta de pruebas las direcciones fp en admin 2025-07-04 12:34:10 +02:00
9aa7d2e0cb arreglados links de preview en presu admin 2025-07-03 12:16:45 +02:00
40391405eb añadido fijo de lomo interior en las funciones getcostelinea y getcostelinearotativa 2025-07-02 14:24:26 +02:00
7bfe9c002a arreglado el cambio del tipo de libro para que recalcule el presupuesto 2025-07-02 14:14:21 +02:00
d5c51f2063 corregido el tamaño maximo de solapas cuando se añade un presu 2025-07-02 11:43:59 +02:00
61d8dca583 corregido direcciones borran precio 2025-07-02 11:15:35 +02:00
e257a3516e Merge branch 'main' into mod/direcciones_ferro_prototipo 2025-07-01 14:25:35 +02:00
18b96f020b Merge branch 'main' into mod/direcciones_ferro_prototipo 2025-07-01 11:55:26 +02:00
8a32e13eb4 Merge branch 'main' into mod/direcciones_ferro_prototipo 2025-06-30 16:27:59 +02:00
813e5b1980 traidos cambios del main 2025-06-30 12:24:31 +02:00
ee9e3eb143 trabajando en presupuesto admin 2025-06-30 11:45:44 +02:00
5c34316bc2 se muestra un alert cuando se quiere añadir una direccion de la principal al ferro que no está en el de cliente. Arrteglado problema con los checks al guardar presupuesto 2025-06-30 10:03:16 +02:00
91f22fd3fb Merge branch 'main' into mod/direcciones_ferro_prototipo 2025-06-30 08:51:03 +02:00
bdb1d1aaec modificado fichero ajax para tener getpromise 2025-06-28 20:17:15 +02:00
bdc0252c72 carga de checks de misma direccion FP implementados en presupuesto cliente 2025-06-28 20:09:37 +02:00
47eafa75ec funcionalidad completa de ferro prototipo en cliente a excepción de guardar los checks de usar la misma dirección 2025-06-28 18:15:49 +02:00
106 changed files with 3762 additions and 1847 deletions

View File

@ -14,4 +14,5 @@
"username": "sk_imn"
}
]
}

View File

@ -0,0 +1,274 @@
<?php
namespace App\Commands;
use CodeIgniter\CLI\BaseCommand;
use CodeIgniter\CLI\CLI;
class ClienteImportar extends BaseCommand
{
protected $group = 'Safekat';
protected $name = 'cliente:importar';
protected $description = 'Importa registros desde customers a clientes solo si no existen por ID';
public function run(array $params)
{
$db = \Config\Database::connect();
$accion = $params[0] ?? 'todo';
// Mapeo de provincias
$provincias = $db->table('lg_provincias')
->select('id, nombre')
->get()
->getResultArray();
$provinciaMap = [];
foreach ($provincias as $provincia) {
$clave = trim(mb_strtolower($provincia['nombre']));
$provinciaMap[$clave] = $provincia['id'];
}
if (in_array($accion, ['clientes', 'todo'])) {
// ⬅️ aquí va tu bloque actual de importación de clientes
$insertados = 0;
$omitidos = 0;
CLI::write("Iniciando importación de clientes por ID...", 'yellow');
$clientes = $db->table('customers')
->where('deleted_at', null)
->get()
->getResultArray();
if (empty($clientes)) {
CLI::write('No se encontraron registros en "customers".', 'red');
return;
}
foreach ($clientes as $cliente) {
$id = (int) $cliente['id'];
// Verifica si ya existe en la tabla destino
$yaExiste = $db->table('clientes')->where('id', $id)->countAllResults();
if ($yaExiste) {
$omitidos++;
CLI::write("Cliente ID $id ya existe. Omitido.", 'blue');
continue;
}
$datos = [
'id' => $id,
'nombre' => $cliente['name'],
'alias' => $cliente['alias'],
'cif' => $cliente['cif'],
'direccion' => $cliente['direccion'],
'ciudad' => $cliente['ciudad'],
'comunidad_autonoma_id' => $cliente['comunidad_autonoma_id'],
'provincia_id' => $this->getProvinciaId($cliente['provincia'], $provinciaMap),
'cp' => $cliente['cp'],
'pais_id' => $cliente['pais_id'],
'telefono' => $cliente['telefono'],
'email' => $cliente['email'],
'comercial_id' => 122,
'soporte_id' => 122,
'forma_pago_id' => ($cliente['forma_pago_id'] > 6) ? 1 : $cliente['forma_pago_id'], // Si no se reconoce fijar a transferencias
'vencimiento' => $cliente['vencimiento'],
'fecha_vencimiento' => $cliente['fechaVencimiento'],
'margen' => $cliente['margen'],
'descuento' => $cliente['descuento'],
'limite_credito' => $cliente['limite_credito'],
'limite_credito_user_id' => $cliente['limite_credito_user_id'],
'limite_credito_change_at' => $cliente['limite_credito_change_at'],
'credito_asegurado' => $cliente['creditoAsegurado'],
'ccc' => $cliente['ccc'],
'ccc_cliente' => $cliente['ccc_customer'],
'num_cuenta' => $cliente['num_cuenta'],
'message_tracking' => $cliente['message_tracking'],
'message_production_start' => $cliente['message_production_start'],
'tirada_flexible' => $cliente['tirada_flexible'],
'descuento_tirada_flexible' => $cliente['descuento_tirada_flexible'],
'comentarios_tirada_flexible' => $cliente['comentarios_tirada_flexible'],
'margen_plantilla_id' => $cliente['margen_plantilla_id'],
'comentarios' => $cliente['comentarios'],
'deleted_at' => null,
'created_at' => date('Y-m-d H:i:s'),
'updated_at' => date('Y-m-d H:i:s'),
'user_created_id' => 10,
'user_update_id' => 10,
'no_envio_base' => 0,
'forzar_rotativa_pod' => 0,
];
try {
$db->table('clientes')->insert($datos);
$insertados++;
CLI::write("Cliente ID $id insertado correctamente.", 'green');
} catch (\Throwable $e) {
CLI::error("❌ Error al insertar cliente ID $id: " . $e->getMessage());
CLI::error("📦 Datos del cliente: " . json_encode($datos, JSON_PRETTY_PRINT));
$omitidos++;
continue;
}
}
CLI::write("Importación completada.", 'green');
CLI::write("Clientes insertados: $insertados", 'green');
CLI::write("Clientes ya existentes: $omitidos", 'blue');
}
if (in_array($accion, ['direcciones', 'todo'])) {
// ⬅️ aquí va tu bloque actual de importación de direcciones
CLI::write("Iniciando importación de direcciones...", 'yellow');
$direcciones = $db->table('customers_address')
->where('deleted_at', null)
->get()
->getResultArray();
$direccionesInsertadas = 0;
$direccionesOmitidas = 0;
foreach ($direcciones as $dir) {
$clienteId = (int) $dir['customer_id'];
$clienteExiste = $db->table('clientes')
->where('id', $clienteId)
->countAllResults();
if (!$clienteExiste) {
CLI::write("⚠️ Dirección ID {$dir['id']} omitida: cliente_id $clienteId no existe.", 'blue');
$direccionesOmitidas++;
continue;
}
$direccionExiste = $db->table('cliente_direcciones')
->where([
'cliente_id' => $clienteId,
'direccion' => $dir['direccion'] ?? '',
'cp' => $dir['cp'] ?? '0',
'municipio' => $dir['ciudad'] ?? '',
'provincia' => $dir['provincia'],
])
->countAllResults();
if ($direccionExiste) {
CLI::write("⚠️ Dirección ID {$dir['id']} ya existe para cliente $clienteId. Omitida.", 'blue');
$direccionesOmitidas++;
continue;
}
$nuevaDir = [
'cliente_id' => $clienteId,
'alias' => $dir['nombre'] ?? '',
'att' => $dir['persona_contacto'] ?? '',
'email' => $dir['email'],
'direccion' => $dir['direccion'] ?? '',
'pais_id' => is_numeric($dir['pais_id']) ? (int) $dir['pais_id'] : null,
'provincia' => $dir['provincia'],
'municipio' => $dir['ciudad'] ?? '',
'cp' => $dir['cp'] ?? '0',
'telefono' => $dir['telefono'],
];
try {
$db->table('cliente_direcciones')->insert($nuevaDir);
$direccionesInsertadas++;
CLI::write("✅ Dirección ID {$dir['id']} insertada para cliente $clienteId", 'green');
} catch (\Throwable $e) {
CLI::error("❌ Error al insertar dirección ID {$dir['id']} (cliente_id $clienteId): " . $e->getMessage());
$direccionesOmitidas++;
}
}
CLI::write("Importación de direcciones finalizada.", 'green');
CLI::write("Direcciones insertadas: $direccionesInsertadas", 'green');
CLI::write("Direcciones omitidas: $direccionesOmitidas", 'blue');
}
if (in_array($accion, ['contactos', 'todo'])) {
CLI::write("Iniciando importación de contactos...", 'yellow');
$contactos = $db->table('customers_contact')
->where('deleted_at', null)
->get()
->getResultArray();
$contactosInsertados = 0;
$contactosOmitidos = 0;
foreach ($contactos as $contacto) {
$clienteId = (int) $contacto['customer_id'];
// Verificar si cliente existe
$clienteExiste = $db->table('clientes')
->where('id', $clienteId)
->countAllResults();
if (!$clienteExiste) {
CLI::write("⚠️ Contacto ID {$contacto['id']} omitido: cliente_id $clienteId no existe.", 'blue');
$contactosOmitidos++;
continue;
}
// Validación para evitar duplicados básicos
$yaExiste = $db->table('cliente_contactos')
->where([
'cliente_id' => $clienteId,
'email' => $contacto['email'],
'nombre' => $contacto['nombre']
])
->countAllResults();
if ($yaExiste) {
CLI::write("⚠️ Contacto ID {$contacto['id']} ya existe para cliente $clienteId. Omitido.", 'blue');
$contactosOmitidos++;
continue;
}
$nuevoContacto = [
'cliente_id' => $clienteId,
'cargo' => $contacto['cargo'],
'nombre' => $contacto['nombre'],
'apellidos' => $contacto['apellidos'],
'telefono' => $contacto['telefono'],
'email' => $contacto['email'],
'deleted_at' => null,
'created_at' => date('Y-m-d H:i:s'),
'updated_at' => date('Y-m-d H:i:s'),
];
try {
$db->table('cliente_contactos')->insert($nuevoContacto);
$contactosInsertados++;
CLI::write("✅ Contacto ID {$contacto['id']} insertado para cliente $clienteId", 'green');
} catch (\Throwable $e) {
CLI::error("❌ Error al insertar contacto ID {$contacto['id']}: " . $e->getMessage());
$contactosOmitidos++;
}
}
CLI::write("Importación de contactos finalizada.", 'green');
CLI::write("Contactos insertados: $contactosInsertados", 'green');
CLI::write("Contactos omitidos: $contactosOmitidos", 'blue');
}
}
private function getProvinciaId(?string $nombre, array $map): ?int
{
if ($nombre === null) {
return null;
}
$clave = trim(mb_strtolower($nombre));
return $map[$clave] ?? null;
}
}

View File

@ -72,4 +72,21 @@ class Paths
* is used when no value is provided to `Services::renderer()`.
*/
public string $viewDirectory = __DIR__ . '/../Views';
/**
* Ruta base relativa dentro de WRITEPATH donde se almacenan
* los archivos asociados a presupuestos.
*
* Esta ruta se utiliza como base para componer las rutas
* completas tanto locales como remotas (SFTP) de ficheros
* relacionados con cada presupuesto.
*
* Ejemplo:
* Si el ID del presupuesto es 123 y el nombre del archivo es "documento.pdf",
* la ruta final será: storage/presupuestos/123/documento.pdf
*
* Se recomienda mantener esta ruta fuera de `public/` por razones de seguridad
* y utilizar controladores para servir los archivos si se desea acceso web.
*/
public string $presupuestosPath = 'storage/presupuestos';
}

View File

@ -1,29 +0,0 @@
<?php
namespace Config;
use CodeIgniter\Config\BaseConfig;
class PedidoXML extends BaseConfig
{
public string $host;
public int $port;
public string $username;
public string $password;
public string $base_dir; # FTP server directory
public bool $xml_enabled;
public int $id_offset;
public function __construct() {
parent::__construct();
$this->host = env("HIDRIVE_HOST","10.5.0.6");
$this->port = env("HIDRIVE_PORT",21);
$this->username = env("HIDRIVE_USER","admin");
$this->password = env("HIDRIVE_PASS","A77h3b0X4OA2rOYAf4w2");
$this->base_dir = env("HIDRIVE_PATH_ROOT","/home/admin/safekat"); # FTP server directory
$this->xml_enabled = env("FTP_XML_ENABLED",false);
$this->id_offset = env("XML_OFFSET_CUSTOMER_ID",1000000);
}
}

View File

@ -0,0 +1,38 @@
<?php
namespace Config;
use CodeIgniter\Config\BaseConfig;
class PresupuestoSFTP extends BaseConfig
{
public string $host;
public int $port;
public string $username;
public string $password;
public string $base_dir;
public string $remote_base_dir = 'ficheros'; // subcarpeta específica para presupuestos
public int $id_offset;
public function __construct()
{
parent::__construct();
$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->id_offset = (int) env("BUDGET_FILES_OFFSET_ID", 1000000);
// Directorio base remoto: /users/usuario/dominio
$domain = parse_url(env("app.baseURL"), PHP_URL_HOST);
$this->base_dir = "/users/{$this->username}/{$domain}";
}
/**
* Devuelve la ruta completa del directorio remoto para un presupuesto
*/
public function getRemoteDirForPresupuesto(int $presupuestoId): string
{
return "{$this->base_dir}/{$this->remote_base_dir}/" . ($presupuestoId + $this->id_offset);
}
}

View File

@ -500,7 +500,6 @@ $routes->group('pedidos', ['namespace' => 'App\Controllers\Pedidos'], function (
$routes->post('cambiarestado', 'Pedido::cambiarEstado', ['as' => 'cambiarEstadoPedido']);
$routes->post('update/(:any)', 'Pedido::update/$1', ['as' => 'actualizarPedido']);
$routes->post('insertfactura', 'Pedido::addFactura');
$routes->get('xml/(:num)', 'Pedido::get_xml_pedido/$1', ['as' => 'getXMLPedido']);
$routes->post('produccion/(:num)', 'Pedido::to_produccion/$1', ['as' => 'toProduccion']);
$routes->get('pedidosCliente', 'Pedido::tablaClienteForm');
$routes->get('getSumCliente/(:num)', 'Pedido::obtenerTotalPedidosCliente/$1');

View File

@ -69,4 +69,10 @@ $routes->group('importador', ['namespace' => 'App\Controllers\Presupuestos'], fu
$routes->get('getencuadernacion', 'Importadorpresupuestos::getEncuadernacionList');
$routes->get('getpresupuestodata', 'Importadorpresupuestos::getPresupuesto', ['as' => 'getPresupuesto']);
$routes->post('importar', 'Importadorpresupuestos::importarPresupuesto');
});
$routes->group('files', ['namespace' => 'App\Controllers\Presupuestos'], function($routes) {
$routes->post('get_files', 'PresupuestoFicheroController::get_files', ['as' => 'getFiles']);
$routes->post('upload_files', 'PresupuestoFicheroController::upload_files', ['as' => 'uploadFiles']);
$routes->post('download_zip', 'PresupuestoFicheroController::download_zip', ['as' => 'downloadFilesZipped']);
});

View File

@ -11,6 +11,7 @@ use App\Services\PapelImpresionService;
use CodeIgniter\Config\BaseService;
use App\Services\ProductionService;
use App\Services\TarifaMaquinaService;
use App\Services\PapelService;
use CodeIgniter\Email\Email;
/**
@ -39,6 +40,9 @@ class Services extends BaseService
* }
*/
public static function papel(){
return new PapelService();
}
public static function production(){
return new ProductionService();
}

View File

@ -77,6 +77,14 @@ abstract class BaseResourceController extends \CodeIgniter\RESTful\ResourceContr
*/
public $alertStyle = 'alerts';
/**
* Permiso requerido para borrar. Si es false/null, no se valida.
* Si es un string (nombre del permiso), se valida.
*
* @var string|false|null
*/
protected $deletePermission = false;
/**
* An array of helpers to be loaded automatically upon
@ -222,6 +230,13 @@ abstract class BaseResourceController extends \CodeIgniter\RESTful\ResourceContr
*/
public function delete($id = null)
{
// 🔒 Verificar permiso solo si está definido como string
if (is_string($this->deletePermission) && !auth()->user()->can($this->deletePermission)) {
$message = lang('Basic.global.permissionDenied'); // O el mensaje que uses
return $this->failWithNewToken($message, 403); // Estilo coherente con tu clase
}
if (!empty(static::$pluralObjectNameCc) && !empty(static::$singularObjectNameCc)) {
$objName = mb_strtolower(lang(ucfirst(static::$pluralObjectNameCc) . '.' . static::$singularObjectNameCc));
} else {
@ -236,8 +251,10 @@ abstract class BaseResourceController extends \CodeIgniter\RESTful\ResourceContr
} else {
$datetime = (new \CodeIgniter\I18n\Time("now"));
$rawResult = $this->model->where('id', $id)
->set(['deleted_at' => $datetime->format('Y-m-d H:i:s'),
'is_deleted' => $this->delete_flag])
->set([
'deleted_at' => $datetime->format('Y-m-d H:i:s'),
'is_deleted' => $this->delete_flag
])
->update();
if (!$rawResult) {
return $this->failNotFound(lang('Basic.global.deleteError', [$objName]));
@ -270,7 +287,8 @@ abstract class BaseResourceController extends \CodeIgniter\RESTful\ResourceContr
}
if ($customValidationMessages == null) {
$validationErrorMessages = $this->model->validationMessages ?? $this->formValidationErrorMessagess ?? null;;
$validationErrorMessages = $this->model->validationMessages ?? $this->formValidationErrorMessagess ?? null;
;
} else {
$validationErrorMessages = $customValidationMessages;
}
@ -366,12 +384,12 @@ abstract class BaseResourceController extends \CodeIgniter\RESTful\ResourceContr
$queryStr = !is_null($query) ? $query->getQuery() : '';
$dbError = $this->model->db->error();
$userFriendlyErrMsg = lang('Basic.global.persistErr1', [static::$singularObjectNameCc]);
if (isset($dbError['code']) && $dbError['code'] == 1062) :
if (isset($dbError['code']) && $dbError['code'] == 1062):
$userFriendlyErrMsg .= PHP_EOL . lang('Basic.global.persistDuplErr', [static::$singularObjectNameCc]);
endif;
// $userFriendlyErrMsg = str_replace("'", "\'", $userFriendlyErrMsg); // Uncomment if experiencing unescaped single quote errors
log_message('error', $userFriendlyErrMsg . PHP_EOL . $e->getMessage() . PHP_EOL . $queryStr);
if (isset($dbError['message']) && !empty($dbError['message'])) :
if (isset($dbError['message']) && !empty($dbError['message'])):
log_message('error', $dbError['code'] . ' : ' . $dbError['message']);
endif;
$this->viewData['errorMessage'] = $userFriendlyErrMsg;

View File

@ -61,11 +61,13 @@ class ChatController extends BaseController
$this->chatService = service("chat");
}
public function index() {}
public function get_chat_departments(string $model,int $modelId)
public function index()
{
}
public function get_chat_departments(string $model, int $modelId)
{
$data = $this->chatService->getChatDepartments($model,$modelId);
$data = $this->chatService->getChatDepartments($model, $modelId);
return $this->response->setJSON($data);
}
@ -250,7 +252,7 @@ class ChatController extends BaseController
public function store_message($model)
{
$data = $this->request->getPost();
$chatMessageEntity = $this->chatService->storeChatMessage($data["chat_department_id"],$model,$data["model_id"],$data);
$chatMessageEntity = $this->chatService->storeChatMessage($data["chat_department_id"], $model, $data["model_id"], $data);
return $this->response->setJSON($chatMessageEntity);
}
@ -341,22 +343,26 @@ class ChatController extends BaseController
}
public function get_chat_users_internal()
{
$query = $this->userModel->builder()->select(
[
"id",
"CONCAT(first_name,' ',last_name,'(',username,')') as name"
]
)->where("cliente_id", null)
->where("deleted_at", null)
->whereNotIn("id", [auth()->user()->id]);
if ($this->request->getGet("q")) {
$query->groupStart()
->orLike("users.username", $this->request->getGet("q"))
->orLike("CONCAT(first_name,' ',last_name)", $this->request->getGet("q"))
$builder = $this->userModel->builder();
$builder->select([
'users.id',
"CONCAT(first_name, ' ', last_name, ' (', auth_identities.secret, ')') AS name"
])
->join('auth_identities', 'auth_identities.user_id = users.id AND auth_identities.type = "email_password"')
->where('cliente_id', null)
->where('deleted_at', null)
->whereNotIn('users.id', [auth()->user()->id]);
if ($this->request->getGet('q')) {
$q = $this->request->getGet('q');
$builder->groupStart()
->orLike('auth_identities.secret', $q)
->orLike("CONCAT(first_name, ' ', last_name)", $q)
->groupEnd();
}
return $this->response->setJSON($query->get()->getResultObject());
return $this->response->setJSON($builder->get()->getResultObject());
}
public function get_chat_users_all()
{
@ -381,7 +387,7 @@ class ChatController extends BaseController
$pm = model(PresupuestoModel::class);
$p = $pm->find($presupuesto_id);
$cm = model(ClienteModel::class);
$clienteContactos = $cm->querySelectClienteContacto($p->cliente_id,$this->request->getGet('q'));
$clienteContactos = $cm->querySelectClienteContacto($p->cliente_id, $this->request->getGet('q'));
return $this->response->setJSON($clienteContactos);
}
public function get_pedido_client_users(int $pedido_id)
@ -389,7 +395,7 @@ class ChatController extends BaseController
$pm = model(PedidoModel::class);
$p = $pm->find($pedido_id);
$cm = model(ClienteModel::class);
$clienteContactos = $cm->querySelectClienteContacto($p->cliente()->id,$this->request->getGet('q'));
$clienteContactos = $cm->querySelectClienteContacto($p->cliente()->id, $this->request->getGet('q'));
return $this->response->setJSON($clienteContactos);
}
public function get_factura_client_users(int $factura_id)
@ -397,7 +403,7 @@ class ChatController extends BaseController
$fm = model(FacturaModel::class);
$f = $fm->find($factura_id);
$cm = model(ClienteModel::class);
$clienteContactos = $cm->querySelectClienteContacto($f->cliente_id,$this->request->getGet('q'));
$clienteContactos = $cm->querySelectClienteContacto($f->cliente_id, $this->request->getGet('q'));
return $this->response->setJSON($clienteContactos);
}
public function get_orden_trabajo_client_users(int $orden_trabajo_id)
@ -406,21 +412,21 @@ class ChatController extends BaseController
$ot = $otm->find($orden_trabajo_id);
$cm = model(ClienteModel::class);
$cliente = $ot->pedido()->cliente();
$clienteContactos = $cm->querySelectClienteContacto($cliente->id,$this->request->getGet('q'));
$clienteContactos = $cm->querySelectClienteContacto($cliente->id, $this->request->getGet('q'));
return $this->response->setJSON($clienteContactos);
}
public function store_hebra(string $model)
{
$auth_user = auth()->user();
$bodyData = $this->request->getPost();
$status = $this->chatService->storeHebra($model,$bodyData['modelId'],$bodyData);
$status = $this->chatService->storeHebra($model, $bodyData['modelId'], $bodyData);
return $this->response->setJSON(["message" => "Hebra creada correctamente", "status" => $status]);
}
public function update_hebra($chat_id)
{
$bodyData = $this->request->getPost();
$chatMessageId = $this->chatMessageModel->insert([
$chatMessageId = $this->chatMessageModel->insert([
"chat_id" => $chat_id,
"message" => $bodyData["message"],
"sender_id" => auth()->user()->id
@ -441,9 +447,9 @@ class ChatController extends BaseController
}
return $this->response->setJSON(["message" => "Hebra actualizada correctamente", "status" => true]);
}
public function get_hebra(string $model,int $modelId)
public function get_hebra(string $model, int $modelId)
{
$data = $this->chatService->getHebras($model,$modelId);
$data = $this->chatService->getHebras($model, $modelId);
return $this->response->setJSON($data);
}
@ -456,8 +462,8 @@ class ChatController extends BaseController
return DataTable::of($query)
->edit('created_at', fn($q) => Time::createFromFormat('Y-m-d H:i:s', $q->created_at)->format("d/m/Y H:i"))
->edit('updated_at', fn($q) => Time::createFromFormat('Y-m-d H:i:s', $q->updated_at)->format("d/m/Y H:i"))
->edit("creator",fn($q) => $q->userId == $auth_user_id ? '<span class="badge text-bg-success w-100">'.lang("App.me").'</span>' : $q->creator)
->add("viewed", fn($q) => $this->chatModel->isMessageChatViewed($q->id, $auth_user_id))
->edit("creator", fn($q) => $q->userId == $auth_user_id ? '<span class="badge text-bg-success w-100">' . lang("App.me") . '</span>' : $q->creator)
->add("viewed", fn($q) => $this->chatModel->isMessageChatViewed($q->id, $auth_user_id))
->add("action", fn($q) => [
"type" => "direct",
"modelId" => $q->id,
@ -478,12 +484,18 @@ class ChatController extends BaseController
return DataTable::of($query)
->edit('created_at', fn($q) => $q->created_at ? Time::createFromFormat('Y-m-d H:i:s', $q->created_at)->format("d/m/Y H:i") : "")
->edit('updated_at', fn($q) => $q->updated_at ? Time::createFromFormat('Y-m-d H:i:s', $q->updated_at)->format("d/m/Y H:i") : "")
->add("viewed", fn($q) => $this->chatModel->isMessageChatViewed($q->chatMessageId))
->edit("creator",fn($q) => $q->userId == $auth_user_id ? '<span class="badge text-bg-success w-100">'.lang("App.me").'</span>' : $q->creator)
->add("action", fn($q) => ["type" => "presupuesto", "modelId" => $q->id, "isAdmin" => $isAdmin,"chatMessageId" => $q->chatMessageId, "lang" => [
"view_chat" => lang('Chat.view_chat'),
"view_by_alt_message" => lang('Chat.view_by_alt_message')
]])
->add("viewed", fn($q) => $this->chatModel->isMessageChatViewed($q->chatMessageId))
->edit("creator", fn($q) => $q->userId == $auth_user_id ? '<span class="badge text-bg-success w-100">' . lang("App.me") . '</span>' : $q->creator)
->add("action", fn($q) => [
"type" => "presupuesto",
"modelId" => $q->id,
"isAdmin" => $isAdmin,
"chatMessageId" => $q->chatMessageId,
"lang" => [
"view_chat" => lang('Chat.view_chat'),
"view_by_alt_message" => lang('Chat.view_by_alt_message')
]
])
->toJson(true);
}
public function datatable_pedido_messages()
@ -494,12 +506,18 @@ class ChatController extends BaseController
return DataTable::of($query)
->edit('created_at', fn($q) => $q->created_at ? Time::createFromFormat('Y-m-d H:i:s', $q->created_at)->format("d/m/Y H:i") : "")
->edit('updated_at', fn($q) => $q->updated_at ? Time::createFromFormat('Y-m-d H:i:s', $q->updated_at)->format("d/m/Y H:i") : "")
->edit("creator",fn($q) => $q->userId == $auth_user_id ? '<span class="badge text-bg-success w-100">'.lang("App.me").'</span>' : $q->creator)
->add("viewed", fn($q) => $this->chatModel->isMessageChatViewed($q->chatMessageId))
->add("action", fn($q) => ["type" => "pedido", "modelId" => $q->id, "isAdmin" => $isAdmin,"chatMessageId" => $q->chatMessageId, "lang" => [
"view_chat" => lang('Chat.view_chat'),
"view_by_alt_message" => lang('Chat.view_by_alt_message')
]])
->edit("creator", fn($q) => $q->userId == $auth_user_id ? '<span class="badge text-bg-success w-100">' . lang("App.me") . '</span>' : $q->creator)
->add("viewed", fn($q) => $this->chatModel->isMessageChatViewed($q->chatMessageId))
->add("action", fn($q) => [
"type" => "pedido",
"modelId" => $q->id,
"isAdmin" => $isAdmin,
"chatMessageId" => $q->chatMessageId,
"lang" => [
"view_chat" => lang('Chat.view_chat'),
"view_by_alt_message" => lang('Chat.view_by_alt_message')
]
])
->toJson(true);
}
@ -511,12 +529,18 @@ class ChatController extends BaseController
return DataTable::of($query)
->edit('created_at', fn($q) => $q->created_at ? Time::createFromFormat('Y-m-d H:i:s', $q->created_at)->format("d/m/Y H:i") : "")
->edit('updated_at', fn($q) => $q->updated_at ? Time::createFromFormat('Y-m-d H:i:s', $q->updated_at)->format("d/m/Y H:i") : "")
->edit("creator",fn($q) => $q->userId == $auth_user_id ? '<span class="badge text-bg-success w-100">'.lang("App.me").'</span>' : $q->creator)
->add("viewed", fn($q) => $this->chatModel->isMessageChatViewed($q->chatMessageId))
->add("action", fn($q) => ["type" => "factura", "modelId" => $q->id, "isAdmin" => $isAdmin,"chatMessageId" => $q->chatMessageId, "lang" => [
"view_chat" => lang('Chat.view_chat'),
"view_by_alt_message" => lang('Chat.view_by_alt_message')
]])
->edit("creator", fn($q) => $q->userId == $auth_user_id ? '<span class="badge text-bg-success w-100">' . lang("App.me") . '</span>' : $q->creator)
->add("viewed", fn($q) => $this->chatModel->isMessageChatViewed($q->chatMessageId))
->add("action", fn($q) => [
"type" => "factura",
"modelId" => $q->id,
"isAdmin" => $isAdmin,
"chatMessageId" => $q->chatMessageId,
"lang" => [
"view_chat" => lang('Chat.view_chat'),
"view_by_alt_message" => lang('Chat.view_by_alt_message')
]
])
->toJson(true);
}
@ -528,29 +552,41 @@ class ChatController extends BaseController
return DataTable::of($query)
->edit('created_at', fn($q) => $q->created_at ? Time::createFromFormat('Y-m-d H:i:s', $q->created_at)->format("d/m/Y H:i") : "")
->edit('updated_at', fn($q) => $q->updated_at ? Time::createFromFormat('Y-m-d H:i:s', $q->updated_at)->format("d/m/Y H:i") : "")
->edit("creator",fn($q) => $q->userId == $auth_user_id ? '<span class="badge text-bg-success w-100">'.lang("App.me").'</span>' : $q->creator)
->add("viewed", fn($q) => $this->chatModel->isMessageChatViewed($q->chatMessageId))
->add("action", fn($q) => ["type" => "ot", "modelId" => $q->id, "isAdmin" => $isAdmin,"chatMessageId" => $q->chatMessageId, "lang" => [
"view_chat" => lang('Chat.view_chat'),
"view_by_alt_message" => lang('Chat.view_by_alt_message')
]])
->edit("creator", fn($q) => $q->userId == $auth_user_id ? '<span class="badge text-bg-success w-100">' . lang("App.me") . '</span>' : $q->creator)
->add("viewed", fn($q) => $this->chatModel->isMessageChatViewed($q->chatMessageId))
->add("action", fn($q) => [
"type" => "ot",
"modelId" => $q->id,
"isAdmin" => $isAdmin,
"chatMessageId" => $q->chatMessageId,
"lang" => [
"view_chat" => lang('Chat.view_chat'),
"view_by_alt_message" => lang('Chat.view_by_alt_message')
]
])
->toJson(true);
}
public function datatable_direct_messages()
{
$auth_user_id = auth()->user()->id;
$auth_user_id = auth()->user()->id;
$isAdmin = auth()->user()->inGroup('admin');
$query = $this->chatModel->getQueryDatatableDirectMessages($auth_user_id);
return DataTable::of($query)
->edit('created_at', fn($q) => $q->created_at ? Time::createFromFormat('Y-m-d H:i:s', $q->created_at)->format("d/m/Y H:i") : "")
->edit('updated_at', fn($q) => $q->updated_at ? Time::createFromFormat('Y-m-d H:i:s', $q->updated_at)->format("d/m/Y H:i") : "")
->edit("creator",fn($q) => $q->userId == $auth_user_id ? '<span class="badge text-bg-success w-100">'.lang("App.me").'</span>' : $q->creator)
->add("viewed", fn($q) => $this->chatModel->isMessageChatViewed($q->chatMessageId))
->add("action", fn($q) => ["type" => "direct", "modelId" => $q->id, "isAdmin" => $isAdmin,"chatMessageId" => $q->chatMessageId, "lang" => [
"view_chat" => lang('Chat.view_chat'),
"view_by_alt_message" => lang('Chat.view_by_alt_message')
]])
->edit("creator", fn($q) => $q->userId == $auth_user_id ? '<span class="badge text-bg-success w-100">' . lang("App.me") . '</span>' : $q->creator)
->add("viewed", fn($q) => $this->chatModel->isMessageChatViewed($q->chatMessageId))
->add("action", fn($q) => [
"type" => "direct",
"modelId" => $q->id,
"isAdmin" => $isAdmin,
"chatMessageId" => $q->chatMessageId,
"lang" => [
"view_chat" => lang('Chat.view_chat'),
"view_by_alt_message" => lang('Chat.view_by_alt_message')
]
])
->toJson(true);
}
@ -651,14 +687,15 @@ class ChatController extends BaseController
{
$bodyData = $this->request->getPost();
$auth_user = auth()->user();
$bodyData["sender_id"] = $auth_user->id;
$bodyData["sender_id"] = $auth_user->id;
$chat_message_id = $this->chatMessageModel->insert($bodyData);
$users_id = $this->chatUserModel->getChatUserArrayId($chat_id);
foreach ($users_id as $user_id) {
if ($user_id != $auth_user->id) {
$this->chatNotificationModel->insert(["chat_message_id" => $chat_message_id, "user_id" => $user_id]);
}
};
}
;
$message = $this->chatMessageModel->get_chat_message($chat_message_id);
return $this->response->setJSON($message);
}
@ -747,7 +784,7 @@ class ChatController extends BaseController
}
public function chat_department_edit($chat_department_id)
{
$chatDepartment = $this->chatDeparmentModel->find($chat_department_id);
$chatDepartment = $this->chatDeparmentModel->find($chat_department_id);
$this->viewData['breadcrumb'] = [
['title' => lang("App.menu_configuration"), 'route' => 'javascript:void(0);', 'active' => false],
['title' => lang("App.menu_config_messages"), 'route' => route_to("configMessagesIndex"), 'active' => false],

View File

@ -25,6 +25,7 @@ class Proveedores extends \App\Controllers\BaseResourceController {
protected $indexRoute = 'proveedorList';
protected $deletePermission = 'proveedores.delete';
public function initController(\CodeIgniter\HTTP\RequestInterface $request, \CodeIgniter\HTTP\ResponseInterface $response, \Psr\Log\LoggerInterface $logger) {

View File

@ -26,6 +26,8 @@ class FormasPago extends \App\Controllers\BaseResourceController
protected $indexRoute = 'formaDePagoList';
protected $deletePermission = 'formas-pago.delete';
public function initController(\CodeIgniter\HTTP\RequestInterface $request, \CodeIgniter\HTTP\ResponseInterface $response, \Psr\Log\LoggerInterface $logger)
{
@ -44,6 +46,7 @@ class FormasPago extends \App\Controllers\BaseResourceController
public function index()
{
checkPermission('formas-pago.menu');
$viewData = [
'currentModule' => static::$controllerSlug,
@ -61,6 +64,7 @@ class FormasPago extends \App\Controllers\BaseResourceController
public function add()
{
checkPermission('formas-pago.create');
if ($this->request->getPost()) :
@ -115,6 +119,7 @@ class FormasPago extends \App\Controllers\BaseResourceController
public function edit($requestedId = null)
{
checkPermission('formas-pago.edit');
if ($requestedId == null) :
return $this->redirect2listView();

View File

@ -21,6 +21,8 @@ class Group extends \App\Controllers\GoBaseController
protected $indexRoute = 'userGroupList';
protected $deletePermission = 'roles-permisos.delete';
public function initController(\CodeIgniter\HTTP\RequestInterface $request, \CodeIgniter\HTTP\ResponseInterface $response, \Psr\Log\LoggerInterface $logger)
{
self::$viewPath = getenv('theme.path') . 'form/group/';
@ -37,6 +39,8 @@ class Group extends \App\Controllers\GoBaseController
public function index()
{
checkPermission('roles-permisos.menu');
$this->viewData['usingClientSideDataTable'] = true;
$this->viewData['pageSubTitle'] = lang('Basic.global.ManageAllRecords', [lang('Groups.group')]);
// IMN
@ -48,11 +52,12 @@ class Group extends \App\Controllers\GoBaseController
public function add()
{
checkPermission('roles-permisos.create');
if ($this->request->getPost()) :
$postData = $this->request->getPost();
$temp_data['id'] = $groupEntity->id;
$temp_data['title'] = $postData['title'];
$temp_data['description'] = $postData['description'];
@ -124,6 +129,7 @@ class Group extends \App\Controllers\GoBaseController
public function edit($requestedId = null)
{
checkPermission('roles-permisos.edit');
helper('general');
@ -243,30 +249,4 @@ class Group extends \App\Controllers\GoBaseController
}
}
public function menuItems()
{
if ($this->request->isAJAX()) {
$searchStr = goSanitize($this->request->getPost('searchTerm'))[0];
$reqId = goSanitize($this->request->getPost('id'))[0];
$reqText = goSanitize($this->request->getPost('text'))[0];
$onlyActiveOnes = false;
$columns2select = [$reqId ?? 'id', $reqText ?? 'nombre'];
$onlyActiveOnes = false;
$menu = $this->model->getSelect2MenuItems($columns2select, $columns2select[1], $onlyActiveOnes, $searchStr);
$nonItem = new \stdClass;
$nonItem->id = '';
$nonItem->text = '- ' . lang('Basic.global.None') . ' -';
array_unshift($menu, $nonItem);
$newTokenHash = csrf_hash();
$csrfTokenName = csrf_token();
$data = [
'menu' => $menu,
$csrfTokenName => $newTokenHash
];
return $this->respond($data);
} else {
return $this->failUnauthorized('Invalid request', 403);
}
}
}

View File

@ -28,6 +28,7 @@ class Maquinas extends \App\Controllers\BaseResourceController
protected static $viewPath = 'themes/vuexy/form/configuracion/maquinas/';
protected $indexRoute = 'maquinaList';
protected MaquinaService $maquinaService;
protected Validation $validation;
@ -55,6 +56,7 @@ class Maquinas extends \App\Controllers\BaseResourceController
public function index()
{
checkPermission('maquinas.menu');
$viewData = [
'currentModule' => static::$controllerSlug,
@ -112,6 +114,8 @@ class Maquinas extends \App\Controllers\BaseResourceController
public function add()
{
checkPermission('maquinas.create');
if ($this->request->getPost()):
$nullIfEmpty = true; // !(phpversion() >= '8.1');
@ -176,7 +180,7 @@ class Maquinas extends \App\Controllers\BaseResourceController
public function edit($requestedId = null)
{
checkPermission('maquinas.edit');
if ($requestedId == null):
return $this->redirect2listView();

View File

@ -28,6 +28,8 @@ class Maquinasdefecto extends \App\Controllers\BaseResourceController
protected $indexRoute = 'maquinaPorDefectoList';
protected $deletePermission = 'maquinas-defecto.delete';
public function initController(\CodeIgniter\HTTP\RequestInterface $request, \CodeIgniter\HTTP\ResponseInterface $response, \Psr\Log\LoggerInterface $logger)
{
@ -45,6 +47,7 @@ class Maquinasdefecto extends \App\Controllers\BaseResourceController
public function index()
{
checkPermission('maquinas-defecto.menu');
$viewData = [
'currentModule' => static::$controllerSlug,
@ -63,7 +66,7 @@ class Maquinasdefecto extends \App\Controllers\BaseResourceController
public function add()
{
checkPermission('maquinas-defecto.create');
if ($this->request->getPost()) :
@ -138,6 +141,7 @@ class Maquinasdefecto extends \App\Controllers\BaseResourceController
public function edit($requestedId = null)
{
checkPermission('maquinas-defecto.edit');
if ($requestedId == null) :
return $this->redirect2listView();

View File

@ -100,6 +100,7 @@ class Maquinaspapelesimpresion extends \App\Controllers\BaseResourceController {
$resourceData = $this->model->getResource($search, $isRotativa, $tarifas, $maquina_id)
->orderBy($order, $dir)->orderBy($order2, $dir2)->orderBy($order3, $dir3)->orderBy($order4, $dir4)->limit($length, $start)->get()->getResultObject();
$query =$this->model->getLastQuery();
return $this->respond(Collection::datatable(
$resourceData,
$this->model->getResource("", $isRotativa, $tarifas, $maquina_id)->countAllResults(),

View File

@ -29,6 +29,7 @@ class Paises extends \App\Controllers\BaseResourceController
protected $indexRoute = 'paisList';
protected $deletePermission = 'paises.delete';
public function initController(\CodeIgniter\HTTP\RequestInterface $request, \CodeIgniter\HTTP\ResponseInterface $response, \Psr\Log\LoggerInterface $logger)
{
@ -47,6 +48,7 @@ class Paises extends \App\Controllers\BaseResourceController
public function index()
{
checkPermission('paises.menu');
$viewData = [
'currentModule' => static::$controllerSlug,
@ -65,6 +67,8 @@ class Paises extends \App\Controllers\BaseResourceController
public function add()
{
checkPermission('paises.create');
if ($this->request->getPost()):
$postData = $this->request->getPost();
@ -119,6 +123,7 @@ class Paises extends \App\Controllers\BaseResourceController
public function edit($requestedId = null)
{
checkPermission('paises.edit');
if ($requestedId == null):
return $this->redirect2listView();

View File

@ -28,6 +28,7 @@ class Papelesgenericos extends \App\Controllers\BaseResourceController
protected $indexRoute = 'papelGenericoList';
protected $deletePermission = 'papel-generico.delete';
public function initController(\CodeIgniter\HTTP\RequestInterface $request, \CodeIgniter\HTTP\ResponseInterface $response, \Psr\Log\LoggerInterface $logger)
@ -40,6 +41,8 @@ class Papelesgenericos extends \App\Controllers\BaseResourceController
// Se indica el flag para los ficheros borrados
$this->delete_flag = 1;
$this->papelService = service('papel');
// Breadcrumbs (IMN)
$this->viewData['breadcrumb'] = [
['title' => lang("App.menu_configuration"), 'route' => "javascript:void(0);", 'active' => false],
@ -52,6 +55,7 @@ class Papelesgenericos extends \App\Controllers\BaseResourceController
public function index()
{
checkPermission('papel-generico.menu');
$viewData = [
'currentModule' => static::$controllerSlug,
@ -69,10 +73,7 @@ class Papelesgenericos extends \App\Controllers\BaseResourceController
public function add()
{
checkPermission('papel-generico.create');
if ($this->request->getPost()):
@ -120,9 +121,11 @@ class Papelesgenericos extends \App\Controllers\BaseResourceController
endif; // $noException && $successfulResult
endif; // ($requestMethod === 'post')
$this->viewData['papelGenerico'] = isset($sanitizedData) ? new PapelGenerico($sanitizedData) : new PapelGenerico();
$this->viewData['tipoPapelGenericoList'] = $this->papelService->getTipoPapelGenerico();
$this->viewData['formAction'] = route_to('createPapelGenerico');
$this->viewData['boxTitle'] = lang('Basic.global.addNew') . ' ' . lang('PapelGenerico.moduleTitle') . ' ' . lang('Basic.global.addNewSuffix');
@ -132,6 +135,7 @@ class Papelesgenericos extends \App\Controllers\BaseResourceController
public function edit($requestedId = null)
{
checkPermission('papel-generico.edit');
if ($requestedId == null):
return $this->redirect2listView();
@ -145,7 +149,6 @@ class Papelesgenericos extends \App\Controllers\BaseResourceController
endif;
if ($this->request->getPost()):
$nullIfEmpty = true; // !(phpversion() >= '8.1');
@ -211,6 +214,8 @@ class Papelesgenericos extends \App\Controllers\BaseResourceController
$this->viewData['papelGenerico'] = $papelGenerico;
$this->viewData['tipoPapelGenericoList'] = $this->papelService->getTipoPapelGenerico();
$this->viewData['formAction'] = route_to('updatePapelGenerico', $id);
$this->viewData['boxTitle'] = lang('Basic.global.edit2') . ' ' . lang('PapelGenerico.moduleTitle') . ' ' . lang('Basic.global.edit3');

View File

@ -52,6 +52,9 @@ class Papelesimpresion extends \App\Controllers\BaseResourceController
protected static $viewPath = 'themes/vuexy/form/configuracion/papel/';
protected $indexRoute = 'papelImpresionList';
protected $deletePermission = 'papel-impresion.delete';
protected Validation $validation;
public function initController(\CodeIgniter\HTTP\RequestInterface $request, \CodeIgniter\HTTP\ResponseInterface $response, \Psr\Log\LoggerInterface $logger)
@ -81,6 +84,7 @@ class Papelesimpresion extends \App\Controllers\BaseResourceController
public function index()
{
checkPermission('papel-impresion.menu');
$viewData = [
'currentModule' => static::$controllerSlug,
@ -98,7 +102,7 @@ class Papelesimpresion extends \App\Controllers\BaseResourceController
public function add()
{
checkPermission('papel-impresion.create');
if ($this->request->getPost()) :
@ -161,6 +165,7 @@ class Papelesimpresion extends \App\Controllers\BaseResourceController
public function edit($requestedId = null)
{
checkPermission('papel-impresion.edit');
if ($requestedId == null) :
return $this->redirect2listView();

View File

@ -22,6 +22,8 @@ class SeriesFacturas extends BaseResourceController
protected $indexRoute = 'seriesFacturasList';
protected $deletePermission = 'series-facturas.delete';
public function initController(\CodeIgniter\HTTP\RequestInterface $request, \CodeIgniter\HTTP\ResponseInterface $response, \Psr\Log\LoggerInterface $logger)
{
@ -40,6 +42,7 @@ class SeriesFacturas extends BaseResourceController
public function index()
{
checkPermission('series-facturas.menu');
$viewData = [
'currentModule' => static::$controllerSlug,
@ -57,6 +60,8 @@ class SeriesFacturas extends BaseResourceController
public function add()
{
checkPermission('series-facturas.create');
if ($this->request->getPost()) :
$postData = $this->request->getPost();
@ -110,6 +115,8 @@ class SeriesFacturas extends BaseResourceController
public function edit($requestedId = null)
{
checkPermission('series-facturas.edit');
if ($requestedId == null) :
return $this->redirect2listView();
endif;

View File

@ -22,6 +22,8 @@ class Ubicaciones extends BaseResourceController
protected $indexRoute = 'ubicacionesList';
protected $deletePermission = 'ubicaciones.delete';
public function initController(\CodeIgniter\HTTP\RequestInterface $request, \CodeIgniter\HTTP\ResponseInterface $response, \Psr\Log\LoggerInterface $logger)
{
@ -40,6 +42,7 @@ class Ubicaciones extends BaseResourceController
public function index()
{
checkPermission('ubicaciones.menu');
$viewData = [
'currentModule' => static::$controllerSlug,
@ -57,6 +60,8 @@ class Ubicaciones extends BaseResourceController
public function add()
{
checkPermission('ubicaciones.create');
if ($this->request->getPost()) :
$postData = $this->request->getPost();
@ -111,6 +116,7 @@ class Ubicaciones extends BaseResourceController
public function edit($requestedId = null)
{
checkPermission('ubicaciones.edit');
if ($requestedId == null) :
return $this->redirect2listView();

View File

@ -69,7 +69,7 @@ class Users extends \App\Controllers\GoBaseController
public function add()
{
if ($this->request->getPost()) :
if ($this->request->getPost()):
$postData = $this->request->getPost();
@ -94,8 +94,8 @@ class Users extends \App\Controllers\GoBaseController
// Obtener proveedor de usuarios
$users = auth()->getProvider();
if ($successfulResult = $this->canValidate()) :
if ($this->canValidate()) :
if ($successfulResult = $this->canValidate()):
if ($this->canValidate()):
try {
// The Email is unique
@ -134,17 +134,12 @@ class Users extends \App\Controllers\GoBaseController
$thenRedirect = true; // Change this to false if you want your user to stay on the form after submission
endif;
if ($noException && $successfulResult) :
if ($noException && $successfulResult):
$id = $users->getInsertID();
$this->group_user_model->where('user_id', $id)->delete();
foreach ($currentGroups as $group) {
$group_user_data = [
'user_id' => $id,
'group' => $group
];
$this->group_user_model->insert($group_user_data);
}
// Asignar los grupos de usuarios a los que pertenece el usuario editado
$this->saveUserGroupsSafely($id, $currentGroups);
$this->chat_department_user_model->where("user_id", $id)->delete();
foreach ($chatDepartments as $chatDepartment) {
$this->chat_department_user_model->insert([
@ -156,8 +151,8 @@ class Users extends \App\Controllers\GoBaseController
$message = lang('Basic.global.saveSuccess', [mb_strtolower(lang('Users.user'))]) . '.';
$message = ucfirst(str_replace("'", "\'", $message));
if ($thenRedirect) :
if (!empty($this->indexRoute)) :
if ($thenRedirect):
if (!empty($this->indexRoute)):
return redirect()->to(route_to($this->indexRoute))->with('successMessage', $message);
else:
return $this->redirect2listView('successMessage', $message);
@ -173,7 +168,7 @@ class Users extends \App\Controllers\GoBaseController
$this->viewData['user'] = isset($sanitizedData) ? new UserEntity($sanitizedData) : new UserEntity();
$this->viewData['clienteList'] = $this->getClienteListItems();
$this->viewData['formAction'] = route_to('createUser');
$this->viewData['groups'] = $this->group_model->select('keyword, title')->findAll();
$this->viewData['groups'] = $this->group_model->select('keyword, title')->where('id >', 0)->findAll();
$this->viewData['chatDepartments'] = $this->chat_department_model->findAll();
$this->viewData['boxTitle'] = lang('Basic.global.addNew') . ' ' . lang('Users.user') . ' ' . lang('Basic.global.addNewSuffix');
@ -191,12 +186,12 @@ class Users extends \App\Controllers\GoBaseController
$users = auth()->getProvider();
$user = $users->findById($id);
if ($user == false) :
if ($user == false):
$message = lang('Basic.global.notFoundWithIdErr', [mb_strtolower(lang('Users.user')), $id]);
return $this->redirect2listView('errorMessage', $message);
endif;
if ($this->request->getPost()) :
if ($this->request->getPost()):
$postData = $this->request->getPost();
@ -218,9 +213,9 @@ class Users extends \App\Controllers\GoBaseController
}
$noException = true;
if ($successfulResult = $this->canValidate()) :
if ($successfulResult = $this->canValidate()):
if ($this->canValidate()) :
if ($this->canValidate()):
try {
if (in_array('cliente-editor', $currentGroups) || in_array('cliente-administrador', $currentGroups)) {
@ -249,16 +244,11 @@ class Users extends \App\Controllers\GoBaseController
$thenRedirect = false;
endif;
if ($noException && $successfulResult) :
if ($noException && $successfulResult):
// Asignar los grupos de usuarios a los que pertenece el usuario editado
$this->saveUserGroupsSafely($user->id, $currentGroups);
$this->group_user_model->where('user_id', $user->id)->delete();
foreach ($currentGroups as $group) {
$group_user_data = [
'user_id' => $user->id,
'group' => $group
];
$this->group_user_model->insert($group_user_data);
}
$this->chat_department_user_model->where("user_id", $id)->delete();
foreach ($chatDepartments as $chatDepartment) {
$this->chat_department_user_model->insert([
@ -270,8 +260,8 @@ class Users extends \App\Controllers\GoBaseController
$message = lang('Basic.global.updateSuccess', [mb_strtolower(lang('Users.user'))]) . '.';
$message = ucfirst(str_replace("'", "\'", $message));
if ($thenRedirect) :
if (!empty($this->indexRoute)) :
if ($thenRedirect):
if (!empty($this->indexRoute)):
return redirect()->to(route_to($this->indexRoute))->with('successMessage', $message);
else:
return $this->redirect2listView('successMessage', $message);
@ -287,7 +277,7 @@ class Users extends \App\Controllers\GoBaseController
$this->viewData['clienteList'] = $this->getClienteListItems($user->cliente_id);
$this->viewData['formAction'] = route_to('updateUser', $id);
$this->viewData['selectedGroups'] = $this->group_model->getUsersRoles($requestedId);
$this->viewData['groups'] = $this->group_model->select('keyword, title')->findAll();
$this->viewData['groups'] = $this->group_model->select('keyword, title')->where('id >', 0)->findAll();
$this->viewData['chatDepartments'] = $this->chat_department_model->select(["display", "name", "id as chatDepartmentId"])->findAll();
$this->viewData['chatDepartmentUser'] = $this->chat_department_user_model->getChatDepartmentUser($user->id);
$this->viewData['boxTitle'] = lang('Basic.global.edit2') . ' ' . lang('Users.user') . ' ' . lang('Basic.global.edit3');
@ -299,18 +289,22 @@ class Users extends \App\Controllers\GoBaseController
public function delete($requestedId = null, bool $deletePermanently = true)
{
if ($requestedId == null) :
if ($requestedId == null):
return $this->redirect2listView();
endif;
$id = filter_var($requestedId, FILTER_SANITIZE_URL);
$user = $this->model->find($id);
if ($user == false) :
if ($user == false):
$message = lang('Basic.global.notFoundWithIdErr', [mb_strtolower(lang('Users.user')), $id]);
return $this->redirect2listView('errorMessage', $message);
endif;
// Elimina todos los grupos actuales
$this->group_user_model->where('user_id', $id)->delete();
// Elimina todos los grupos de chat actuales
$this->chat_department_user_model->where("user_id", $id)->delete();
$users = auth()->getProvider();
@ -433,11 +427,11 @@ class Users extends \App\Controllers\GoBaseController
protected function getClienteListItems($selId = null)
{
$data = ['' => ""];
if (!empty($selId)) :
if (!empty($selId)):
$clienteModel = model('App\Models\Clientes\ClienteModel');
$selOption = $clienteModel->where('id', $selId)->findColumn('nombre');
if (!empty($selOption)) :
if (!empty($selOption)):
$data[$selId] = $selOption[0];
endif;
endif;
@ -450,7 +444,7 @@ class Users extends \App\Controllers\GoBaseController
['title' => lang("App.menu_change_session"), 'route' => route_to('maquinistaUserChangeList'), 'active' => true]
];
$maquinistas = [];
$users = auth()->getProvider()->whereNotIn('id',[auth()->user()->id])->findAll();
$users = auth()->getProvider()->whereNotIn('id', [auth()->user()->id])->findAll();
foreach ($users as $key => $user) {
if ($user->inGroup('maquina') && !$user->inGroup('admin', 'comercial', 'cliente-editor', 'cliente-admin')) {
$maquinistas[] = $user;
@ -467,4 +461,50 @@ class Users extends \App\Controllers\GoBaseController
auth()->login($user);
return redirect("home");
}
/**
* Asigna grupos a un usuario, asegurando que no se pueda inyectar el grupo 'root',
* pero manteniéndolo si ya lo tenía previamente.
*
* @param int $userId ID del usuario al que se le asignarán los grupos
* @param array $requestedGroups Grupos solicitados desde el formulario
* @return void
*/
private function saveUserGroupsSafely(int $userId, array $requestedGroups): void
{
// Verifica si el usuario ya tenía el grupo 'root'
$existingGroups = $this->group_user_model
->where('user_id', $userId)
->findColumn('group') ?? [];
$hasRoot = in_array('root', $existingGroups);
// Elimina todos los grupos actuales
$this->group_user_model->where('user_id', $userId)->delete();
// Inserta solo los grupos válidos (sin 'root')
foreach ($requestedGroups as $group) {
if (!empty($group) && $group !== 'root') {
$this->group_user_model->insert([
'user_id' => $userId,
'group' => $group,
'created_at' => date('Y-m-d H:i:s'),
]);
} elseif ($group === 'root') {
log_message('alert', "Intento de asignar grupo 'root' al usuario ID $userId");
}
}
// Reasigna 'root' solo si el usuario ya lo tenía
if ($hasRoot) {
$this->group_user_model->insert([
'user_id' => $userId,
'group' => 'root',
'created_at' => date('Y-m-d H:i:s'),
]);
}
}
}

View File

@ -1,4 +1,5 @@
<?php
namespace App\Controllers\Importadores;
use App\Controllers\BaseResourceController;
@ -393,7 +394,7 @@ class ImportadorBubok extends BaseResourceController
'gramajeCubierta' => in_array($encuadernadoId, [1, 3]) ? 150 : 300, // 150 gramos para "fresado tapa dura" y "cosido tapa dura"
'solapas' => !empty($producto->cover->type->consolapas) ? 80 : 0,
'acabado' => $acabadoId,
'cabezada' => 'WHI',
'cabezada' => model('\App\Models\Configuracion\ConfigVariableModel')->getCabezadaDefault(),
'lomoRedondo' => 0
],
'guardas' => [],
@ -456,85 +457,33 @@ class ImportadorBubok extends BaseResourceController
], 400);
}
// Descarga y subida de archivos al SFTP
$presupuestoFicheroModel = model('App\Models\Presupuestos\PresupuestoFicheroModel');
$ftp = new \App\Libraries\SafekatFtpClient();
// ✅ Importar archivos desde URLs y subir al SFTP
$uploaderService = new \App\Services\PresupuestoUploaderService(
new \App\Libraries\SftpClientWrapper(config('PresupuestoSFTP')),
model(\App\Models\Presupuestos\PresupuestoFicheroModel::class),
config('PresupuestoSFTP')
);
$archivoUrls = [
'cover' => $producto->cover->file ?? null,
'body' => $producto->body->file ?? null,
];
foreach ($archivoUrls as $tipo => $url) {
if (!$url)
continue;
$resultadoArchivos = $uploaderService->importarArchivosDesdeUrlsBubok($response['sk_id'], $archivoUrls);
try {
$contenido = @file_get_contents($url); // silenciar errores de PHP
if ($contenido === false || strlen($contenido) === 0) {
// No se pudo descargar el archivo: generar archivo de error para FTP
$errorMessage = "ERROR: No se pudo descargar el archivo remoto para $tipo desde la URL: $url";
$remoteDir = $ftp->getPresupuestoRemotePath($response['sk_id']); // crea esta función si no existe
$remoteErrorFile = $remoteDir . '/ERROR_' . strtoupper($tipo) . '.txt';
// Crear archivo temporal con el mensaje de error
$tempErrorFile = WRITEPATH . 'uploads/presupuestos/ERROR_' . $tipo . '.txt';
file_put_contents($tempErrorFile, $errorMessage);
if (!$ftp->is_dir($remoteDir)) {
$ftp->mkdir($remoteDir, recursive: true);
}
$ftp->put($remoteErrorFile, $tempErrorFile, $ftp::SOURCE_LOCAL_FILE);
continue; // no procesar este archivo
}
// ✅ Procesar normalmente si la descarga tuvo éxito
$nombreOriginal = basename(parse_url($url, PHP_URL_PATH));
$extension = pathinfo($nombreOriginal, PATHINFO_EXTENSION);
$nombreLimpio = $presupuestoFicheroModel->saveFileInBBDD(
$response['sk_id'],
$nombreOriginal,
$extension,
auth()->id()
);
if (is_null($nombreLimpio))
continue;
$rutaLocal = WRITEPATH . 'uploads/presupuestos/';
if (!is_dir($rutaLocal)) {
mkdir($rutaLocal, 0777, true);
}
file_put_contents($rutaLocal . $nombreLimpio, $contenido);
} catch (\Throwable $e) {
//log_message('error', 'Error inesperado en descarga de archivo remoto: ' . $e->getMessage());
}
}
// Subir al FTP después de guardar localmente
try {
$ftp->uploadFilePresupuesto($response['sk_id']);
} catch (\Throwable $e) {
log_message('error', 'Error subiendo archivos al FTP: ' . $e->getMessage());
if (!$resultadoArchivos['success']) {
log_message('warning', 'Errores al importar archivos desde Bubok: ' . print_r($resultadoArchivos['errores'], true));
}
return $this->respond([
'status' => 200,
'data' => [
'sk_id' => $response['sk_id'],
'sk_url' => $response['sk_url'] ?? null
'sk_url' => $response['sk_url'] ?? null,
'archivos_subidos' => $resultadoArchivos['archivos_subidos'],
'errores_archivos' => $resultadoArchivos['errores']
]
]);
} catch (\Throwable $e) {
return $this->respond([
'status' => 500,
@ -544,8 +493,4 @@ class ImportadorBubok extends BaseResourceController
]);
}
}
}

View File

@ -272,7 +272,7 @@ class ImportadorCatalogo extends BaseResourceController
'gramajeCubierta' => $libro->cubierta_gramaje,
'solapas' => $libro->cubierta_ancho_solapas,
'acabado' => $libro->cubierta_acabado_id,
'cabezada' => 'WHI',
'cabezada' => model('\App\Models\Configuracion\ConfigVariableModel')->getCabezadaDefault(),
'lomoRedondo' => 0
],

View File

@ -6,7 +6,6 @@ use App\Controllers\Facturacion\Facturas;
use App\Entities\Pedidos\PedidoEntity;
use App\Models\Collection;
use App\Models\Pedidos\PedidoModel;
use App\Services\PedidoXMLService;
use App\Services\ProductionService;
use Hermawan\DataTables\DataTable;
use CodeIgniter\I18n\Time;
@ -614,12 +613,7 @@ class Pedido extends \App\Controllers\BaseResourceController
$pedidoEntity->created_at_footer = $pedidoEntity->created_at ? date(' H:i d/m/Y', strtotime($pedidoEntity->created_at)) : '';
$pedidoEntity->updated_at_footer = $pedidoEntity->updated_at ? date(' H:i d/m/Y', strtotime($pedidoEntity->updated_at)) : '';
}
public function get_xml_pedido($pedido_id)
{
$data = PedidoXMLService::generate_xml($pedido_id);
// $xml_service = new PedidoXMLService($this->model);
return $this->respond($data);
}
public function to_produccion($pedido_id)
{

View File

@ -36,6 +36,8 @@ class Buscador extends \App\Controllers\BaseResourceController
protected $indexRoute = 'buscadorPresupuestosList';
protected $deletePermission = 'presupuesto.delete';
public function initController(\CodeIgniter\HTTP\RequestInterface $request, \CodeIgniter\HTTP\ResponseInterface $response, \Psr\Log\LoggerInterface $logger)
{

View File

@ -0,0 +1,184 @@
<?php
namespace App\Controllers\Presupuestos;
use App\Controllers\BaseController;
use App\Services\PresupuestoUploaderService;
use App\Libraries\SftpClientWrapper;
use App\Models\Presupuestos\PresupuestoFicheroModel;
use Config\PresupuestoSFTP;
class PresupuestoFicheroController extends BaseController
{
public function get_files()
{
// 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()
{
$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];
}
// Servicio de subida (con SFTP)
$service = new \App\Services\PresupuestoUploaderService(
new \App\Libraries\SftpClientWrapper(config('PresupuestoSFTP')),
$model,
config('PresupuestoSFTP')
);
// Borrar ficheros eliminados por el usuario (BD y remoto)
$service->removeFromRemote($presupuesto_id);
$numDeleted = $model->deleteMissingFiles($presupuesto_id, $old_files);
$results = [];
foreach ($files as $file) {
if (!$file->isValid()) {
$results[] = [
'name' => $file->getName(),
'status' => 'invalid',
'message' => $file->getErrorString()
];
continue;
}
$newName = $model->saveFileInBBDD(
$presupuesto_id,
$file->getClientName(),
$file->getClientExtension(),
auth()->id()
);
// Crear directorio si no existe
$uploadDir = dirname($model->getAbsolutePath($presupuesto_id, $newName));
if (!is_dir($uploadDir)) {
mkdir($uploadDir, 0755, true);
}
$file->move($uploadDir, $newName);
$results[] = [
'name' => $file->getClientName(),
'status' => 'uploaded'
];
}
// Subida al SFTP
$sftpResult = $service->uploadToRemote($presupuesto_id);
// ✅ Contar totales para mostrar en el frontend
$numUploaded = count(array_filter($results, fn($f) => $f['status'] === 'uploaded'));
$numErrores = count(array_filter($results, fn($f) => $f['status'] !== 'uploaded'));
if (!$sftpResult['success']) {
return $this->response->setJSON([
'message' => 'Error en la subida de algunos archivos.',
'summary' => [
'subidos_ok' => $numUploaded,
'errores_locales' => $numErrores,
'errores_remotos' => count(array_filter($sftpResult['files'], fn($f) => !$f['success'])),
'borrados' => $numDeleted,
],
'details' => [
'local' => $results,
'sftp' => $sftpResult['files']
]
])->setStatusCode(500);
}
return $this->response->setJSON([
'message' => 'Archivos subidos correctamente.',
'summary' => [
'subidos_ok' => $numUploaded,
'errores_locales' => $numErrores,
'errores_remotos' => 0,
'borrados' => $numDeleted
],
'details' => [
'local' => $results,
'sftp' => $sftpResult['files']
]
]);
}
public function download_zip()
{
$presupuesto_id = $this->request->getPost('presupuesto_id');
$ot_id = $this->request->getPost('ot_id');
if (!$presupuesto_id) {
return $this->response->setStatusCode(400)->setBody('Presupuesto ID requerido');
}
$prefijo = (!empty($ot_id) && is_numeric($ot_id)) ? "OT_{$ot_id}" : null;
$service = new \App\Services\PresupuestoUploaderService(
new \App\Libraries\SftpClientWrapper(config('PresupuestoSFTP')),
model('App\Models\Presupuestos\PresupuestoFicheroModel'),
config('PresupuestoSFTP')
);
$result = $service->downloadZip((int) $presupuesto_id, $prefijo);
if (!$result['success'] || empty($result['zipPath'])) {
return $this->response
->setStatusCode(500)
->setJSON(['error' => $result['message']]);
}
$zipPath = $result['zipPath'];
// Definir nombre final del ZIP para el cliente
$nombreArchivo = $prefijo
? "{$prefijo}_PRESUPUESTO_{$presupuesto_id}.zip"
: "archivos_presupuesto_{$presupuesto_id}.zip";
// Eliminar archivo ZIP tras terminar la descarga (una vez enviada la respuesta)
register_shutdown_function(function () use ($zipPath) {
if (file_exists($zipPath)) {
unlink($zipPath);
}
});
// Descargar el archivo al cliente
return $this->response
->download($zipPath, null)
->setFileName($nombreArchivo);
}
}

View File

@ -448,7 +448,9 @@ class Presupuestoadmin extends \App\Controllers\BaseResourceController
'retractilado' => model('App\Models\Configuracion\ConfigVariableModel')->getVariable('id_servicio_retractilado')->value,
'retractilado5' => model('App\Models\Configuracion\ConfigVariableModel')->getVariable('id_servicio_retractilado5')->value,
'ferro' => model('App\Models\Configuracion\ConfigVariableModel')->getVariable('id_servicio_ferro')->value,
'ferro_2' => model('App\Models\Configuracion\ConfigVariableModel')->getVariable('id_servicio_ferro_2')->value,
'prototipo' => model('App\Models\Configuracion\ConfigVariableModel')->getVariable('id_servicio_prototipo')->value,
'prototipo_2' => model('App\Models\Configuracion\ConfigVariableModel')->getVariable('id_servicio_prototipo_2')->value,
'solapas_grandes_cubierta' => model('App\Models\Configuracion\ConfigVariableModel')->getVariable('id_servicio_plegado_exceso_solapas_cubierta')->value,
'solapas_grandes_sobrecubierta' => model('App\Models\Configuracion\ConfigVariableModel')->getVariable('id_servicio_plegado_exceso_solapas_sobrecubierta')->value,
'solapas_grandes_faja' => model('App\Models\Configuracion\ConfigVariableModel')->getVariable('id_servicio_plegado_exceso_solapas_faja')->value,
@ -458,6 +460,8 @@ class Presupuestoadmin extends \App\Controllers\BaseResourceController
$this->viewData['tipo_impresion_id'] = $presupuestoEntity->tipo_impresion_id; // Cosido tapa blanda JJO
$this->viewData['cabezadas'] = model('\App\Models\Configuracion\ConfigVariableModel')->getCabezadasDisponibles();
$this->viewData = array_merge($this->viewData, $this->getStringsFromTipoImpresion($presupuestoEntity->tipo_impresion_id));
$this->viewData['formAction'] = route_to('updatePresupuestoAdmin', $id);
@ -565,7 +569,6 @@ class Presupuestoadmin extends \App\Controllers\BaseResourceController
$modelCliente = new ClienteModel();
$modelPapelGenerico = new PapelGenericoModel();
$presupuesto = $this->model->find($id);
$data = [];
if ($presupuesto) {
@ -586,6 +589,7 @@ class Presupuestoadmin extends \App\Controllers\BaseResourceController
$data['datosGenerales']['coleccion'] = $presupuesto->coleccion;
$data['datosGenerales']['numero_edicion'] = $presupuesto->numero_edicion;
$data['datosGenerales']['isbn'] = $presupuesto->isbn;
$data['datosGenerales']['iskn'] = $presupuesto->iskn;
$data['datosGenerales']['pais'] = $presupuesto->pais_id;
$data['datosGenerales']['pais_nombre'] = model('App\Models\Configuracion\PaisModel')->find($presupuesto->pais_id)->nombre;
$data['datosGenerales']['cliente']['id'] = $presupuesto->cliente_id;
@ -630,7 +634,9 @@ class Presupuestoadmin extends \App\Controllers\BaseResourceController
$data['datosLibro']['acabadoFaja']['text'] = $modelAcabado->find($presupuesto->acabado_faja_id)->nombre;
}
$data['datosLibro']['prototipo'] = $presupuesto->prototipo;
$data['datosLibro']['prototipo2'] = $this->hasPrototipo2($id);
$data['datosLibro']['ferro'] = $presupuesto->ferro;
$data['datosLibro']['ferro2'] = $this->hasFerro2($id);
$data['datosLibro']['ferroDigital'] = $presupuesto->ferro_digital;
$data['datosLibro']['marcapaginas'] = $presupuesto->marcapaginas;
$data['datosLibro']['retractilado'] = $presupuesto->retractilado;
@ -659,6 +665,21 @@ class Presupuestoadmin extends \App\Controllers\BaseResourceController
$data['direcciones'] = $this->obtenerDireccionesEnvio($id, $presupuesto->cliente_id);
}
$data['direccionesFP'] = [];
$direccionFP1 = $this->obtenerDireccionesEnvio($id, $presupuesto->cliente_id, true, 1);
if(count($direccionFP1) > 0){
$data['direccionesFP']['fp1'] = $direccionFP1;
} else {
$data['direccionesFP']['fp1'] = [];
}
$direccionFP2 = $this->obtenerDireccionesEnvio($id, $presupuesto->cliente_id, true, 2);
if(count($direccionFP2) > 0){
$data['direccionesFP']['fp2'] = $direccionFP2;
} else {
$data['direccionesFP']['fp2'] = [];
}
$data['direccionesFP']['checkboxes'] = json_decode($presupuesto->getDireccionFPChecks());
$data['comentarios_cliente'] = $presupuesto->comentarios_cliente;
$data['comentarios_safekat'] = $presupuesto->comentarios_safekat;
$data['comentarios_pdf'] = $presupuesto->comentarios_pdf;
@ -1951,7 +1972,7 @@ class Presupuestoadmin extends \App\Controllers\BaseResourceController
return PresupuestoService::checkLineasEnvios($direccionesEnvio);
}
protected function obtenerDireccionesEnvio($id, $cliente_id)
protected function obtenerDireccionesEnvio($id, $cliente_id, $is_fp = false, $num_fp = 0)
{
$model = model('App\Models\Presupuestos\PresupuestoDireccionesModel');
$model_direcciones = model('App\Models\Clientes\ClienteDireccionesModel');
@ -1959,10 +1980,38 @@ class Presupuestoadmin extends \App\Controllers\BaseResourceController
->join('lg_proveedores', 'presupuesto_direcciones.proveedor_id = lg_proveedores.id')
->join('lg_paises', 'presupuesto_direcciones.pais_id = lg_paises.id')
->select('presupuesto_direcciones.*, lg_proveedores.nombre AS proveedor, lg_paises.nombre AS pais')
->where('presupuesto_id', $id)->findAll();
->where('presupuesto_id', $id)
->where('is_ferro_prototipo', $is_fp);
if ($is_fp) {
$direcciones = $direcciones
->where('num_ferro_prototipo', $num_fp);
}
return $direcciones;
return $direcciones->findAll();
}
protected function hasPrototipo2($presupuestoId){
$servicios = (new PresupuestoServiciosExtraModel())->getResource($presupuestoId)->get()->getResultObject();
$id_servicio = model('App\Models\Configuracion\ConfigVariableModel')->getVariable('id_servicio_prototipo_2')->value;
foreach ($servicios as $servicio) {
if ($servicio->tarifa_extra_id == $id_servicio) {
return true;
}
}
return false;
}
protected function hasFerro2($presupuestoId)
{
$servicios = (new PresupuestoServiciosExtraModel())->getResource($presupuestoId)->get()->getResultObject();
$id_servicio = model('App\Models\Configuracion\ConfigVariableModel')->getVariable('id_servicio_ferro_2')->value;
foreach ($servicios as $servicio) {
if ($servicio->tarifa_extra_id == $id_servicio) {
return true;
}
}
return false;
}
}

View File

@ -133,6 +133,7 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
$this->viewData['lomo_maximo_fresado_cosido'] = model('App\Models\Configuracion\ConfigVariableModel')->getVariable('lomo_maximo_fresado_cosido')->value;
$this->viewData['lomo_minimo_fresado_cosido'] = model('App\Models\Configuracion\ConfigVariableModel')->getVariable('lomo_minimo_fresado_cosido')->value;
$this->viewData['eb'] = 0;
$this->viewData['cabezadas'] = model('\App\Models\Configuracion\ConfigVariableModel')->getCabezadasDisponibles();
$this->viewData['boxTitle'] = lang('Basic.global.addNew') . ' ' . $this->viewData['pageTitle'] . ' ' . lang('Basic.global.addNewSuffix');
@ -178,6 +179,7 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
$this->viewData['lomo_maximo_fresado_cosido'] = model('App\Models\Configuracion\ConfigVariableModel')->getVariable('lomo_maximo_fresado_cosido')->value;
$this->viewData['lomo_minimo_fresado_cosido'] = model('App\Models\Configuracion\ConfigVariableModel')->getVariable('lomo_minimo_fresado_cosido')->value;
$this->viewData['eb'] = $presupuestoEntity->envio_base;
$this->viewData['cabezadas'] = model('\App\Models\Configuracion\ConfigVariableModel')->getCabezadasDisponibles();
// Si se ha llamado a esta funcion porque se ha duplicado el presupuesto
// se actualiza la bbdd para que sólo ejecute algunas funciones una vez
@ -412,6 +414,7 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
}
}
}
$lomo = round($lomo, 2);
$errors = [
'status' => 0,
@ -472,7 +475,6 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
'errors' => $errors
);
return $this->respond($data);
} else {
return $this->failUnauthorized('Invalid request', 403);
}
@ -611,9 +613,10 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
}
if (array_key_exists('exception', $return_data)) {
return $this->failServerError(
$return_data['exception'] . ' - ' .
$return_data['file'] . ' - ' . $return_data['line']
$return_data['file'] . ' - ' . $return_data['line']
);
}
@ -719,7 +722,11 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
}
}
// Se suma el coste de envío a cada precio unidad
for ($i = 0; $i < count($tirada); $i++) {
if ($return_data['coste_envio'] && isset($return_data['coste_envio'][$i]) && $return_data['coste_envio'][$i] > 0)
$return_data['precio_u'][$i] = round(floatval($return_data['precio_u'][$i]) + $return_data['coste_envio'][$i] / $tirada[$i], 4);
}
if ($this->request) {
if ($this->request->isAJAX())
@ -727,7 +734,6 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
} else {
return $return_data;
}
} catch (Exception $e) {
if ($this->request) {
if ($this->request->isAJAX())
@ -736,7 +742,6 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
return "Error: " . $e->getMessage();
}
}
}
@ -843,11 +848,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);
}
}
@ -868,7 +871,6 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
'menu' => $data,
$csrfTokenName => $newTokenHash
]);
} else {
return $this->failUnauthorized('Invalid request', 403);
}
@ -1103,7 +1105,7 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
'solapasCubierta' => intval($cubierta['solapas'] ?? 0) == 1 ? intval($cubierta['tamanioSolapas']) : 0,
'acabado' => $cubierta['acabado'] ?? 0,
'lomoRedondo' => $cubierta['lomoRedondo'] ?? 0,
'cabezada' => $cubierta['cabezada'] ?? 'WHI',
'cabezada' => $cubierta['cabezada'] ?? model('\App\Models\Configuracion\ConfigVariableModel')->getCabezadaDefault(),
];
// Sobrecubierta
@ -1295,7 +1297,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);
@ -1330,7 +1331,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);
}
}
@ -1381,6 +1381,13 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
$datos_presupuesto['faja'] = $faja;
$reqData['datosCabecera'] ?? [];
$datos_presupuesto['direcciones_fp_checks'] = $reqData['direcciones_fp_checks'] ?? (object) [
'addFP1isAddMain' => "false",
'addFP2isAddMain' => "false",
'addFP2isaddFP1' => "false"
];
$id = $model_presupuesto->insertarPresupuestoCliente(
$id,
$selected_tirada,
@ -1561,11 +1568,10 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
}
if (count($direccionesFP1) > 0) {
$this->guardarLineaEnvio($id, $direccionesFP1, $peso_libro, true);
$this->guardarLineaEnvio($id, $direccionesFP1, $peso_libro, true, true, 1);
}
if (count($direccionesFP2) > 0) {
$this->guardarLineaEnvio($id, $direccionesFP2, $peso_libro, true);
$this->guardarLineaEnvio($id, $direccionesFP2, $peso_libro, true, true, 2);
}
if ($confirmar) {
@ -1708,11 +1714,18 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
$data['direcciones'] = $this->obtenerDireccionesEnvio($id);
}
$direccionesFerroPrototipo = $this->obtenerDireccionesEnvioFerro($id);
if ($direccionesFerroPrototipo && count($direccionesFerroPrototipo) > 0) {
$data['direccionesFerroPrototipo'] = $direccionesFerroPrototipo;
}
$data['direccionesFPChecks'] = $presupuesto->getDireccionFPChecks();
if (intval($presupuesto->estado_id) == 2) {
$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;
@ -1736,96 +1749,7 @@ 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);
}
}
public function upload_files()
{
$model = model('App\Models\Presupuestos\PresupuestoFicheroModel');
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$presupuesto_id = $_POST['presupuesto_id'];
$old_files = json_decode($_POST['oldFiles']);
$ftp = new SafekatFtpClient();
// Comprobar si se han subido archivos
if (!empty($_FILES['file']) || !empty($old_files)) {
// Borrar los archivos existentes del presupuesto
$ftp->removeFiles($presupuesto_id);
$model->deleteFiles($presupuesto_id, $old_files);
if (!empty($_FILES['file'])) {
$files = $_FILES['file'];
// Iterar sobre los archivos
for ($i = 0; $i < count($files['name']); $i++) {
// Aquí puedes acceder a las propiedades del archivo
$name = $files['name'][$i];
$extension = explode('.', $files['name'][$i])[1];
$tmp_name = $files['tmp_name'][$i];
$new_name = $model->saveFileInBBDD($presupuesto_id, $name, $extension, auth()->id());
// Se sube el fichero
// Pero primero se comprueba que la carpeta presupuestos exista
if (!is_dir(WRITEPATH . 'uploads/presupuestos')) {
mkdir(WRITEPATH . 'uploads/presupuestos', 0777, true);
}
if (!is_null($new_name)) {
$path = WRITEPATH . 'uploads/presupuestos/' . $new_name;
move_uploaded_file($tmp_name, $path);
}
}
$ftp->uploadFilePresupuesto($presupuesto_id);
}
} else {
// Borrar los archivos existentes del presupuesto
$ftp->removeFiles($presupuesto_id);
$model->deleteFiles($presupuesto_id);
}
}
return json_encode(['message' => 'Archivos subidos correctamente']);
}
/***********************
*
@ -1871,7 +1795,7 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
}
protected function guardarLineaEnvio($presupuestoId, $direccion, $peso_libro, $coste_cero = false)
protected function guardarLineaEnvio($presupuestoId, $direccion, $peso_libro, $coste_cero = false, $is_ferro_prototipo = false, $num_ferro_prototipo = 0)
{
$unidades = intval($direccion['unidades']);
@ -1891,8 +1815,12 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
$data->presupuesto_id = $presupuestoId;
$data->tarifa_id = $data->id;
unset($data->id);
if($coste_cero) {
if ($coste_cero) {
$data->coste = 0;
if ($is_ferro_prototipo) {
$data->is_ferro_prototipo = 1;
$data->num_ferro_prototipo = $num_ferro_prototipo;
}
} else {
$data->precio = $data->coste;
}
@ -1912,6 +1840,7 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
{
if ($tipo == 'encuadernacion') {
$model = new PresupuestoEncuadernacionesModel();
$data = [
@ -2097,18 +2026,17 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
for ($t = 0; $t < count($tirada); $t++) {
// Inicialización para los totalizadores
if ($extra_info) {
$totalPapel = 0.0;
$margenPapel = 0.0;
$totalImpresion = 0.0;
$margenImpresion = 0.0;
$totalPapel = 0.0;
$margenPapel = 0.0;
$totalImpresion = 0.0;
$margenImpresion = 0.0;
$sumForFactor = 0.0;
$sumForFactorPonderado = 0.0;
$sumForFactor = 0.0;
$sumForFactorPonderado = 0.0;
$totalServicios = 0.0;
$margenServicios = 0.0;
$totalServicios = 0.0;
$margenServicios = 0.0;
}
$tirada[$t] = intval($tirada[$t]);
$is_cosido = (new TipoPresupuestoModel())->get_isCosido($tipo_impresion_id);
@ -2180,16 +2108,15 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
$lomo += floatval($linea['mano']);
$info['lomo_interior'] += floatval($linea['mano']);
}
if ($extra_info) {
$this->calcular_coste_linea(
$linea,
$totalPapel,
$margenPapel,
$sumForFactor,
$totalImpresion,
$margenImpresion
);
}
$this->calcular_coste_linea(
$linea,
$totalPapel,
$margenPapel,
$sumForFactor,
$totalImpresion,
$margenImpresion
);
}
}
@ -2228,13 +2155,12 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
$costeInterior = 0.0;
$peso_interior = 0.0;
$lomo = 0;
if ($extra_info) {
$totalPapel = 0.0;
$margenPapel = 0.0;
$sumForFactor = 0.0;
$totalImpresion = 0.0;
$margenImpresion = 0.0;
}
$totalPapel = 0.0;
$margenPapel = 0.0;
$sumForFactor = 0.0;
$totalImpresion = 0.0;
$margenImpresion = 0.0;
foreach ($interior as $linea) {
if (count($linea) > 0) {
$costeInterior += round(floatval($linea['total_impresion']), 2);
@ -2243,17 +2169,15 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
$lomo += floatval($linea['mano']);
}
$peso_interior += floatval($linea['peso']);
if ($extra_info) {
$this->calcular_coste_linea(
$linea,
$totalPapel,
$margenPapel,
$sumForFactor,
$totalImpresion,
$margenImpresion
);
}
$this->calcular_coste_linea(
$linea,
$totalPapel,
$margenPapel,
$sumForFactor,
$totalImpresion,
$margenImpresion
);
}
}
}
@ -2298,17 +2222,14 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
$lomo += floatval($cubierta['mano']);
}
if ($extra_info) {
$this->calcular_coste_linea(
$cubierta,
$totalPapel,
$margenPapel,
$sumForFactor,
$totalImpresion,
$margenImpresion
);
}
$this->calcular_coste_linea(
$cubierta,
$totalPapel,
$margenPapel,
$sumForFactor,
$totalImpresion,
$margenImpresion
);
}
if ($coste_cubierta <= 0) {
@ -2327,7 +2248,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) {
@ -2359,16 +2280,14 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
return $return_data;
}
$coste_servicios += round(floatval($acabadoCubierta[0]->total), 2);
if ($extra_info) {
//$totalServicios += round(floatval($acabadoCubierta[0]->total), 2);
$base = round(floatval($acabadoCubierta[0]->total / (1 + $acabadoCubierta[0]->margen / 100.0)), 2);
$base = round(floatval($base / $cantidad_total), 2) * $cantidad_total;
$totalServicios += $base;
$margenServicios += round(floatval($acabadoCubierta[0]->total - $base), 2);
}
//$totalServicios += round(floatval($acabadoCubierta[0]->total), 2);
$base = round(floatval($acabadoCubierta[0]->total / (1 + $acabadoCubierta[0]->margen / 100.0)), 2);
$base = round(floatval($base / $cantidad_total), 2) * $cantidad_total;
$totalServicios += $base;
$margenServicios += round(floatval($acabadoCubierta[0]->total - $base), 2);
}
}
}
if ($lomoRedondo) {
@ -2399,14 +2318,12 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
return $return_data;
}
$coste_servicios += round(floatval($resultado[0]->total), 2);
if ($extra_info) {
//$totalServicios += round(floatval($resultado[0]->total), 2);
$base = round(floatval($resultado[0]->total / (1 + $resultado[0]->margen / 100.0)), 2);
$base = round(floatval($base / $cantidad_total), 2) * $cantidad_total;
$totalServicios += $base;
$margenServicios += round(floatval($resultado[0]->total - $base), 2);
}
//$totalServicios += round(floatval($resultado[0]->total), 2);
$base = round(floatval($resultado[0]->total / (1 + $resultado[0]->margen / 100.0)), 2);
$base = round(floatval($base / $cantidad_total), 2) * $cantidad_total;
$totalServicios += $base;
$margenServicios += round(floatval($resultado[0]->total - $base), 2);
}
}
@ -2435,17 +2352,15 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
if (count($linea_sobrecubierta) > 0) {
$coste_sobrecubierta += round(floatval($linea_sobrecubierta['total_impresion']), 2);
$peso_sobrecubierta += round(floatval($linea_sobrecubierta['peso']), 2);
if ($extra_info) {
$this->calcular_coste_linea(
$linea_sobrecubierta,
$totalPapel,
$margenPapel,
$sumForFactor,
$totalImpresion,
$margenImpresion
);
}
$this->calcular_coste_linea(
$linea_sobrecubierta,
$totalPapel,
$margenPapel,
$sumForFactor,
$totalImpresion,
$margenImpresion
);
}
if ($coste_sobrecubierta <= 0) {
@ -2496,13 +2411,12 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
}
$coste_servicios += round(floatval($acabadoSobrecubierta[0]->total), 2);
if ($extra_info) {
//$totalServicios += round(floatval($acabadoSobrecubierta[0]->total), 2);
$base = round(floatval($acabadoSobrecubierta[0]->total / (1 + $acabadoSobrecubierta[0]->margen / 100.0)), 2);
$base = round(floatval($base / $cantidad_total), 2) * $cantidad_total;
$totalServicios += $base;
$margenServicios += round(floatval($acabadoSobrecubierta[0]->total - $base), 2);
}
//$totalServicios += round(floatval($acabadoSobrecubierta[0]->total), 2);
$base = round(floatval($acabadoSobrecubierta[0]->total / (1 + $acabadoSobrecubierta[0]->margen / 100.0)), 2);
$base = round(floatval($base / $cantidad_total), 2) * $cantidad_total;
$totalServicios += $base;
$margenServicios += round(floatval($acabadoSobrecubierta[0]->total - $base), 2);
}
}
}
@ -2544,17 +2458,15 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
if (intval($tirada[$t]) == intval($selected_tirada)) {
$lomo += floatval($guardas['mano']);
}
if ($extra_info) {
$this->calcular_coste_linea(
$guardas,
$totalPapel,
$margenPapel,
$sumForFactor,
$totalImpresion,
$margenImpresion
);
}
$this->calcular_coste_linea(
$guardas,
$totalPapel,
$margenPapel,
$sumForFactor,
$totalImpresion,
$margenImpresion
);
}
if ($coste_guardas <= 0) {
$errorModel = new ErrorPresupuesto();
@ -2598,17 +2510,15 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
$linea_faja['tipo_linea'] = 'lp_faja';
$coste_faja += round(floatval($linea_faja['total_impresion']), 2);
$peso_faja += floatval($linea_faja['peso']);
if ($extra_info) {
$this->calcular_coste_linea(
$linea_faja,
$totalPapel,
$margenPapel,
$sumForFactor,
$totalImpresion,
$margenImpresion
);
}
$this->calcular_coste_linea(
$linea_faja,
$totalPapel,
$margenPapel,
$sumForFactor,
$totalImpresion,
$margenImpresion
);
}
if ($coste_faja <= 0) {
@ -2658,13 +2568,12 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
}
$coste_servicios += round(floatval($acabadoFaja[0]->total), 2);
if ($extra_info) {
//$totalServicios += round(floatval($acabadoFaja[0]->total), 2);
$base = round(floatval($acabadoFaja[0]->total / (1 + $acabadoFaja[0]->margen / 100.0)), 2);
$base = round(floatval($base / $cantidad_total), 2) * $cantidad_total;
$totalServicios += $base;
$margenServicios += round(floatval($acabadoFaja[0]->total - $base), 2);
}
//$totalServicios += round(floatval($acabadoFaja[0]->total), 2);
$base = round(floatval($acabadoFaja[0]->total / (1 + $acabadoFaja[0]->margen / 100.0)), 2);
$base = round(floatval($base / $cantidad_total), 2) * $cantidad_total;
$totalServicios += $base;
$margenServicios += round(floatval($acabadoFaja[0]->total - $base), 2);
}
}
}
@ -2713,13 +2622,12 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
$costeServiciosDefecto += round(floatval($servicio->total), 2);
if ($extra_info) {
//$totalServicios += round(floatval($servicio->total), 2);
$base = round(floatval($servicio->total / (1 + $servicio->margen / 100.0)), 2);
$base = round(floatval($base / $cantidad_total), 2) * $cantidad_total;
$totalServicios += $base;
$margenServicios += round(floatval($servicio->total - $base), 2);
}
//$totalServicios += round(floatval($servicio->total), 2);
$base = round(floatval($servicio->total / (1 + $servicio->margen / 100.0)), 2);
$base = round(floatval($base / $cantidad_total), 2) * $cantidad_total;
$totalServicios += $base;
$margenServicios += round(floatval($servicio->total - $base), 2);
}
$servDefectoMan = PresupuestoCLienteService::getServiciosManipuladoDefault([
@ -2751,13 +2659,12 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
$costeServiciosDefecto += round(floatval($servicio->total), 2);
if ($extra_info) {
//$totalServicios += round(floatval($servicio->total), 2);
$base = round(floatval($servicio->total / (1 + $servicio->margen / 100.0)), 2);
$base = round(floatval($base / $cantidad_total), 2) * $cantidad_total;
$totalServicios += $base;
$margenServicios += round(floatval($servicio->total - $base), 2);
}
//$totalServicios += round(floatval($servicio->total), 2);
$base = round(floatval($servicio->total / (1 + $servicio->margen / 100.0)), 2);
$base = round(floatval($base / $cantidad_total), 2) * $cantidad_total;
$totalServicios += $base;
$margenServicios += round(floatval($servicio->total - $base), 2);
}
if ($extra_info) {
@ -2857,13 +2764,12 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
}
$coste_servicios += round(floatval($resultado[0]->total), 2);
if ($extra_info) {
//$totalServicios += round(floatval($resultado[0]->total), 2);
$base = round(floatval($resultado[0]->total / (1 + $resultado[0]->margen / 100.0)), 2);
$base = round(floatval($base / $cantidad_total), 2) * $cantidad_total;
$totalServicios += $base;
$margenServicios += round(floatval($resultado[0]->total - $base), 2);
}
//$totalServicios += round(floatval($resultado[0]->total), 2);
$base = round(floatval($resultado[0]->total / (1 + $resultado[0]->margen / 100.0)), 2);
$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([
@ -2890,13 +2796,12 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
array_push($serviciosAutomaticos, $resultado[0]);
$coste_servicios += round(floatval($resultado[0]->precio), 2);
if ($extra_info) {
//$totalServicios += round(floatval($resultado[0]->precio), 2);
$base = round(floatval($resultado[0]->total / (1 + $resultado[0]->margen / 100.0)), 2);
$base = round(floatval($base / $cantidad_total), 2) * $cantidad_total;
$totalServicios += $base;
$margenServicios += round(floatval($resultado[0]->total - $base), 2);
}
//$totalServicios += round(floatval($resultado[0]->precio), 2);
$base = round(floatval($resultado[0]->total / (1 + $resultado[0]->margen / 100.0)), 2);
$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([
@ -2925,13 +2830,12 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
}
$coste_servicios += round(floatval($resultado[0]->total), 2);
if ($extra_info) {
//$totalServicios += round(floatval($resultado[0]->total), 2);
$base = round(floatval($resultado[0]->total / (1 + $resultado[0]->margen / 100.0)), 2);
$base = round(floatval($base / $cantidad_total), 2) * $cantidad_total;
$totalServicios += $base;
$margenServicios += round(floatval($resultado[0]->total - $base), 2);
}
//$totalServicios += round(floatval($resultado[0]->total), 2);
$base = round(floatval($resultado[0]->total / (1 + $resultado[0]->margen / 100.0)), 2);
$base = round(floatval($base / $cantidad_total), 2) * $cantidad_total;
$totalServicios += $base;
$margenServicios += round(floatval($resultado[0]->total - $base), 2);
}
}
@ -2967,15 +2871,13 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
array_push($serviciosExtra, $resultado[0]);
$coste_servicios += round(floatval($resultado[0]->precio), 2);
if ($extra_info) {
//$totalServicios += round(floatval($resultado[0]->precio), 2);
$base = round(floatval($resultado[0]->precio / (1 + $resultado[0]->margen / 100.0)), 2);
$base = round(floatval($base / $cantidad_total), 2) * $cantidad_total;
$totalServicios += $base;
$margenServicios += round(floatval($resultado[0]->precio - $base), 2);
}
}
//$totalServicios += round(floatval($resultado[0]->precio), 2);
$base = round(floatval($resultado[0]->precio / (1 + $resultado[0]->margen / 100.0)), 2);
$base = round(floatval($base / $cantidad_total), 2) * $cantidad_total;
$totalServicios += $base;
$margenServicios += round(floatval($resultado[0]->precio - $base), 2);
}
}
// Plegado de solapas grandes
@ -3007,13 +2909,12 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
}
$coste_servicios += round(floatval($resultado[0]->total), 2);
if ($extra_info) {
//$totalServicios += round(floatval($resultado[0]->total), 2);
$base = round(floatval($resultado[0]->total / (1 + $resultado[0]->margen / 100.0)), 2);
$base = round(floatval($base / $cantidad_total), 2) * $cantidad_total;
$totalServicios += $base;
$margenServicios += round(floatval($resultado[0]->total - $base), 2);
}
//$totalServicios += round(floatval($resultado[0]->total), 2);
$base = round(floatval($resultado[0]->total / (1 + $resultado[0]->margen / 100.0)), 2);
$base = round(floatval($base / $cantidad_total), 2) * $cantidad_total;
$totalServicios += $base;
$margenServicios += round(floatval($resultado[0]->total - $base), 2);
}
if (is_array($sobreCubierta) && ($sobreCubierta['solapas'] > 0 && intval($linea_sobrecubierta['dimension_desarrollo']['ancho']) > 630)) {
@ -3045,13 +2946,12 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
}
$coste_servicios += round(floatval($resultado[0]->total), 2);
if ($extra_info) {
//$totalServicios += round(floatval($resultado[0]->total), 2);
$base = round(floatval($resultado[0]->total / (1 + $resultado[0]->margen / 100.0)), 2);
$base = round(floatval($base / $cantidad_total), 2) * $cantidad_total;
$totalServicios += $base;
$margenServicios += round(floatval($resultado[0]->total - $base), 2);
}
//$totalServicios += round(floatval($resultado[0]->total), 2);
$base = round(floatval($resultado[0]->total / (1 + $resultado[0]->margen / 100.0)), 2);
$base = round(floatval($base / $cantidad_total), 2) * $cantidad_total;
$totalServicios += $base;
$margenServicios += round(floatval($resultado[0]->total - $base), 2);
}
if (is_array($faja) && $faja !== [] && ($faja['solapas'] > 0 && intval($linea_faja['dimension_desarrollo']['ancho']) > 630)) {
@ -3083,13 +2983,12 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
}
$coste_servicios += round(floatval($resultado[0]->total), 2);
if ($extra_info) {
//$totalServicios += round(floatval($resultado[0]->total), 2);
$base = round(floatval($resultado[0]->total / (1 + $resultado[0]->margen / 100.0)), 2);
$base = round(floatval($base / $cantidad_total), 2) * $cantidad_total;
$totalServicios += $base;
$margenServicios += round(floatval($resultado[0]->total - $base), 2);
}
//$totalServicios += round(floatval($resultado[0]->total), 2);
$base = round(floatval($resultado[0]->total / (1 + $resultado[0]->margen / 100.0)), 2);
$base = round(floatval($base / $cantidad_total), 2) * $cantidad_total;
$totalServicios += $base;
$margenServicios += round(floatval($resultado[0]->total - $base), 2);
}
/*$total_por_tirada = $costeInterior +
@ -3218,7 +3117,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)
@ -3338,8 +3236,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"
@ -3426,7 +3323,7 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
{
$model = model('App\Models\Presupuestos\PresupuestoDireccionesModel');
$direcciones = $model->where('presupuesto_id', $id)
->where('is_ferro_prototipo', 0)->asArray()->findAll();
->where('is_ferro_prototipo', 1)->get()->getResultArray();
return $direcciones;
}
@ -3659,30 +3556,5 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
return $servicios;
}
public function download_zip()
{
$presupuesto_id = $this->request->getPost('presupuesto_id');
if (!$presupuesto_id) {
return $this->response->setStatusCode(400)->setBody('Presupuesto ID requerido');
}
$ftpClient = new \App\Libraries\SafekatFtpClient();
try {
$zipPath = $ftpClient->downloadZipPresupuesto((int) $presupuesto_id);
if ($zipPath === null || !file_exists($zipPath)) {
return $this->response->setStatusCode(404)->setBody('No se encontraron archivos');
}
return $this->response
->download($zipPath, null) // null = usar nombre original del archivo
->setFileName('archivos_presupuesto_' . $presupuesto_id . '.zip');
} catch (\Throwable $e) {
log_message('error', $e->getMessage());
return $this->response->setStatusCode(500)->setBody('Error interno');
}
}
}

View File

@ -55,6 +55,7 @@ class Presupuestodirecciones extends \App\Controllers\BaseResourceController
$proveedor_id = $reqData['proveedor_id'] ?? "";
$entregaPieCalle = $reqData['entregaPieCalle'] ?? 0;
$is_ferro_prototipo = $reqData['is_ferro_prototipo'] ?? 0;
$num_ferro_prototipo = $reqData['num_ferro_prototipo'] ?? 0;
$data = [
"presupuesto_id" => $presupuesto_id,
@ -74,7 +75,8 @@ class Presupuestodirecciones extends \App\Controllers\BaseResourceController
"proveedor" => $proveedor,
"proveedor_id" => $proveedor_id,
"entregaPieCalle" => $entregaPieCalle,
"is_ferro_prototipo" => $is_ferro_prototipo
"is_ferro_prototipo" => $is_ferro_prototipo,
"num_ferro_prototipo" => $num_ferro_prototipo
];
$response = $this->model->insert($data);

View File

@ -1,35 +0,0 @@
<?php
namespace App\Controllers\Produccion;
use App\Controllers\BaseController;
class Ordenmaquina extends BaseController
{
function __construct()
{
}
public function index()
{
echo 'Orden maquina';
}
public function delete()
{
}
public function add()
{
}
public function edit()
{
}
}

View File

@ -1,35 +0,0 @@
<?php
namespace App\Controllers\Produccion;
use App\Controllers\BaseController;
class Ordentrabajomaquetacion extends BaseController
{
function __construct()
{
}
public function index()
{
echo 'Orden maquetación';
}
public function delete()
{
}
public function add()
{
}
public function edit()
{
}
}

View File

@ -1,35 +0,0 @@
<?php
namespace App\Controllers\Produccion;
use App\Controllers\BaseController;
class Pedidoproduccion extends BaseController
{
function __construct()
{
}
public function index()
{
echo 'Pedido produccion';
}
public function delete()
{
}
public function add()
{
}
public function edit()
{
}
}

View File

@ -54,10 +54,10 @@ class Backups extends BaseController
}
// === 2. Backups remotos en SFTP ===
$sftpHost = getenv('HIDRIVE_HOST');
$sftpUser = getenv('HIDRIVE_USER');
$sftpPass = getenv('HIDRIVE_PASS');
$remoteDir = '/users/erp2019/backups_erp/';
$sftpHost = getenv('HIDRIVE_BK_HOST');
$sftpUser = getenv('HIDRIVE_BK_USER');
$sftpPass = getenv('HIDRIVE_BK_PASS');
$remoteDir = getenv('HIDRIVE_BK_PATH_ROOT');
$sftp = new SFTP($sftpHost);
if ($sftp->login($sftpUser, $sftpPass)) {
@ -269,9 +269,10 @@ class Backups extends BaseController
}
if (!empty($remotePath)) {
$sftpHost = getenv('HIDRIVE_HOST');
$sftpUser = getenv('HIDRIVE_USER');
$sftpPass = getenv('HIDRIVE_PASS');
$sftpHost = getenv('HIDRIVE_BK_HOST');
$sftpUser = getenv('HIDRIVE_BK_USER');
$sftpPass = getenv('HIDRIVE_BK_PASS');
$sftp = new SFTP($sftpHost);
@ -307,10 +308,10 @@ class Backups extends BaseController
}
// También se puede intentar buscar en el SFTP si quieres
$sftpHost = getenv('HIDRIVE_HOST');
$sftpUser = getenv('HIDRIVE_USER');
$sftpPass = getenv('HIDRIVE_PASS');
$remotePath = '/users/erp2019/backups_erp/' . $filename;
$sftpHost = getenv('HIDRIVE_BK_HOST');
$sftpUser = getenv('HIDRIVE_BK_USER');
$sftpPass = getenv('HIDRIVE_BK_PASS');
$remotePath = getenv('HIDRIVE_BK_PATH_ROOT') . $filename;
$sftp = new SFTP($sftpHost);
if ($sftp->login($sftpUser, $sftpPass)) {
@ -379,6 +380,7 @@ class Backups extends BaseController
public function restoreLocal($file)
{
$path = WRITEPATH . 'backups/' . $file;
if (!file_exists($path)) {
throw new \CodeIgniter\Exceptions\PageNotFoundException("Backup no encontrado.");
}
@ -399,21 +401,37 @@ class Backups extends BaseController
$sqlFile = $sqlFiles[0];
$dbConfig = config('Database')->default;
$host = $dbConfig['hostname'];
$username = $dbConfig['username'];
$password = $dbConfig['password'];
$database = $dbConfig['database'];
$cmd = "mysql -h {$host} -u{$username} -p'{$password}' {$database} < {$sqlFile}";
system($cmd, $retval);
if ($retval !== 0) {
throw new \RuntimeException("Error al restaurar la base de datos. Código: $retval");
// === Verificar que el archivo SQL existe y tiene contenido
if (!file_exists($sqlFile)) {
throw new \RuntimeException("Archivo SQL no encontrado.");
}
array_map('unlink', glob($extractPath . '*'));
rmdir($extractPath);
if (filesize($sqlFile) === 0) {
throw new \RuntimeException("El archivo SQL está vacío.");
}
// === Configuración de base de datos
$dbConfig = config('Database')->default;
$host = escapeshellarg($dbConfig['hostname']);
$username = escapeshellarg($dbConfig['username']);
$password = escapeshellarg($dbConfig['password']);
$database = escapeshellarg($dbConfig['database']);
// === Construcción del comando con stderr redirigido
$cmd = "mysql -h $host -u $username -p$password $database -e \"source $sqlFile\" 2>&1";
// === Ejecutar y capturar la salida
exec($cmd, $output, $retval);
// === Verificar resultado
if ($retval !== 0) {
throw new \RuntimeException("Error al restaurar la base de datos:\n" . implode("\n", $output));
}
// === Limpieza
helper('filesystem');
delete_files($extractPath, true); // elimina contenido
rmdir($extractPath); // elimina el directorio
return redirect()->to(route_to('backupsList'))->with('message', 'Backup restaurado correctamente (vía sistema).');
} else {
@ -424,60 +442,82 @@ class Backups extends BaseController
public function restoreRemote($filename)
{
helper('filesystem');
// Buscar el backup en la base de datos
$entorno = getenv('SK_ENVIRONMENT');
if ($entorno === 'development') {
// Construir ruta remota directamente
$remotePath = '/users/erp2019/backups_erp/' . $filename;
$localPath = WRITEPATH . 'backups/' . $filename;
$sftpHost = getenv('HIDRIVE_BK_HOST');
$sftpUser = getenv('HIDRIVE_BK_USER');
$sftpPass = getenv('HIDRIVE_BK_PASS');
$sftp = new SFTP($sftpHost);
if (!$sftp->login($sftpUser, $sftpPass)) {
return redirect()->to(route_to('backupsList'))->with('error', 'No se pudo autenticar en el servidor SFTP.');
}
$fileContents = $sftp->get($remotePath);
if ($fileContents === false) {
return redirect()->to(route_to('backupsList'))->with('error', 'No se pudo descargar el archivo remoto.');
}
if (write_file($localPath, $fileContents) === false) {
return redirect()->to(route_to('backupsList'))->with('error', 'No se pudo guardar el archivo localmente.');
}
// Restaurar directamente
return $this->restoreLocal($filename);
}
// Producción: flujo normal con base de datos
$backup = $this->backupModel->where('filename', $filename)->first();
if (!$backup || empty($backup['path_remote'])) {
return redirect()->to(route_to('backupsList'))->with('error', 'Backup remoto no encontrado en la base de datos.');
}
// Parámetros SFTP
$sftpHost = getenv('HIDRIVE_HOST');
$sftpUser = getenv('HIDRIVE_USER');
$sftpPass = getenv('HIDRIVE_PASS');
$remotePath = $backup['path_remote'];
$localPath = WRITEPATH . 'backups/' . $filename;
// Conectar al SFTP
$sftp = new SFTP($sftpHost);
$sftpHost = getenv('HIDRIVE_BK_HOST');
$sftpUser = getenv('HIDRIVE_BK_USER');
$sftpPass = getenv('HIDRIVE_BK_PASS');
$sftp = new SFTP($sftpHost);
if (!$sftp->login($sftpUser, $sftpPass)) {
return redirect()->to(route_to('backupsList'))->with('error', 'No se pudo autenticar en el servidor SFTP.');
}
// Descargar el archivo
$fileContents = $sftp->get($remotePath);
if ($fileContents === false) {
return redirect()->to(route_to('backupsList'))->with('error', 'No se pudo descargar el archivo remoto.');
}
// Guardar localmente
if (write_file($localPath, $fileContents) === false) {
return redirect()->to(route_to('backupsList'))->with('error', 'No se pudo guardar el archivo localmente.');
}
// Actualizar la base de datos para marcar el archivo como local
$this->backupModel->update($backup['id'], [
'path_local' => $localPath,
]);
$this->backupModel->update($backup['id'], ['path_local' => $localPath]);
// Restaurar usando el método local
return $this->restoreLocal($filename);
}
private function sendToSFTP($localPath, $remoteFilename)
{
$sftpHost = getenv('HIDRIVE_HOST');
$sftpUser = getenv('HIDRIVE_USER');
$sftpPass = getenv('HIDRIVE_PASS');
$remotePath = '/users/erp2019/backups_erp/' . $remoteFilename;
$sftpHost = getenv('HIDRIVE_BK_HOST');
$sftpUser = getenv('HIDRIVE_BK_USER');
$sftpPass = getenv('HIDRIVE_BK_PASS');
$remotePath = getenv('HIDRIVE_BK_PATH_ROOT') . $remoteFilename;
$sftp = new SFTP($sftpHost);

View File

@ -3,6 +3,7 @@
namespace App\Controllers\Sistema;
use CodeIgniter\Controller;
use App\Models\Presupuestos\PresupuestoFicheroModel;
class Intranet extends Controller
{
@ -11,25 +12,24 @@ class Intranet extends Controller
{
helper('file');
$resource_path = WRITEPATH . 'uploads/presupuestos/' . $resource_name;
$model = new PresupuestoFicheroModel();
$file = $model->where('file_path LIKE', "%{$resource_name}")->first();
if (file_exists($resource_path)) {
// Get the mime type of the file
$mime_type = mime_content_type($resource_path);
// Get an instance of the Response class
$response = service('response');
// Set the content type
$response->setContentType($mime_type);
// Set the output
$response->setBody(file_get_contents($resource_path));
// Send the response to the browser
$response->send();
if (!$file) {
return service('response')->setStatusCode(404)->setBody("Archivo no encontrado");
}
$resource_path = WRITEPATH . $file->file_path;
if (file_exists($resource_path)) {
$mime_type = mime_content_type($resource_path);
$response = service('response');
$response->setContentType($mime_type);
$response->setBody(file_get_contents($resource_path));
$response->send();
} else {
return service('response')->setStatusCode(404)->setBody("Archivo no encontrado");
}
}
function tickets($resource_name)
@ -54,7 +54,6 @@ class Intranet extends Controller
// Send the response to the browser
$response->send();
}
}
function orden_trabajo($ot_id, $resource_name)
{
@ -76,7 +75,6 @@ class Intranet extends Controller
// Send the response to the browser
$response->send();
}
}
function catalogo($catalogo_id, $resource_name)
@ -99,7 +97,5 @@ class Intranet extends Controller
// Send the response to the browser
$response->send();
}
}
}
}

View File

@ -25,6 +25,8 @@ class ServiciosAcabado extends BaseResourceController
protected $indexRoute = 'serviciosAcabadoList';
protected $deletePermission = 'tarifa-acabado.delete';
public function initController(\CodeIgniter\HTTP\RequestInterface $request, \CodeIgniter\HTTP\ResponseInterface $response, \Psr\Log\LoggerInterface $logger)
{

View File

@ -28,6 +28,8 @@ class TarifaAcabados extends BaseResourceController
protected $indexRoute = 'tarifaAcabadoList';
protected $deletePermission = 'tarifa-acabado.delete';
public function initController(\CodeIgniter\HTTP\RequestInterface $request, \CodeIgniter\HTTP\ResponseInterface $response, \Psr\Log\LoggerInterface $logger)
{

View File

@ -19,6 +19,8 @@ class Tarifaextra extends \App\Controllers\GoBaseController
protected $indexRoute = 'tarifaextraList';
protected $deletePermission = 'tarifa-extra.delete';
public function initController(\CodeIgniter\HTTP\RequestInterface $request, \CodeIgniter\HTTP\ResponseInterface $response, \Psr\Log\LoggerInterface $logger)
{

View File

@ -19,6 +19,8 @@ class Tarifapreimpresion extends \App\Controllers\GoBaseController
protected $indexRoute = 'tarifapreimpresionList';
protected $deletePermission = 'tarifa-preimpresion.delete';
public function initController(\CodeIgniter\HTTP\RequestInterface $request, \CodeIgniter\HTTP\ResponseInterface $response, \Psr\Log\LoggerInterface $logger)
{

View File

@ -32,6 +32,8 @@ class Tarifasencuadernacion extends \App\Controllers\BaseResourceController
protected $indexRoute = 'tarifaEncuadernacionList';
protected $deletePermission = 'tarifa-encuadernacion.delete';
public function initController(\CodeIgniter\HTTP\RequestInterface $request, \CodeIgniter\HTTP\ResponseInterface $response, \Psr\Log\LoggerInterface $logger)
{

View File

@ -28,6 +28,8 @@ class Tarifasmanipulado extends \App\Controllers\BaseResourceController
protected $indexRoute = 'tarifaManipuladoList';
protected $deletePermission = 'tarifa-manipulado.delete';
public function initController(\CodeIgniter\HTTP\RequestInterface $request, \CodeIgniter\HTTP\ResponseInterface $response, \Psr\Log\LoggerInterface $logger)
{

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,24 @@
<?php
namespace App\Database\Migrations;
use CodeIgniter\Database\Migration;
class ConfigDireccionesFerroPrototipo extends Migration
{
public function up()
{
$this->forge->addColumn('presupuestos', [
'direcciones_fp_checks' => [
'type' => 'JSON',
'null' => false,
'default' => '{"addFP1isAddMain": "0", "addFP2isAddMain": "0", "addFP2isaddFP1": "0"}',
'comment' => 'valores de los checks de las direcciones ferro/prototipo',
],
]);
}
public function down()
{
$this->forge->dropColumn('presupuestos', 'direcciones_fp_checks');
}
}

View File

@ -0,0 +1,25 @@
<?php
namespace App\Database\Migrations;
use CodeIgniter\Database\Migration;
class AumentoLomoFijo extends Migration
{
public function up()
{
$this->db->table('config_variables_app')->insert([
'name' => 'aumento_fijo_lomo_interior',
'value' => '1.3',
'description' => 'Aumento fijo del lomo interior por cola (se añade en el interior)',
'created_at' => date('Y-m-d H:i:s')
]);
}
public function down()
{
// Borrar los nuevos campos
$this->db->table('config_variables_app')->whereIn('name', [
'aumento_fijo_lomo_interior'
])->delete();
}
}

View File

@ -0,0 +1,33 @@
<?php
namespace App\Database\Migrations;
use CodeIgniter\Database\Migration;
class FerroPrototipo2 extends Migration
{
public function up()
{
$this->db->table('config_variables_app')->insert([
'name' => 'id_servicio_ferro_2',
'value' => '31',
'description' => 'D del servicio extra "ferro (2 unidades)" que aparece en los presupuestos',
'created_at' => date('Y-m-d H:i:s')
]);
$this->db->table('config_variables_app')->insert([
'name' => 'id_servicio_prototipo_2',
'value' => '28',
'description' => 'D del servicio extra "Prototipo (2 unidades)" que aparece en los presupuestos',
'created_at' => date('Y-m-d H:i:s')
]);
}
public function down()
{
// Borrar los nuevos campos
$this->db->table('config_variables_app')->whereIn('name', [
'id_servicio_ferro_2',
'id_servicio_prototipo_2'
])->delete();
}
}

View File

@ -0,0 +1,68 @@
<?php
namespace App\Database\Migrations;
use CodeIgniter\Database\Migration;
class CreateTiposPapelGenerico extends Migration
{
public function up()
{
// Crear tabla tipos_papel_generico
$this->forge->addField([
'id' => [
'type' => 'INT',
'unsigned' => true,
'auto_increment' => true,
],
'clave' => [
'type' => 'VARCHAR',
'constraint' => '50',
'unique' => true,
],
]);
$this->forge->addKey('id', true);
$this->forge->createTable('tipos_papel_generico');
// Insertar claves
$data = [
['clave' => 'offset_blanco'],
['clave' => 'offset_ahuesado'],
['clave' => 'estucados'],
['clave' => 'volumen'],
['clave' => 'especiales'],
['clave' => 'reciclados'],
['clave' => 'cartulinas'],
['clave' => 'verjurados'],
];
$this->db->table('tipos_papel_generico')->insertBatch($data);
// Añadir columna tipo_papel_generico_id a lg_papel_generico
$this->forge->addColumn('lg_papel_generico', [
'tipo_papel_generico_id' => [
'type' => 'INT',
'unsigned' => true,
'null' => true,
'after' => 'id', // Ajusta si deseas colocarla en otro lugar
]
]);
// Agregar constraint foreign key
$this->db->query(
'ALTER TABLE lg_papel_generico
ADD CONSTRAINT fk_tipo_papel_generico
FOREIGN KEY (tipo_papel_generico_id)
REFERENCES tipos_papel_generico(id)
ON DELETE SET NULL
ON UPDATE CASCADE'
);
}
public function down()
{
// Eliminar foreign key primero
$this->db->query('ALTER TABLE lg_papel_generico DROP FOREIGN KEY fk_tipo_papel_generico');
$this->forge->dropColumn('lg_papel_generico', 'tipo_papel_generico_id');
$this->forge->dropTable('tipos_papel_generico');
}
}

View File

@ -0,0 +1,27 @@
<?php
namespace App\Database\Migrations;
use CodeIgniter\Database\Migration;
class AddIsknToPresupuestos extends Migration
{
public function up()
{
$this->forge->addColumn('presupuestos', [
'iskn' => [
'type' => 'VARCHAR',
'constraint' => 64,
'null' => true,
'default' => null,
'after' => 'coleccion', // o cualquier campo existente tras el cual quieras insertarlo
'collation' => 'utf8_unicode_ci',
],
]);
}
public function down()
{
$this->forge->dropColumn('presupuestos', 'iskn');
}
}

View File

@ -16,11 +16,13 @@ class PapelGenerico extends \CodeIgniter\Entity\Entity
"activo" => false,
"created_at" => null,
"updated_at" => null,
"tipo_papel_generico_id" => null,
];
protected $casts = [
"show_in_client" => "boolean",
"activo" => "boolean",
"show_in_client_special" => "boolean",
"is_deleted" => "int",
"tipo_papel_generico_id" => "int",
];
}

View File

@ -0,0 +1,11 @@
<?php
namespace App\Entities\Configuracion;
use CodeIgniter\Entity;
class TipoPapelGenerico extends \CodeIgniter\Entity\Entity
{
protected $attributes = [
"clave" => null,
];
}

View File

@ -47,6 +47,7 @@ class PresupuestoEntity extends \CodeIgniter\Entity\Entity
"titulo" => "",
"autor" => null,
"coleccion" => null,
"iskn" => null,
"numero_edicion" => null,
"isbn" => null,
"referencia_cliente" => null,
@ -117,6 +118,12 @@ class PresupuestoEntity extends \CodeIgniter\Entity\Entity
'lomo_redondo' => null,
'cabezada' => null,
'envio_base' => null,
'direcciones_fp_checks' => [
'addFP1isAddMain' => "false",
'addFP2isAddMain' => "false",
'addFP2isaddFP1' => "false"
],
];
protected $casts = [
"cliente_id" => "int",
@ -190,6 +197,7 @@ class PresupuestoEntity extends \CodeIgniter\Entity\Entity
'papel_interior_diferente' => "boolean",
'paginasCuadernillo' => "int",
'lomo_redondo' => "boolean",
'direcciones_fp_checks' => 'json',
];
/**
* Devuelve la entity con un campo `presupuesto_lineas` con las lineas de presupuesto asociadas
@ -326,4 +334,15 @@ class PresupuestoEntity extends \CodeIgniter\Entity\Entity
}
return $tipo_presupuesto;
}
public function getDireccionFPChecks()
{
return $this->attributes['direcciones_fp_checks'] ?? [];
}
public function setDireccionFPChecks($value)
{
$this->attributes['direcciones_fp_checks'] = is_array($value) ? json_encode($value) : $value;
return $this;
}
}

View File

@ -101,6 +101,20 @@ function getGravatarURL(int $size = 30)
{
return "https://gravatar.com/avatar/".md5(auth()->user()->getEmail())."?s=".$size;
}
if (!function_exists('gravatar_url')) {
function gravatar_url(?string $email, int $size = 40): string
{
if (!$email) {
return "https://www.gravatar.com/avatar/?s={$size}&d=mp";
}
return "https://www.gravatar.com/avatar/" . md5(strtolower(trim($email))) . "?s={$size}&d=identicon";
}
}
function getAllClassFolder($folder = null){
try {
helper('filesystem');

View File

@ -123,7 +123,7 @@ if (!function_exists('checkPermission')) {
$response = \Config\Services::response();
if (!auth()->user()->can($sectionPermission)) {
$session->setFlashdata('errorMessage', "No tiene permisos de acceso");
$session->setFlashdata('errorMessage', lang('Basic.global.permissionDenied'));
$route = $redirectRoute ?? 'home';
return $response->redirect(route_to($route));

View File

@ -90,6 +90,7 @@ return [
'wait' => 'Wait',
'yes' => 'Yes',
'back' => 'Back',
'permissionDenied' => 'You do not have permission for this action'
],

View File

@ -35,6 +35,7 @@ return [
'coleccion' => 'Collection',
'numeroEdicion' => 'Edition number',
'isbn' => 'ISBN',
'iskn' => 'Identificador ISKN',
'referenciaCliente' => 'Customer reference',
'formatoLibro' => "Book format",
'papelFormatoId' => "Size",

View File

@ -34,7 +34,7 @@ return [
"global_prev" => "Anterior",
"global_next" => "Siguiente",
"global_save_file" => "Guardar ficheros",
"global_upload_files" => "Subir ficheros",
"global_select_files" => "Seleccionar ficheros",
"global_download_files" => "Descargar ficheros",
"global_all" => "Todos",
// LOGIN - Index
@ -757,7 +757,7 @@ return [
"menu_tarifaextra" => "Serv. Extra",
"menu_tarifamanipulado" => "Manipulado",
"menu_tarifaencuadernacion" => "Encuadernación",
"menu_tarifapapelcompra" => "Papel compra",
"menu_tarifapapelcompra" => "Papel impresión",
"menu_servicioAcabado" => "Servicios acabado",
"menu_tarifaacabado" => "Acabado",
"menu_tarifapapeldefecto" => "Papel defecto",

View File

@ -94,6 +94,7 @@ return [
'yes' => 'Si',
'no' => 'No',
'back' => 'Volver',
'permissionDenied' => 'No tiene permisos de acceso'
],

View File

@ -6,6 +6,7 @@ return [
'code' => 'Código',
'codeOt' => 'Código Ot',
'createdAt' => 'Creado el',
'tipo_papel_generico_id' => 'Tipo Papel Genérico',
'deletedAt' => 'Deleted At',
'id' => 'ID',
'activo' => 'Activo',
@ -21,6 +22,16 @@ return [
'updatedAt' => 'Actualizado el',
'form_acordion_title' => 'Propiedades Papel Genérico',
// Tipos de papel genérico
'offset_blanco' => 'Offset Blanco',
'offset_ahuesado' => 'Offset Ahuesado',
'estucados' => 'Estucados',
'volumen' => 'Volumen',
'especiales' => 'Especiales',
'reciclados' => 'Reciclados',
'cartulinas' => 'Cartulinas',
'verjurados' => 'Verjurados',
'validation' => [
'code' => [
'max_length' => 'El campo {field} no puede exceder {param} caracteres en longitud.',

View File

@ -80,8 +80,10 @@ return [
'acabadoFaja' => 'Acabado Faja',
'cosido' => 'Cosido',
'ferro' => 'Ferro',
'ferro_2' => 'Ferro (2 uds.)',
'ferroDigital' => 'Ferro Digital',
'prototipo' => 'Prototipo',
'prototipo_2' => 'Prototipo (2 uds.)',
'imagenesBnInterior' => 'Imágenes B/N interior',
'recogerEnTaller' => 'Recoger en taller',
'marcapaginas' => 'Marcapáginas',
@ -305,7 +307,7 @@ return [
'previewSobrecubierta' => 'Configuración del papel: Sobrecubierta',
'previewFaja' => 'Configuración del papel: Faja',
'previewPapelGenerico' => 'Papel Genérico',
'previewPapelCompra' => 'Papel de Compra',
'previewPapelCompra' => 'Papel Impresión',
'previewAreaImpresion' => 'Área de Impresión',
'previewPosicionFormas' => 'Posición de Formas',
'previewDetalles' => 'Detalles del trabajo',
@ -436,6 +438,9 @@ return [
'paginas_multiplo_4' => 'El número total de páginas para <b>cosido</b> y <b>grapado</b> debe ser múltiplo de 4',
'paginas_pares' => 'El número de páginas debe ser par',
'extras_cubierta' => 'Rellene todos los campos',
'error_sameAddPrincipal_FP' => 'Debe añadir al menos una dirección en el envío para usarla',
'error_sameAddFP1' => 'Debe añadir al menos una dirección en el envío del primer ferro para usarla.'
],
'errores' => [
@ -463,6 +468,7 @@ return [
Por favor, disminuya el número de páginas o el gramaje del papel para que sea encuadernable.",
'error_lomo_minimo' => "No se pueden encuadernar libros {0} con un lomo interior inferior a {1} mm. El lomo actual es de {2} mm. <br>
Por favor, aumente el número de páginas o el gramaje del papel para que sea encuadernable.",
'error_direccion_principal_no_encontrada' => 'No se ha encontrado la dirección en las direcciones del cliente. Por favor, añádala antes de marcar esta opción.',
],
'resize_preview' => 'Refrescar vista esquema'

View File

@ -15,52 +15,23 @@ class SafekatFtpClient
protected string $username;
protected string $password;
protected string $base_dir;
protected bool $xml_enabled;
protected object $pedido_xml_config;
public function __construct()
{
$this->pedido_xml_config = config("PedidoXML");
$this->pedido_xml_config = config("PresupuestoSFTP");
$this->host = $this->pedido_xml_config->host;
$this->username = $this->pedido_xml_config->username;
$this->password = $this->pedido_xml_config->password;
$this->port = $this->pedido_xml_config->port;
$this->base_dir = $this->pedido_xml_config->base_dir;
$this->xml_enabled = $this->pedido_xml_config->xml_enabled;
$this->ftp = new SFTP($this->host);
}
/**
* Upload the content of $filename to the base directory declared in App\Config\FTP.php
*
* @param string $content
* @param string $filename
* @return boolean
*/
public function uploadXML(string $content, string $filename): bool
{
try {
if ($this->xml_enabled == false)
return false;
$remotePath = implode("/", [$this->base_dir, 'pedidos', 'xml_nuevos']);
$this->ftp->login(username: $this->username, password: $this->password);
if (!$this->ftp->is_dir($remotePath)) {
$this->ftp->mkdir($remotePath, recursive: true);
}
$this->ftp->put($remotePath . '/' . $filename, $content);
return true;
} catch (\Throwable $th) {
throw $th;
log_message('error', $th->getMessage());
return false;
}
}
public function uploadFilePresupuesto(int $presupuesto_id)
{
try {
if ($this->xml_enabled == false)
return false;
$model = model(PresupuestoFicheroModel::class);
$modelPedidoLinea = model(PedidoLineaModel::class);
$pedidoLinea = $modelPedidoLinea->findByPresupuesto($presupuesto_id);
@ -86,7 +57,6 @@ class SafekatFtpClient
public function removeFiles(int $presupuesto_id)
{
try {
// if ($this->xml_enabled == false) return false;
$model = model(PresupuestoFicheroModel::class);
$modelPedidoLinea = model(PedidoLineaModel::class);
$pedidoLinea = $modelPedidoLinea->findByPresupuesto($presupuesto_id);
@ -115,7 +85,7 @@ class SafekatFtpClient
return implode('/', [$this->base_dir, 'pedidos_files', $rootIdExtern]);
}
public function downloadZipPresupuesto(int $presupuesto_id): ?string
public function downloadZipPresupuesto(int $presupuesto_id, ?string $prefijo = null): ?string
{
$modelPedidoLinea = model(PedidoLineaModel::class);
$model = model(PresupuestoFicheroModel::class);
@ -143,8 +113,11 @@ class SafekatFtpClient
foreach ($files as $file) {
$originalName = $file->nombre ?? basename($file->file_path);
$localFile = $localTempDir . '/' . $originalName;
$prefixedName = $prefijo ? $prefijo . '_' . $originalName : $originalName;
$localFile = $localTempDir . '/' . $prefixedName;
$remoteFile = $remotePath . '/' . basename($file->file_path);
$this->ftp->get($remoteFile, $localFile);
}
@ -167,4 +140,5 @@ class SafekatFtpClient
}
}

View File

@ -0,0 +1,47 @@
<?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);
}
public function get(string $remotePath, string $localPath): bool
{
return $this->client->get($remotePath, $localPath);
}
}

View File

@ -56,4 +56,40 @@ class ConfigVariableModel extends Model
return $builder->get()->getFirstRow();
}
/**
* Devuelve solo el valor de la variable por nombre
*/
public function getValue(string $name): ?string
{
$row = $this->getVariable($name);
return $row ? $row->value : null;
}
/**
* Devuelve el valor decodificado (JSON) si aplica
*/
public function getDecodedValue(string $name): ?array
{
$value = $this->getValue($name);
$decoded = json_decode($value, true);
return (json_last_error() === JSON_ERROR_NONE && is_array($decoded)) ? $decoded : null;
}
/**
* Devuelve las opciones disponibles de cabezadas (como array clave => langKey)
*/
public function getCabezadasDisponibles(): array
{
return $this->getDecodedValue('cabezadas_disponibles') ?? [];
}
/**
* Devuelve la cabezada por defecto, o 'WHI' si no está definida
*/
public function getCabezadaDefault(): string
{
return $this->getValue('cabezada_default') ?? 'WHI';
}
}

View File

@ -22,7 +22,18 @@ class PapelGenericoModel extends \App\Models\BaseModel
4 => "t1.show_in_client_special",
];
protected $allowedFields = ["nombre", "code", "code_ot", "show_in_client", "show_in_client_special", "deleted_at", "is_deleted", "activo"];
protected $allowedFields =
[
"nombre",
"code",
"code_ot",
"show_in_client",
"show_in_client_special",
"deleted_at",
"is_deleted",
"activo",
"tipo_papel_generico_id",
];
protected $returnType = "App\Entities\Configuracion\PapelGenerico";
protected $useTimestamps = true;
@ -132,16 +143,16 @@ class PapelGenericoModel extends \App\Models\BaseModel
return empty($search)
? $builder
: $builder
->groupStart()
->like("t1.id", $search)
->orLike("t1.nombre", $search)
->orLike("t1.code", $search)
->orLike("t1.code_ot", $search)
->orLike("t1.id", $search)
->orLike("t1.nombre", $search)
->orLike("t1.code", $search)
->orLike("t1.code_ot", $search)
->groupEnd();
->groupStart()
->like("t1.id", $search)
->orLike("t1.nombre", $search)
->orLike("t1.code", $search)
->orLike("t1.code_ot", $search)
->orLike("t1.id", $search)
->orLike("t1.nombre", $search)
->orLike("t1.code", $search)
->orLike("t1.code_ot", $search)
->groupEnd();
}

View File

@ -0,0 +1,22 @@
<?php
namespace App\Models\Configuracion;
class TipoPapelGenericoModel extends \App\Models\BaseModel
{
protected $table = "tipos_papel_generico";
/**
* Whether primary key uses auto increment.
*
* @var bool
*/
protected $useAutoIncrement = true;
protected $allowedFields = [
"clave",
];
protected $returnType = "App\Entities\Configuracion\TipoPapelGenerico";
}

View File

@ -2,6 +2,8 @@
namespace App\Models\Presupuestos;
use Config\Paths;
class PresupuestoFicheroModel extends \App\Models\BaseModel
{
protected $table = "presupuesto_ficheros";
@ -23,16 +25,42 @@ class PresupuestoFicheroModel extends \App\Models\BaseModel
public static $labelField = "nombre";
/**
* Devuelve la ruta relativa del archivo dentro de WRITEPATH.
*
* @param int $presupuesto_id
* @param string $filename
* @return string
*/
public function getRelativePath(int $presupuesto_id, string $filename): string
{
return config(Paths::class)->presupuestosPath . '/' . $presupuesto_id . '/' . $filename;
}
/**
* Devuelve la ruta absoluta en el sistema de archivos del servidor.
*
* @param int $presupuesto_id
* @param string $filename
* @return string
*/
public function getAbsolutePath(int $presupuesto_id, string $filename): string
{
return WRITEPATH . $this->getRelativePath($presupuesto_id, $filename);
}
public function saveFileInBBDD($presupuesto_id, $filename, $extension, $user_id)
{
try {
$new_filename = $this->generateFileHash($filename) . '.' . $extension;
$relativePath = $this->getRelativePath($presupuesto_id, $new_filename);
$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', $relativePath)
->set('upload_by', $user_id)
->set('upload_at', date('Y-m-d H:i:s'))
->insert();
@ -54,8 +82,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 +105,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 +137,30 @@ 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);
$deletedCount = 0;
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();
$deletedCount++;
}
}
return $deletedCount;
}
/**
* Función para convertir el nombre y extensión de un fichero en un hash único
@ -117,6 +173,4 @@ class PresupuestoFicheroModel extends \App\Models\BaseModel
{
return hash('sha256', $filename);
}
}

View File

@ -67,6 +67,7 @@ class PresupuestoModel extends \App\Models\BaseModel
"titulo",
"autor",
"coleccion",
"iskn",
"numero_edicion",
"isbn",
"referencia_cliente",
@ -139,6 +140,7 @@ class PresupuestoModel extends \App\Models\BaseModel
'lomo_redondo',
'cabezada',
'envio_base',
'direcciones_fp_checks',
];
protected $returnType = "App\Entities\Presupuestos\PresupuestoEntity";
@ -400,15 +402,27 @@ class PresupuestoModel extends \App\Models\BaseModel
}
}
function confirmarPresupuesto($presupuesto_id)
/**
* Confirma un presupuesto (cambia su estado a 'confirmado') y,
* si no tiene asignado un ISKN, lo genera y lo asigna automáticamente.
*
* @param int $presupuesto_id ID del presupuesto a confirmar.
* @return void
*/
public function confirmarPresupuesto($presupuesto_id)
{
// Cambiar el estado del presupuesto a '2' (confirmado)
$this->db
->table($this->table . " t1")
->where('t1.id', $presupuesto_id)
->set('t1.estado_id', 2)
->update();
// Si existe y aún no tiene ISKN asignado, lo generamos y asignamos
$this->asignarIskn($presupuesto_id);
}
function insertarPresupuestoCliente($id, $tirada, $data, $data_cabecera, $extra_info, $resumen_totales, $iva_reducido, $excluir_rotativa, $tiradas_alternativas)
{
@ -500,8 +514,8 @@ class PresupuestoModel extends \App\Models\BaseModel
'total_antes_descuento' => round(
$totalCostes + $totalMargenes +
$resumen_totales['coste_envio'] + $resumen_totales['margen_envio'] +
$data['envio_base'],
$resumen_totales['coste_envio'] + $resumen_totales['margen_envio'] +
$data['envio_base'],
2
),
'total_descuento' => 0,
@ -510,31 +524,33 @@ class PresupuestoModel extends \App\Models\BaseModel
'total_precio_unidad' => $resumen_totales['precio_unidad'],
'total_presupuesto' => round(
$totalCostes + $totalMargenes +
$resumen_totales['coste_envio'] + $resumen_totales['margen_envio'] +
$data['envio_base'],
$resumen_totales['coste_envio'] + $resumen_totales['margen_envio'] +
$data['envio_base'],
2
),
'total_aceptado' => round(
$totalCostes + $totalMargenes +
$resumen_totales['coste_envio'] + $resumen_totales['margen_envio'] +
$data['envio_base'],
$resumen_totales['coste_envio'] + $resumen_totales['margen_envio'] +
$data['envio_base'],
2
),
'total_factor' => round(
($totalCostes + $totalMargenes) /
$resumen_totales['sumForFactor'],
$resumen_totales['sumForFactor'],
2
),
'total_factor_ponderado' => round(
($totalCostes + $totalMargenes) /
$resumen_totales['sumForFactorPonderado'],
$resumen_totales['sumForFactorPonderado'],
2
),
'iva_reducido' => $iva_reducido,
'excluir_rotativa' => $excluir_rotativa,
'direcciones_fp_checks' => $data['direcciones_fp_checks'] ? json_encode($data['direcciones_fp_checks']) : null,
];
/* Actualizacion */
if ($id != 0) {
@ -632,7 +648,6 @@ class PresupuestoModel extends \App\Models\BaseModel
'gramaje' => intval($data['faja']['gramaje']),
);
}
}
$json = json_encode($values);
return $json;
@ -912,5 +927,19 @@ class PresupuestoModel extends \App\Models\BaseModel
]);
}
public function asignarIskn(int $presupuesto_id): bool
{
$presupuesto = $this->find($presupuesto_id);
// Si no existe o ya tiene ISKN, no lo modificamos
if (!$presupuesto || !empty($presupuesto->iskn)) {
return false;
}
return $this->update($presupuesto_id, [
'iskn' => model('App\Models\Catalogo\IdentificadorIsknModel')->newIskn(),
'updated_at' => date('Y-m-d H:i:s'),
'user_update_id' => auth()->id(),
]);
}
}

View File

@ -100,6 +100,18 @@ class GroupModel extends \App\Models\BaseModel
->countAllResults();
}
public function getUsersByRol(string $groupKeyWord)
{
return $this->db
->table('auth_groups_users agu')
->select('u.id, ai.secret as email, u.first_name, u.last_name')
->join('users u', 'u.id = agu.user_id')
->join('auth_identities ai', 'ai.user_id = u.id AND ai.type = "email_password"', 'left')
->where('agu.group', $groupKeyWord)
->get()
->getResult();
}
public function getUsersRoles($userId)
{

View File

@ -0,0 +1,27 @@
<?php
namespace App\Services;
use CodeIgniter\Config\BaseService;
use App\Models\Configuracion\TipoPapelGenericoModel;
class PapelService extends BaseService
{
protected TipoPapelGenericoModel $tipoPapelGenericoModel;
public function __construct()
{
$this->tipoPapelGenericoModel = model(TipoPapelGenericoModel::class);
}
public function getTipoPapelGenerico()
{
$values = $this->tipoPapelGenericoModel->findAll();
$tipoPapelGenericoList = [];
foreach ($values as $value) {
$tipoPapelGenericoList[$value->id] = lang('PapelGenerico.' . $value->clave);
}
return $tipoPapelGenericoList;
}
}

View File

@ -1,222 +0,0 @@
<?php
namespace App\Services;
use DOMDocument;
use App\Libraries\SafekatFtpClient;
use CodeIgniter\Config\BaseService;
use App\Models\Pedidos\PedidoModel;
use App\Models\Presupuestos\PresupuestoModel;
class PedidoXMLService extends BaseService
{
public static function get_pedido_presupuesto(int $pedido_id)
{
$data_xml = [];
$pedidoModel = model(PedidoModel::class);
$presupuestoModel = model(PresupuestoModel::class);
$data_xml['pedido_cliente_presupuesto'] = $pedidoModel->getPedidoClientePresupuesto($pedido_id);
$data_xml['pedido_presupuesto_direcciones'] = $pedidoModel->getPedidoPresupuestoDirecciones($pedido_id);
$data_xml['pedido_presupuesto_lineas'] = $pedidoModel->getPedidoPresupuestoLineas($pedido_id);
$servicios = $presupuestoModel->getServiciosPresupuesto($data_xml['pedido_cliente_presupuesto']->presupuestoId);
$data_xml['servicios'] = $servicios;
$data_xml['preimpresion'] = PedidoXMLService::parse_servicio_preimpresion($servicios['preimpresion']);
$data_xml["acabado"] = PedidoXMLService::parse_servicio_acabado($servicios['acabado']);
$data_xml["binding"] = PedidoXMLService::get_binding_code($data_xml['pedido_cliente_presupuesto']->codigoTipoImpresion,$data_xml['pedido_cliente_presupuesto']->solapas);
return $data_xml;
}
protected static function parse_servicio_acabado(array $data_xml_servicios_acabado)
{
$xml_element = [];
$service_xml_key_value = [
"ShrinkWrapping" => fn($nombre) => str_contains($nombre,"retractilado"),
"Finish" => fn($nombre) => str_contains($nombre,"brillo"),
"PlakeneT" =>fn($nombre) => str_contains($nombre,"plakene traslúcido"),];
foreach($data_xml_servicios_acabado as $servicio_acabado)
{
$service_name = strtolower($servicio_acabado->nombre);
foreach ($service_xml_key_value as $key => $value) {
$xml_element[$key] = $value($service_name) ? 1 : 0 ;
}
}
return $xml_element;
}
protected static function parse_servicio_preimpresion(array $data_xml_servicios_preimpresion)
{
$xml_element = [];
$service_xml_key_value = [
"Urgent" => fn($nombre) => str_contains($nombre,"Pedido urgente"),
"Prototype" => fn($nombre) => str_contains($nombre,"Prototipo"),
"Layout" =>fn($nombre) => str_contains($nombre,"Maquetación"),
"Correction" =>fn($nombre) => str_contains($nombre,"Corrección ortográfica"),
// "Review" =>fn($nombre) => str_contains($nombre,"Revisión Profesional de archivo"),
"Design" =>fn($nombre) => str_contains($nombre,'Diseño de Cubierta'),
];
foreach($data_xml_servicios_preimpresion as $servicio_pre)
{
$service_name = $servicio_pre->nombre;
foreach ($service_xml_key_value as $key => $value) {
$value_service = $value($service_name) ? 1 : 0 ;
if( $value_service){
$xml_element[$key] = $servicio_pre->precio ;
}else if(!isset($xml_element[$key])){
$xml_element[$key] = $value_service;
}
}
}
return $xml_element;
}
public static function generate_xml($pedido_id)
{
$papel_formato_ancho = 0;
$papel_formato_alto = 0;
$data = PedidoXMLService::get_pedido_presupuesto($pedido_id);
$xml = new DOMDocument('1.0', 'utf-8');
$xml_order_el = $xml->createElement('Order');
$xml_header_el = $xml->createElement('Header');
$offset_pedido_id = env('XML_OFFSET_CUSTOMER_ID',1000000) + $data["pedido_cliente_presupuesto"]->pedidoId;
$xml_header_el->appendChild($xml->createElement('CustomerCode', $data["pedido_cliente_presupuesto"]->presupuestoClienteId));
$xml_header_el->appendChild($xml->createElement('CodeNode', env('NODE_CODE_XML','SFK')));
$xml_header_el->appendChild($xml->createElement('ExternId', $offset_pedido_id));
$xml_header_el->appendChild($xml->createElement('NumProducts', 1));
$xml_header_el->appendChild($xml->createElement('Date', now_db()));
$xml_order_el->appendChild($xml_header_el);
$xml_products_el = $xml->createElement('Products');
$xml_product_el = $xml->createElement('Product');
$xml_product_el->appendChild($xml->createElement('ItemId', $offset_pedido_id));
$xml_product_el->appendChild($xml->createElement('Quantity', $data["pedido_cliente_presupuesto"]->tirada));
$xml_product_el->appendChild($xml->createElement('Title', $data["pedido_cliente_presupuesto"]->titulo));
$xml_product_el->appendChild($xml->createElement('Pages', $data["pedido_cliente_presupuesto"]->paginas));
$xml_product_el->appendChild($xml->createElement('Reprint', $data["pedido_cliente_presupuesto"]->inc_rei ?? 0));
if ($data["pedido_cliente_presupuesto"]->papel_formato_personalizado) {
$papel_formato_ancho = $data["pedido_cliente_presupuesto"]->papelAnchoPersonalidado;
$papel_formato_alto = $data["pedido_cliente_presupuesto"]->papelAltoPersonalidado;
} else {
$papel_formato_ancho = $data["pedido_cliente_presupuesto"]->lgPapelFormatoAncho;
$papel_formato_alto = $data["pedido_cliente_presupuesto"]->lgPapelFormatoAlto;
}
$xml_product_el->appendChild($xml->createElement('Width', $papel_formato_ancho));
$xml_product_el->appendChild($xml->createElement('Height', $papel_formato_alto));
$presupuestoLineaTipoCubierta = null;
$xml_presupuesto_lineas_el = $xml->createElement('Lines');
## Iterate throught presupuesto_lineas
foreach ($data["pedido_presupuesto_lineas"] as $row) {
if (str_contains($row->tipo, "rot") || str_contains($row->tipo, "bn") || str_contains($row->tipo, "color")) {
$colorInterior = PedidoXMLService::get_color_interior($row);
$xmlInside = $xml->createElement('Inside');
$xmlInside->appendChild($xml->createElement('TypeOfPrint', $colorInterior));
$xmlInside->appendChild($xml->createElement('HQ', str_contains($row->tipo, 'hq') ? 1 : 0));
$xmlInside->appendChild($xml->createElement('Pages', $row->paginas));
$xmlInside->appendChild($xml->createElement('Paper', $row->papelCode));
$xmlInside->appendChild($xml->createElement('Weight', $row->gramaje));
$xml_presupuesto_lineas_el->appendChild($xmlInside);
} else if (str_contains($row->tipo, "lp_cubierta") ) {//|| str_contains($row->tipo, "sobrecubierta")
//? If both exists presupuestoLineaTipoCubierta is override by sobreCubierta making null and not adding
$papelCubiertaCode = $row->papelCode;
$papelCubiertaGramaje = $row->gramaje;
$presupuestoLineaTipoCubierta = $row->tipo == "lp_cubierta" ? $row : null;
}
}
$xml_product_el->appendChild($xml_presupuesto_lineas_el);
if ($presupuestoLineaTipoCubierta) {
$containsTarifaAcabadoBrillo = isset($data['acabado']['Finish']) ? true : false;
if ($containsTarifaAcabadoBrillo) {
$acabado = "brillo";
} else {
$acabado = "mate";
}
$xmlCover = $xml->createElement('Cover');
$xmlCover->appendChild($xml->createElement('Sides', $presupuestoLineaTipoCubierta->paginas / 2));
$xmlCover->appendChild($xml->createElement('Paper', $presupuestoLineaTipoCubierta->papelCode));
$xmlCover->appendChild($xml->createElement('Weight', $presupuestoLineaTipoCubierta->gramaje));
$xmlCover->appendChild($xml->createElement('Flaps', $data["pedido_cliente_presupuesto"]->solapas));
$xmlCover->appendChild($xml->createElement('WidthFlaps', $data["pedido_cliente_presupuesto"]->solapas_ancho));
$xmlCover->appendChild($xml->createElement('Finish', $acabado));
$xml_product_el->appendChild($xmlCover);
}
$xml_product_el->appendChild($xml->createElement('Binding', $data['binding']));
$xml_services_el = $xml->createElement('Services');
$xml_services_el->appendChild($xml->createElement('Bookmark', $data["pedido_cliente_presupuesto"]->marcapaginas));
foreach ($data['preimpresion'] as $key => $value) {
$xml_services_el->appendChild($xml->createElement($key, $value));
}
foreach ($data['acabado'] as $key => $value) {
$xml_services_el->appendChild($xml->createElement($key, $value));
}
$xml_product_el->appendChild($xml_services_el);
$xml_envios_el = $xml->createElement('Shipments');
foreach ($data["pedido_presupuesto_direcciones"] as $pedido_presupuesto_direccion) {
$xml_envio_el = $xml->createElement('Shipment');
$xml_envio_el->appendChild($xml->createElement('Qty', $pedido_presupuesto_direccion->cantidad));
$xml_envio_el->appendChild($xml->createElement('Price', $pedido_presupuesto_direccion->precio));
$xml_envio_el->appendChild($xml->createElement('Attention', $pedido_presupuesto_direccion->att));
$xml_envio_el->appendChild($xml->createElement('Email', $pedido_presupuesto_direccion->email));
$xml_envio_el->appendChild($xml->createElement('Address', $pedido_presupuesto_direccion->direccion));
$xml_envio_el->appendChild($xml->createElement('Province', $pedido_presupuesto_direccion->provincia));
$xml_envio_el->appendChild($xml->createElement('City', $pedido_presupuesto_direccion->municipio));
$xml_envio_el->appendChild($xml->createElement('Zip', $pedido_presupuesto_direccion->cp));
$xml_envio_el->appendChild($xml->createElement('CountryCode', $pedido_presupuesto_direccion->paisCode3));
$xml_envio_el->appendChild($xml->createElement('Telephone', $pedido_presupuesto_direccion->telefono));
$xml_envios_el->appendChild($xml_envio_el);
}
$xml_product_el->appendChild($xml_envios_el);
$xml_product_el->appendChild($xml->createElement('Comments', $data["pedido_cliente_presupuesto"]->comentarios_safekat));
$xml_product_el->appendChild($xml->createElement('CommentsClient', $data["pedido_cliente_presupuesto"]->comentarios_cliente));
$xml_products_el->appendChild($xml_product_el);
$xml_order_el->appendChild($xml_products_el);
$xml->appendChild($xml_order_el);
$file_has_suffix = hash('sha512',$offset_pedido_id);
$file_name = PedidoXMLService::generate_xml_file_name($file_has_suffix);
$ftp = new SafekatFtpClient();
$ftp->uploadXML($xml->saveXML(),$file_name);
return $data;
}
protected static function generate_xml_file_name(string $hash) : string
{
return implode("",["SafekatNew_",$hash,".xml"]);
}
protected static function get_binding_code(string $tipo_impresion_nombre,bool $solapas) : ?string
{
$solapa = $solapas ? '1' : '0';
$key = implode("_",[$tipo_impresion_nombre,$solapa]);
$xml_mapping_binding =
[
"libroFresadoTapaBlanda_0" => 'RF',
"libroFresadoTapaBlanda_1" => 'RFS',
"libroCosidoTapaBlanda_0" => 'RCHV',
"libroCosidoTapaBlanda_1" => 'RCHVS',
"libroGrapado_0" => 'CC2',
"libroGrapado_1" => 'CC2S',
"libroCosidoTapaDura_0" => 'TDC',
"libroCosidoTapaDura_1" => 'TDC',
"libroFresadoTapaDura_0" => 'RDF',
"libroFresadoTapaDura_1" => 'RDF',
"libroEspiralTapaBlanda_0" => 'ESP',
"libroEspiralTapaBlanda_1" => 'ESP',
"libroWireoTapaBlanda_0" => 'WIO',
"libroWireoTapaBlanda_1" => 'WIO',
];
return $xml_mapping_binding[$key] ?? null;
}
protected static function get_color_interior($pre_linea): ?string
{
$color_interior = null;
$bn_tipo_array = ['lp_bn', 'lp_bnhq', 'lp_rot_bn'];
$color_tipo_array = ['lp_color', 'lp_color_hq', 'lp_rot_color'];
if (in_array($pre_linea->tipo, $bn_tipo_array)) {
$color_interior = "bn";
};
if (in_array($pre_linea->tipo, $color_tipo_array)) {
$color_interior = "color";
};
return $color_interior;
}
}

View File

@ -386,6 +386,7 @@ class PresupuestoService extends BaseService
$precio_pedido = $precio_libro * ($datosPedido->tirada + $datosPedido->merma);
$mano = PresupuestoService::computeLomoInterior($datosPedido->paginas, $papel_impresion->espesor);
$mano += floatval(model('App\Models\Configuracion\ConfigVariableModel')->getVariable('aumento_fijo_lomo_interior')->value);
// peso
$peso = PresupuestoService::computePeso(
@ -515,6 +516,7 @@ class PresupuestoService extends BaseService
$data['total_corte'] = round(($data['tiempo_corte'] / 60.0) * $maquina->precio_hora_corte, 2);
$data['mano'] = PresupuestoService::computeLomoInterior($datosPedido->paginas, $papel_impresion->espesor);
$data['mano'] += floatval(model('App\Models\Configuracion\ConfigVariableModel')->getVariable('aumento_fijo_lomo_interior')->value);
// ($paginas / 2.0) * (($gramaje / 1000.0) * $papel_compra->mano);
// peso
@ -1901,7 +1903,6 @@ class PresupuestoService extends BaseService
"user_updated_id" => auth()->user()->id,
];
$id_linea = $model_pedido_linea->insert($data_pedido_linea);
//PedidoXMLService::generate_xml($pedido_id);
}
if ($id_linea != 0 && $pedido_id != 0) {

View File

@ -0,0 +1,306 @@
<?php
namespace App\Services;
use App\Models\Presupuestos\PresupuestoFicheroModel;
use App\Libraries\SftpClientWrapper;
use Config\PresupuestoSFTP;
class PresupuestoUploaderService
{
public function __construct(
protected SftpClientWrapper $ftp,
protected PresupuestoFicheroModel $fileModel,
protected PresupuestoSFTP $config
) {}
/**
* Sube todos los archivos asociados a un presupuesto al SFTP.
*/
public function uploadToRemote(int $presupuestoId): array
{
$remoteDir = $this->config->getRemoteDirForPresupuesto($presupuestoId);
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) {
$filename = basename($file->file_path);
$localPath = WRITEPATH . $file->file_path;
$remotePath = $remoteDir . '/' . $filename;
if (!file_exists($localPath)) {
$results[] = [
'file' => $file->nombre,
'remotePath' => $remotePath,
'success' => false,
'error' => 'Archivo local no encontrado'
];
continue;
}
$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
];
}
/**
* Elimina todos los archivos actuales del presupuesto del SFTP.
*/
public function removeFromRemote(int $presupuestoId): array
{
$remoteDir = $this->config->getRemoteDirForPresupuesto($presupuestoId);
$files = $this->fileModel->getFiles($presupuestoId);
$results = [];
foreach ($files as $file) {
$filename = basename($file->file_path);
$remotePath = $remoteDir . '/' . $filename;
if ($this->ftp->exists($remotePath)) {
$deleted = $this->ftp->delete($remotePath);
$results[] = [
'file' => $file->nombre,
'remotePath' => $remotePath,
'success' => $deleted,
'message' => $deleted ? 'Eliminado correctamente' : 'Falló al eliminar'
];
} else {
$results[] = [
'file' => $file->nombre,
'remotePath' => $remotePath,
'success' => false,
'message' => 'Archivo no encontrado en el SFTP'
];
}
}
return $results;
}
/**
* Elimina del SFTP los archivos que ya no existen en la lista permitida.
*/
public function removeMissingFromRemote(int $presupuestoId, array $keepFileNames): void
{
$remoteDir = $this->config->getRemoteDirForPresupuesto($presupuestoId);
$files = $this->fileModel->getFiles($presupuestoId);
foreach ($files as $file) {
if (!in_array($file->nombre, $keepFileNames)) {
$remotePath = $remoteDir . '/' . basename($file->file_path);
if ($this->ftp->exists($remotePath)) {
$this->ftp->delete($remotePath);
}
}
}
}
/**
* Descarga archivos de SFTP y genera un ZIP temporal para el presupuesto dado.
*
* @param int $presupuestoId ID del presupuesto.
* @param string|null $prefijo Prefijo para los nombres de los archivos.
* @return array Estructura: ['success' => bool, 'message' => string, 'zipPath' => string|null]
*/
public function downloadZip(int $presupuestoId, ?string $prefijo = null): array
{
$files = $this->fileModel->getFiles($presupuestoId);
if (empty($files)) {
return [
'success' => false,
'message' => "No hay archivos en la base de datos para el presupuesto ID {$presupuestoId}.",
'zipPath' => null
];
}
$remoteDir = $this->config->getRemoteDirForPresupuesto($presupuestoId);
if (!$this->ftp->exists($remoteDir)) {
return [
'success' => false,
'message' => "El directorio remoto no existe: {$remoteDir}",
'zipPath' => null
];
}
$localTempDir = WRITEPATH . 'zip_presupuestos/' . uniqid("presupuesto_");
if (!is_dir($localTempDir) && !mkdir($localTempDir, 0777, true)) {
return [
'success' => false,
'message' => "No se pudo crear el directorio temporal en: {$localTempDir}",
'zipPath' => null
];
}
$erroresDescarga = [];
foreach ($files as $file) {
$originalName = $file->nombre ?? basename($file->file_path ?? '');
$prefixedName = $prefijo ? $prefijo . '_' . $originalName : $originalName;
$localFile = $localTempDir . '/' . $prefixedName;
$remoteFile = $remoteDir . '/' . basename($file->file_path ?? '');
if (!$this->ftp->get($remoteFile, $localFile)) {
$erroresDescarga[] = "Error al descargar: {$remoteFile}";
}
}
if (count($erroresDescarga) === count($files)) {
return [
'success' => false,
'message' => "Fallo al descargar todos los archivos:\n" . implode("\n", $erroresDescarga),
'zipPath' => null
];
}
$zipPath = $localTempDir . '.zip';
$zip = new \ZipArchive();
if (!$zip->open($zipPath, \ZipArchive::CREATE | \ZipArchive::OVERWRITE)) {
return [
'success' => false,
'message' => "No se pudo crear el archivo ZIP: {$zipPath}",
'zipPath' => null
];
}
foreach (glob($localTempDir . '/*') as $localFile) {
$zip->addFile($localFile, basename($localFile));
}
$zip->close();
foreach (glob($localTempDir . '/*') as $localFile) {
unlink($localFile);
}
rmdir($localTempDir);
if (!file_exists($zipPath)) {
return [
'success' => false,
'message' => "El ZIP no fue generado correctamente.",
'zipPath' => null
];
}
return [
'success' => true,
'message' => "ZIP generado correctamente.",
'zipPath' => $zipPath
];
}
public function importarArchivosDesdeUrlsBubok(int $presupuestoId, array $urls): array
{
$resultados = [];
$errores = [];
foreach ($urls as $tipo => $url) {
if (empty($url)) {
$errores[] = "URL vacía para tipo: {$tipo}";
continue;
}
try {
// Intenta descargar el contenido del archivo desde la URL
$contenido = @file_get_contents($url);
// Si no se puede descargar, se genera un archivo de error local (no se guarda en BBDD)
if ($contenido === false || strlen($contenido) === 0) {
$mensajeError = "ERROR: No se pudo descargar el archivo remoto para $tipo desde la URL: $url";
$nombreError = 'ERROR_' . strtoupper($tipo) . '.txt';
// Ruta local en la estructura estándar (no BBDD)
$rutaError = $this->fileModel->getAbsolutePath($presupuestoId, $nombreError);
// Crear el directorio si no existe
$directorio = dirname($rutaError);
if (!is_dir($directorio)) {
mkdir($directorio, 0755, true);
}
// Guardar el archivo con el mensaje de error
file_put_contents($rutaError, $mensajeError);
// Registrar el error en el array de errores
$errores[] = $mensajeError;
continue;
}
// Nombre original y extensión del archivo descargado
$nombreOriginal = basename(parse_url($url, PHP_URL_PATH));
$extension = pathinfo($nombreOriginal, PATHINFO_EXTENSION);
// Registrar el archivo en la base de datos y obtener el nombre limpio
$nombreLimpio = $this->fileModel->saveFileInBBDD(
$presupuestoId,
$nombreOriginal,
$extension,
auth()->id()
);
if (!$nombreLimpio) {
$errores[] = "No se pudo registrar '$nombreOriginal' en la base de datos.";
continue;
}
// Obtener la ruta completa donde se guardará el archivo localmente
$rutaAbsoluta = $this->fileModel->getAbsolutePath($presupuestoId, $nombreLimpio);
// Crear el directorio si no existe
$directorio = dirname($rutaAbsoluta);
if (!is_dir($directorio)) {
mkdir($directorio, 0755, true);
}
// Guardar el archivo en el sistema de archivos local
file_put_contents($rutaAbsoluta, $contenido);
// Añadir el archivo a la lista de resultados
$resultados[] = [
'nombre' => $nombreLimpio,
'tipo' => $tipo,
'ruta_local' => $rutaAbsoluta
];
} catch (\Throwable $e) {
$errores[] = "Error inesperado procesando '$tipo': " . $e->getMessage();
}
}
// Subida de todos los archivos válidos al servidor remoto SFTP
try {
$this->uploadToRemote($presupuestoId);
} catch (\Throwable $e) {
$errores[] = "Error al subir archivos al SFTP: " . $e->getMessage();
}
// Devolver el resumen del proceso
return [
'success' => empty($errores),
'archivos_subidos' => $resultados,
'errores' => $errores
];
}
}

View File

@ -12,7 +12,7 @@
data-bs-parent="#accordionPresupuestoFiles">
<div class="accordion-body">
<div class="col-12">
<div class="dropzone needsclick" id="<?= $id ?>" data-id="<?= $modelId ?>">
<div class="dropzone needsclick" id="<?= $id ?>" data-id="<?= $modelId ?>" data-ot-id="<?= $otId ?? '' ?>">
<div class="dz-message needsclick">
Arrastre aquí los ficheros o haga click
@ -24,7 +24,7 @@
</div>
<div class="col-md-12 gap-2">
<button id="<?= $id ?>_btnUploadFiles" class="btn mt-3 btn-sm btn-primary waves-effect waves-light ml-2 ">
<span class="align-middle d-sm-inline-block d-none me-sm-1"><?= lang('App.global_upload_files') ?></span>
<span class="align-middle d-sm-inline-block d-none me-sm-1"><?= lang('App.global_select_files') ?></span>
<i class="ti ti-upload ti-xs"></i>
</button>
<button id="<?= $id ?>_btnSubmitFiles" class="btn mt-3 btn-success btn-sm waves-effect waves-light ml-2">

View File

@ -8,6 +8,23 @@
value="<?= old('nombre', $papelGenerico->nombre) ?>">
</div><!--//.mb-3 -->
<div class="mb-3">
<label for="tipo_papel_generico_id" class="form-label">
<?= lang('PapelGenerico.tipo_papel_generico_id') ?>
</label>
<select id="tipo_papel_generico_id" name="tipo_papel_generico_id" class="form-control select2" data-placeholder="">
<option value="" <?= is_null($papelGenerico->tipo_papel_generico_id) ? 'selected' : '' ?>></option>
<?php if (isset($tipoPapelGenericoList) && is_array($tipoPapelGenericoList) && !empty($tipoPapelGenericoList)):
foreach ($tipoPapelGenericoList as $k => $v): ?>
<option value="<?= $k ?>" <?= $k == $papelGenerico->tipo_papel_generico_id ? 'selected' : '' ?>>
<?= esc($v) ?>
</option>
<?php endforeach;
endif; ?>
</select>
</div><!--//.mb-3 -->
<div class="mb-3">
<label for="code" class="form-label">
<?= lang('PapelGenerico.code') ?>
@ -28,8 +45,8 @@
<label for="activo_papel_generico" class="form-check-label">
<?= lang('PapelGenerico.activo') ?>
</label>
<input type="checkbox" id="activo_papel_generico" name="activo" value="1"
class="form-check-input" <?= $papelGenerico->activo == true ? 'checked' : ''; ?>>
<input type="checkbox" id="activo_papel_generico" name="activo" value="1" class="form-check-input"
<?= $papelGenerico->activo == true ? 'checked' : ''; ?>>
</div><!--//.form-check -->
</div><!--//.mb-3 -->
<div class="mb-3">

View File

@ -15,7 +15,7 @@
<?= view('themes/_commonPartialsBs/_alertBoxes'); ?>
<table id="tableConfigVariables" class="table table-striped table-hover" style="width: 100%;">
<table id="tableConfigVariables" class="table table-striped table-hover table-responsive" style="width: 100%; word-break: break-word;">
<thead>
<tr>
<th><?= lang('ConfigVariables.datatable.columns.name') ?></th>
@ -55,11 +55,13 @@
<div class="row g-4">
<div class="col-12 mb-0">
<label for="value" class="form-label"><?= lang('ConfigVariables.form.value') ?></label>
<input type="number" min=0 id="value" class="form-control">
<div id="value-wrapper">
</div>
</div>
<div class="col-12 mb-0">
<label for="description" class="form-label"><?= lang('ConfigVariables.form.description') ?></label>
<textarea type="text" rows="4" cols="10" id="description" class="form-control"></textarea>
<textarea type="text" rows="4" cols="10" id="description" class="form-control"></textarea>
</div>
</div>
</div>
@ -75,4 +77,13 @@
<?= $this->endSection() ?>
<?= $this->section("additionalExternalJs") ?>
<script type="module" src="<?= versioned_asset('assets/js/safekat/pages/configuracion/variables.js') ?>"></script>
<script>
// Pasamos las opciones al frontend desde PHP
window.CABEZADAS_OPCIONES = <?= json_encode([
'WHI' => lang('Presupuestos.blanca'),
'GRE' => lang('Presupuestos.verde'),
'BLUE' => lang('Presupuestos.azul'),
'REDYEL' => lang('Presupuestos.rojaAmarilla'),
]) ?>;
</script>
<?= $this->endSection() ?>

View File

@ -1,82 +1,94 @@
<?= $this->include('themes/_commonPartialsBs/datatables') ?>
<?= $this->extend('themes/vuexy/main/defaultlayout') ?>
<?= $this->section('content'); ?>
<div class="row">
<div class="col-md-12">
<div class="card card-info">
<div class="card-header">
<h3 class="card-title"><?= lang('RolesPermisos.pageTitle') ?></h3>
</div><!--//.card-header -->
<div class="card-body">
<div class="container-xxl flex-grow-1 container-p-y">
<!-- Role cards -->
<div class="row g-4">
<div class="col-xl-4 col-lg-6 col-md-6">
<div class="card h-100">
<div class="row h-100">
<div class="col-sm-5">
<div class="d-flex align-items-end h-100 justify-content-center mt-sm-0 mt-3">
<img
src="<?= site_url('themes/vuexy/img/illustrations/add-new-roles.png') ?>"
class="img-fluid mt-sm-4 mt-md-0"
alt="add-new-roles"
width="83"/>
</div>
<div class="row">
<div class="col-md-12">
<div class="card card-info">
<div class="card-header">
<h3 class="card-title"><?= lang('RolesPermisos.pageTitle') ?></h3>
</div><!--//.card-header -->
<div class="card-body">
<div class="container-xxl flex-grow-1 container-p-y">
<!-- Role cards -->
<div class="row g-4">
<div class="col-xl-4 col-lg-6 col-md-6">
<div class="card h-100">
<div class="row h-100">
<div class="col-sm-5">
<div class="d-flex align-items-end h-100 justify-content-center mt-sm-0 mt-3">
<img src="<?= site_url('themes/vuexy/img/illustrations/add-new-roles.png') ?>"
class="img-fluid mt-sm-4 mt-md-0" alt="add-new-roles" width="83" />
</div>
<div class="col-sm-7">
<div class="card-body text-sm-end text-center ps-sm-0">
<button
onclick="window.location='<?= route_to('newGroup') ?>'"
class="btn btn-primary mb-2 text-nowrap add-new-role"
>
<?= lang('Basic.global.addNew') ?>
</button>
<p class="mb-0 mt-1"><?= lang("RolesPermisos.addRol") ?></p>
</div>
</div>
<div class="col-sm-7">
<div class="card-body text-sm-end text-center ps-sm-0">
<button onclick="window.location='<?= route_to('newGroup') ?>'"
class="btn btn-primary mb-2 text-nowrap add-new-role">
<?= lang('Basic.global.addNew') ?>
</button>
<p class="mb-0 mt-1"><?= lang("RolesPermisos.addRol") ?></p>
</div>
</div>
</div>
</div>
</div>
<?php foreach ($userGroupList as $item) : ?>
<div class="col-xl-4 col-lg-6 col-md-6">
<div class="card">
<div class="card-body">
<div class="d-flex justify-content-between">
<h6 class="fw-normal mb-2"><?= $model->getUsersWithRol($item->keyword); ?><?= lang("RolesPermisos.totalUsers") ?></h6>
<?php foreach ($userGroupList as $item): ?>
<?php $item->users = $model->getUsersByRol($item->keyword); ?>
<div class="col-xl-4 col-lg-6 col-md-6">
<div class="card">
<div class="card-body">
<div class="d-flex justify-content-between">
<h6 class="fw-normal mb-2">
<?= $model->getUsersWithRol($item->keyword); ?>
<?= lang("RolesPermisos.totalUsers") ?>
</h6>
<ul class="list-unstyled d-flex align-items-center avatar-group mb-0">
<?php foreach ($item->users as $user): ?>
<li data-bs-toggle="tooltip" data-popup="tooltip-custom" data-bs-placement="top"
title="<?= esc($user->first_name . ' ' . $user->last_name) ?>"
class="avatar avatar-sm pull-up">
<img class="rounded-circle" src="<?= gravatar_url($user->email, 30) ?>"
alt="<?= esc($user->email) ?>" />
</li>
<?php endforeach; ?>
</ul>
</div>
<div class="d-flex justify-content-between align-items-end mt-1">
<div class="role-heading">
<h4 class="mb-1"><?= esc($item->title) ?></h4>
<a href="<?= route_to('editGroup', $item->id) ?>">
<span><?= lang('Basic.global.edit') ?></span>
</a>
</div>
<div class="d-flex justify-content-between align-items-end mt-1">
<div class="role-heading">
<h4 class="mb-1"><?= esc($item->title) ?></h4>
<a href="<?= route_to('editGroup', $item->id) ?>">
<span><?= lang('Basic.global.edit') ?></span>
</a>
</div>
<?=
anchor('#confirm2delete', "<i class='ti ti-trash ti-md'></i>",
<?=
anchor(
'#confirm2delete',
"<i class='ti ti-trash ti-md'></i>",
[
'class' => 'text-muted',
'data-href' => route_to('deleteGroup', $item->id),
'data-bs-toggle' => 'modal',
'data-bs-target' => '#confirm2delete'
]);
?>
</div>
]
);
?>
</div>
</div>
</div>
<?php endforeach; ?>
</div>
<!--/ Role cards -->
</div>
<?php endforeach; ?>
</div>
<?= view('themes/_commonPartialsBs/_alertBoxes'); ?>
<!--/ Role cards -->
</div>
<?= view('themes/_commonPartialsBs/_alertBoxes'); ?>
</div><!--//.card-body -->
<div class="card-footer">
</div><!--//.card-body -->
<div class="card-footer">
</div><!--//.card-footer -->
</div><!--//.card -->
</div><!--//.col -->
</div><!--//.row -->
</div><!--//.card-footer -->
</div><!--//.card -->
</div><!--//.col -->
</div><!--//.row -->
<?= $this->endSection() ?>

View File

@ -1,69 +1,207 @@
<div class="accordion accordion-bordered mt-3" id="accordionEnvios">
<div class="card accordion-item active">
<h2 class="accordion-header" id="headingOne">
<button type="button" class="accordion-button" data-bs-toggle="collapse" data-bs-target="#accordionEnviosTip" aria-expanded="false" aria-controls="accordionEnviosTip">
<button type="button" class="accordion-button" data-bs-toggle="collapse"
data-bs-target="#accordionEnviosTip" aria-expanded="false" aria-controls="accordionEnviosTip">
<h4><?= lang("Presupuestos.envios") ?></h4>
</button>
</h2>
<div id="accordionEnviosTip" class="accordion-collapse collapse show" data-bs-parent="#accordionEnvios">
<div id="accordionEnviosTip" class="accordion-collapse collapse show" data-bs-parent="#accordionEnvios">
<div class="accordion-body">
<div id='alert-envios'></div>
<?= view("themes/vuexy/form/presupuestos/admin/_presupuestoDireccionesForm") ?>
<div class='row'>
<div class='col-md-12 col-lg-4 px-4 py-2'>
<label for='envio_base' class='form-label'>
Envio base
</label>
<input readonly type='text' class='form-control' id='envio_base' name='envio_base' value='<?= $presupuestoEntity->envio_base ?>' />
<div> <!-- Direcciones envio -->
<div id='alert-envios'></div>
<?= view("themes/vuexy/form/presupuestos/admin/_presupuestoDireccionesForm") ?>
<div class='row'>
<div class='col-md-12 col-lg-4 px-4 py-2'>
<label for='envio_base' class='form-label'>
Envio base
</label>
<input readonly type='text' class='form-control' id='envio_base' name='envio_base'
value='<?= $presupuestoEntity->envio_base ?>' />
</div>
</div>
<div id='rowTable' class='row'>
<table id="tableOfDireccionesEnvio"
class="table comparator-table dt-responsive dataTable px-2 update-resumen-presupuesto"
style="width: 95%;">
<thead>
<tr>
<th class="lp-header">TARIFA ID</th>
<th class="lp-header"><?= lang('PresupuestosDirecciones.cantidad') ?></th>
<th class="lp-header"><?= lang('PresupuestosDirecciones.peso') ?></th>
<th class="lp-header"><?= lang('PresupuestosDirecciones.att') ?></th>
<th class="lp-header"><?= lang('PresupuestosDirecciones.email') ?></th>
<th class="lp-header"><?= lang('PresupuestosDirecciones.direccion') ?></th>
<th class="lp-header"><?= lang('PresupuestosDirecciones.cp') ?></th>
<th class="lp-header"><?= lang('PresupuestosDirecciones.municipio') ?></th>
<th class="lp-header"><?= lang('PresupuestosDirecciones.pais') ?></th>
<th class="lp-header">pais_id</th>
<th class="lp-header"><?= lang('PresupuestosDirecciones.telefono') ?></th>
<th class="lp-header"><?= lang('PresupuestosDirecciones.proveedor') ?></th>
<th class="lp-header">Proveedor_id</th>
<th class="lp-header"><?= lang('PresupuestosDirecciones.costePrecio') ?></th>
<th class="lp-header"><?= lang('Tarifaacabado.margen') ?></th>
<th class="lp-header">Pallets?</th>
<th style="min-width:120px !important;" class="lp-header">
<?= lang('Basic.global.Action') ?>
</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
<div id='rowTable' class='row'>
<table id="tableOfDireccionesEnvio" class="table comparator-table dt-responsive dataTable px-2 update-resumen-presupuesto" style="width: 95%;">
<thead>
<tr>
<th class="lp-header">TARIFA ID</th>
<th class="lp-header"><?= lang('PresupuestosDirecciones.cantidad') ?></th>
<th class="lp-header"><?= lang('PresupuestosDirecciones.peso') ?></th>
<th class="lp-header"><?= lang('PresupuestosDirecciones.att') ?></th>
<th class="lp-header"><?= lang('PresupuestosDirecciones.email') ?></th>
<th class="lp-header"><?= lang('PresupuestosDirecciones.direccion') ?></th>
<th class="lp-header"><?= lang('PresupuestosDirecciones.cp') ?></th>
<th class="lp-header"><?= lang('PresupuestosDirecciones.municipio') ?></th>
<th class="lp-header"><?= lang('PresupuestosDirecciones.pais') ?></th>
<th class="lp-header">pais_id</th>
<th class="lp-header"><?= lang('PresupuestosDirecciones.telefono') ?></th>
<th class="lp-header"><?= lang('PresupuestosDirecciones.proveedor') ?></th>
<th class="lp-header">Proveedor_id</th>
<th class="lp-header"><?= lang('PresupuestosDirecciones.costePrecio') ?></th>
<th class="lp-header"><?= lang('Tarifaacabado.margen') ?></th>
<th class="lp-header">Pallets?</th>
<th class="lp-header">Ferro o Prototipo?</th>
<th style="min-width:120px !important;" class="lp-header"><?= lang('Basic.global.Action') ?></th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
<div class="row">
<div class="col-md-12 col-lg-4 px-4 py-2">
<input class="form-check-input" type="checkbox" id="recoger_en_taller" name="recoger_en_taller" value="1" <?= $presupuestoEntity->recoger_en_taller == true ? 'checked' : ''; ?> >
<label class="form-check-label" for="recoger_en_taller"><?= lang('Presupuestos.recogerEnTaller') ?></label>
<div class="row">
<div class="col-md-12 col-lg-4 px-4 py-2">
<input class="form-check-input" type="checkbox" id="recoger_en_taller"
name="recoger_en_taller" value="1" <?= $presupuestoEntity->recoger_en_taller == true ? 'checked' : ''; ?>>
<label class="form-check-label"
for="recoger_en_taller"><?= lang('Presupuestos.recogerEnTaller') ?></label>
</div>
</div>
</div>
<div id="rowInsertar" class="row">
<div class="col-md-12 col-lg-4 px-4 py-2">
<button id="insertar_direccion" type="button" class="btn btn-secondary waves-effect waves-light float-start"><?= lang("Presupuestos.insertar")?></button>
<div id="rowInsertar" class="row">
<div class="col-md-12 col-lg-4 px-4 py-2">
<button id="insertar_direccion" type="button"
class="btn btn-secondary waves-effect waves-light float-start"><?= lang("Presupuestos.insertar") ?></button>
</div>
</div>
</div>
</div> <!-- //.Direcciones envio -->
<div id="div-envio-fp-1" class="mt-3 datos-envio-fp-1"> <!-- Direcciones envio fp 1 -->
<div class="divider divider-dark text-start mb-1">
<div class="divider-text">
<h6>
Dirección de envío ferro/prototipo
</h6>
</div>
</div>
<div id='alert-envio-fp1'></div>
<div id='rowTable' class='row'>
<table id="tableOfDireccionesEnvioFP1"
class="table comparator-table dt-responsive dataTable px-2 update-resumen-presupuesto"
style="width: 95%;">
<thead>
<tr>
<th class="lp-header">TARIFA ID</th>
<th class="lp-header"><?= lang('PresupuestosDirecciones.cantidad') ?></th>
<th class="lp-header"><?= lang('PresupuestosDirecciones.peso') ?></th>
<th class="lp-header"><?= lang('PresupuestosDirecciones.att') ?></th>
<th class="lp-header"><?= lang('PresupuestosDirecciones.email') ?></th>
<th class="lp-header"><?= lang('PresupuestosDirecciones.direccion') ?></th>
<th class="lp-header"><?= lang('PresupuestosDirecciones.cp') ?></th>
<th class="lp-header"><?= lang('PresupuestosDirecciones.municipio') ?></th>
<th class="lp-header"><?= lang('PresupuestosDirecciones.pais') ?></th>
<th class="lp-header">pais_id</th>
<th class="lp-header"><?= lang('PresupuestosDirecciones.telefono') ?></th>
<th class="lp-header"><?= lang('PresupuestosDirecciones.proveedor') ?></th>
<th class="lp-header">Proveedor_id</th>
<th class="lp-header"><?= lang('PresupuestosDirecciones.costePrecio') ?></th>
<th class="lp-header"><?= lang('Tarifaacabado.margen') ?></th>
<th class="lp-header">Pallets?</th>
<th style="min-width:120px !important;" class="lp-header">
<?= lang('Basic.global.Action') ?>
</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
<div class="row">
<div class="col-md-12 col-lg-4 px-4 py-2">
<input class="form-check-input check-direccion-fp" type="checkbox" id="sameAddPrincipalFP1"
name="sameAddPrincipalFP1" value="1" >
<label class="form-check-label"
for="sameAddPrincipalFP1"><?= lang('PresupuestosDirecciones.sameAddPrincipal') ?></label>
</div>
</div>
<div id="rowInsertarEnvioFP1" class="row datos-envio-fp-1">
<div class="col-md-12 col-lg-4 px-4 py-2">
<button id="insertar_direccion_fp1" type="button"
class="btn btn-secondary waves-effect waves-light float-start"><?= lang("Presupuestos.insertar") ?></button>
</div>
</div>
</div> <!-- //.Direcciones envio fp1-->
<div id="div-envio-fp-2" class="mt-3 datos-envio-fp-2"> <!-- Direcciones envio fp 2 -->
<div class="divider divider-dark text-start mb-1">
<div class="divider-text">
<h6>
Dirección de envío ferro/prototipo 2
</h6>
</div>
</div>
<div id='alert-envio-fp2'></div>
<div id='rowTable' class='row'>
<table id="tableOfDireccionesEnvioFP2"
class="table comparator-table dt-responsive dataTable px-2 update-resumen-presupuesto"
style="width: 95%;">
<thead>
<tr>
<th class="lp-header">TARIFA ID</th>
<th class="lp-header"><?= lang('PresupuestosDirecciones.cantidad') ?></th>
<th class="lp-header"><?= lang('PresupuestosDirecciones.peso') ?></th>
<th class="lp-header"><?= lang('PresupuestosDirecciones.att') ?></th>
<th class="lp-header"><?= lang('PresupuestosDirecciones.email') ?></th>
<th class="lp-header"><?= lang('PresupuestosDirecciones.direccion') ?></th>
<th class="lp-header"><?= lang('PresupuestosDirecciones.cp') ?></th>
<th class="lp-header"><?= lang('PresupuestosDirecciones.municipio') ?></th>
<th class="lp-header"><?= lang('PresupuestosDirecciones.pais') ?></th>
<th class="lp-header">pais_id</th>
<th class="lp-header"><?= lang('PresupuestosDirecciones.telefono') ?></th>
<th class="lp-header"><?= lang('PresupuestosDirecciones.proveedor') ?></th>
<th class="lp-header">Proveedor_id</th>
<th class="lp-header"><?= lang('PresupuestosDirecciones.costePrecio') ?></th>
<th class="lp-header"><?= lang('Tarifaacabado.margen') ?></th>
<th class="lp-header">Pallets?</th>
<th style="min-width:120px !important;" class="lp-header">
<?= lang('Basic.global.Action') ?>
</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
<div class="row d-flex justify-content-start">
<div class="col-auto px-2 py-2">
<input class="form-check-input check-direccion-fp-2" type="checkbox" id="sameAddPrincipalFP2"
name="sameAddPrincipalFP2" value="1" >
<label class="form-check-label"
for="sameAddPrincipalFP2"><?= lang('PresupuestosDirecciones.sameAddPrincipal') ?></label>
</div>
<div class="col-auto px-2 py-2">
<input class="form-check-input check-direccion-fp-2" type="checkbox" id="sameAddFP1" name="sameAddFP1" value="1"
>
<label class="form-check-label"
for="sameAddFP1"><?= lang('PresupuestosDirecciones.sameAddFP1') ?></label>
</div>
</div>
<div id="rowInsertarEnvioFP2" class="row datos-envio-fp-2">
<div class="col-md-12 col-lg-4 px-4 py-2">
<button id="insertar_direccion_fp2" type="button"
class="btn btn-secondary waves-effect waves-light float-start"><?= lang("Presupuestos.insertar") ?></button>
</div>
</div>
</div> <!-- //.Direcciones envio fp2-->
</div> <!-- //.accordion-body -->
</div> <!-- //.accordion-collapse -->
</div> <!-- //.accordion-item -->
</div> <!-- //.accordion -->
</div> <!-- //.accordion -->

View File

@ -303,11 +303,20 @@
</label>
</div><!--//.form-check -->
</div><!--//.mb-3 -->
<div class="mb-3">
</div><!--//.mb-3 -->
</div><!--//.col -->
<div class="col-md-12 col-lg-3 px-4">
<div class="mb-3">
<div class="form-check">
<label for="prototipo_2" class="form-check-label">
<input type="checkbox" id="prototipo_2" name="prototipo_2" value="1"
class="form-check-input" service="extra"
service-id=<?= $serviciosAutomaticos['prototipo_2'] ?>>
<?= lang('Presupuestos.prototipo_2') ?>
</label>
</div><!--//.form-check -->
</div><!--//.mb-3 -->
</div><!--//.col -->
</div>
@ -326,6 +335,18 @@
</div><!--//.mb-3 -->
</div><!--//.col -->
<div class="col-md-12 col-lg-3 px-4">
<div class="mb-3">
<div class="form-check">
<label for="ferro_2" class="form-check-label">
<input type="checkbox" id="ferro_2" name="ferro_2" value="1" class="form-check-input"
service="extra" service-id=<?= $serviciosAutomaticos['ferro_2'] ?>>
<?= lang('Presupuestos.ferro_2') ?>
</label>
</div><!--//.form-check -->
</div><!--//.mb-3 -->
</div><!--//.col -->
<div class="col-md-12 col-lg-3 px-4">
<div class="mb-3">

View File

@ -222,46 +222,39 @@
</div>
<?php if ($tipo_impresion_id == 1 || $tipo_impresion_id == 3): ?>
<div class="col-md-12 col-lg-2 px-4">
</div>
<div class="col-md-12 col-lg-2 px-4">
</div>
<div class="col-md-12 col-lg-2 px-4">
<label id="label_compLomoRedondo" for="compLomoRedondo" class="form-label">
<?= lang('Presupuestos.lomoRedondo') ?>*
</label>
<select id="compLomoRedondo" name="lomo_redondo" service-id="<?= $serviciosAutomaticos['lomo_redondo'] ?>"
class="form-control select2bs2 comp_cubierta_items" style="width: 100%;">
<option value="0">
<p>
<?= lang('Presupuestos.no') ?>
</p>
</option>
<option value="1">
<p>
<?= lang('Presupuestos.si') ?>
</p>
</option>
</select>
</div>
<div class="col-md-12 col-lg-2 px-4">
<label for="cabezada" class="form-label">
<?= lang('Presupuestos.cabezada') ?>
</label>
<select class="form-select select2bs2" id="cabezada" name="cabezada">
<option value="WHI">
<?= lang('Presupuestos.blanca') ?>
</option>
<option value="GRE">
<?= lang('Presupuestos.verde') ?>
</option>
<option value="BLUE">
<?= lang('Presupuestos.azul') ?>
</option>
<option value="REDYEL">
<?= lang('Presupuestos.rojaAmarilla') ?>
</option>
</select>
</div>
<div class="col-md-12 col-lg-2 px-4">
<label id="label_compLomoRedondo" for="compLomoRedondo" class="form-label">
<?= lang('Presupuestos.lomoRedondo') ?>*
</label>
<select id="compLomoRedondo" name="lomo_redondo" service-id="<?= $serviciosAutomaticos['lomo_redondo'] ?>"
class="form-control select2bs2 comp_cubierta_items" style="width: 100%;">
<option value="0">
<p>
<?= lang('Presupuestos.no') ?>
</p>
</option>
<option value="1">
<p>
<?= lang('Presupuestos.si') ?>
</p>
</option>
</select>
</div>
<div class="col-md-12 col-lg-2 px-4">
<label for="cabezada" class="form-label">
<?= lang('Presupuestos.cabezada') ?>
</label>
<select class="form-select" name="cabezada" id="cabezada">
<?php foreach ($cabezadas as $key => $langKey): ?>
<option value="<?= esc($key) ?>">
<?= lang($langKey) ?>
</option>
<?php endforeach; ?>
</select>
</div>
<?php endif; ?>
<div>
<hr class="my-1">
@ -269,83 +262,83 @@
</div>
<?php if ($tipo_impresion_id != 5 && $tipo_impresion_id != 6 && $tipo_impresion_id != 7 && $tipo_impresion_id != 8 && $tipo_impresion_id != 21): ?>
<div class="row">
<div class="col-md-12 col-lg-2 px-4">
<p>
<?= lang('PapelImpresion.sobrecubierta') ?>
</p>
<div class="row">
<div class="col-md-12 col-lg-2 px-4">
<p>
<?= lang('PapelImpresion.sobrecubierta') ?>
</p>
</div>
<div class="col-md-12 col-lg-2 px-4">
<select id="compSobrecubierta" name="comp_sobrecubierta"
class="form-control select2bs2 comp_sobrecubierta_items" style="width: 100%;">
<option value="0">
<?= lang('Presupuestos.no') ?>
</option>
<option value="1">
<?= lang('Presupuestos.si') ?>
</option>
</select>
</div>
<div class="col-md-12 col-lg-6 px-4">
<select disabled id="compPapelSobrecubierta" name="comp_papel_sobrecubierta"
class="form-control select2bs2 comp_sobrecubierta_items" style="width: 100%;">
</select>
</div>
<div class="col-md-12 col-lg-2 px-4">
<select disabled id="compGramajeSobrecubierta" name="comp_gramaje_sobrecubierta"
class="form-control select2bs2 comp_sobrecubierta_items" style="width: 100%;">
</select>
</div>
<div>
<hr class="my-1">
</div>
</div>
<div class="col-md-12 col-lg-2 px-4">
<select id="compSobrecubierta" name="comp_sobrecubierta"
class="form-control select2bs2 comp_sobrecubierta_items" style="width: 100%;">
<option value="0">
<?= lang('Presupuestos.no') ?>
</option>
<option value="1">
<?= lang('Presupuestos.si') ?>
</option>
</select>
</div>
<div class="col-md-12 col-lg-6 px-4">
<select disabled id="compPapelSobrecubierta" name="comp_papel_sobrecubierta"
class="form-control select2bs2 comp_sobrecubierta_items" style="width: 100%;">
</select>
</div>
<div class="col-md-12 col-lg-2 px-4">
<select disabled id="compGramajeSobrecubierta" name="comp_gramaje_sobrecubierta"
class="form-control select2bs2 comp_sobrecubierta_items" style="width: 100%;">
</select>
</div>
<div>
<hr class="my-1">
</div>
</div>
<?php endif; ?>
<?php if ($tipo_impresion_id == 1 || $tipo_impresion_id == 3 || $tipo_impresion_id == 5 || $tipo_impresion_id == 7): ?>
<div class="row">
<div class="col-md-12 col-lg-2 px-4">
<p>
<?= lang('PapelImpresion.guardas') ?>
</p>
</div>
<div class="col-md-12 col-lg-2 px-4">
<select id="compCarasGuardas" name="comp_paginas_guardas"
class="form-control select2bs2 comp_guardas_items" style="width: 100%;">
<option value="0">
<p>
<?= lang('Presupuestos.sinImpresion') ?>
</p>
</option>
<option value="4">
<p>
<?= lang('Presupuestos.unaCara') ?>
</p>
</option>
<option value="8">
<?php if ($tipo_impresion_id != 5 && $tipo_impresion_id != 6 && $tipo_impresion_id != 7 && $tipo_impresion_id != 8): ?>
<p>
<?= lang('Presupuestos.dosCaras') ?>
</p>
<?php endif ?>
</option>
</select>
</div>
<div class="col-md-12 col-lg-6 px-4">
<select id="compPapelGuardas" name="comp_papel_guardas"
class="form-control select2bs2 comp_guardas_items" style="width: 100%;">
</select>
</div>
<div class="col-md-12 col-lg-2 px-4">
<select id="compGramajeGuardas" name="comp_gramaje_guardas"
class="form-control select2bs2 comp_guardas_items" style="width: 100%;">
</select>
</div>
<div class="row">
<div class="col-md-12 col-lg-2 px-4">
<p>
<?= lang('PapelImpresion.guardas') ?>
</p>
</div>
<div class="col-md-12 col-lg-2 px-4">
<select id="compCarasGuardas" name="comp_paginas_guardas"
class="form-control select2bs2 comp_guardas_items" style="width: 100%;">
<option value="0">
<p>
<?= lang('Presupuestos.sinImpresion') ?>
</p>
</option>
<option value="4">
<p>
<?= lang('Presupuestos.unaCara') ?>
</p>
</option>
<option value="8">
<?php if ($tipo_impresion_id != 5 && $tipo_impresion_id != 6 && $tipo_impresion_id != 7 && $tipo_impresion_id != 8): ?>
<p>
<?= lang('Presupuestos.dosCaras') ?>
</p>
<?php endif ?>
</option>
</select>
</div>
<div class="col-md-12 col-lg-6 px-4">
<select id="compPapelGuardas" name="comp_papel_guardas"
class="form-control select2bs2 comp_guardas_items" style="width: 100%;">
</select>
</div>
<div class="col-md-12 col-lg-2 px-4">
<select id="compGramajeGuardas" name="comp_gramaje_guardas"
class="form-control select2bs2 comp_guardas_items" style="width: 100%;">
</select>
</div>
<div>
<hr class="my-1">
<div>
<hr class="my-1">
</div>
</div>
</div>
<?php endif; ?>
<div class="row">
@ -733,102 +726,102 @@
<!----------------------------------------------------------------------------->
<?php if ($tipo_impresion_id == 1 || $tipo_impresion_id == 3 || $tipo_impresion_id == 5 || $tipo_impresion_id == 7): ?>
<div class="accordion mt-3" id="accordionCompGuardas">
<div class="card accordion-item active">
<h2 class="accordion-header" id="headingOne">
<button id="accordion-button-int-guardas" type="button" class="accordion-button"
data-bs-toggle="collapse" data-bs-target="#accordionCompGuardasTip"
aria-expanded="false" aria-controls="accordionCompGuardasTip">
<h6 id="title_guardas">
<?= lang("Presupuestos.Guardas") ?>
</h6>
</button>
</h2>
<div class="accordion mt-3" id="accordionCompGuardas">
<div class="card accordion-item active">
<h2 class="accordion-header" id="headingOne">
<button id="accordion-button-int-guardas" type="button" class="accordion-button"
data-bs-toggle="collapse" data-bs-target="#accordionCompGuardasTip"
aria-expanded="false" aria-controls="accordionCompGuardasTip">
<h6 id="title_guardas">
<?= lang("Presupuestos.Guardas") ?>
</h6>
</button>
</h2>
<div id="accordionCompGuardasTip" class="accordion-collapse collapse"
data-bs-parent="#accordionCompGuardasTip">
<div class="accordion-body">
<div id="accordionCompGuardasTip" class="accordion-collapse collapse"
data-bs-parent="#accordionCompGuardasTip">
<div class="accordion-body">
<table id="tableCompGuardas" class="comparator-table table dt-responsive dataTable"
style="width: 100%;">
<thead>
<tr>
<th style="padding-right: 0.75em;">
<?= lang('Presupuestos.tipo') ?>
</th>
<th style="padding-right: 0.75em;">
<?= lang('Presupuestos.paginas') ?>
</th>
<th style="padding-right: 0.75em;">
<?= lang('Presupuestos.papel') ?>
</th>
<th style="padding-right: 0.75em;">
<?= lang('Presupuestos.gramaje') ?>
</th>
<th style="padding-right: 0.75em;">
<?= lang('Presupuestos.marca') ?>
</th>
<th style="padding-right: 0.75em;">
<?= lang('Presupuestos.maquina') ?>
</th>
<th style="padding-right: 0.75em;">
<?= lang('Presupuestos.numeroPliegos') ?>
</th>
<th style="padding-right: 0.75em; max-width:80px">
<?= lang('Presupuestos.pliegosPedido') ?>
</th>
<th style="padding-right: 0.75em; max-width:80px">
<?= lang('Presupuestos.precioPliego') ?>
</th>
<th style="padding-right: 0.75em;">
<?= lang('Presupuestos.libro') ?>
</th>
<th style="padding-right: 0.75em; max-width:80px">
<?= lang('Presupuestos.totalPapelPedido') ?>
</th>
<th style="padding-right: 0.75em;">
<?= lang('Presupuestos.lomo') ?>
</th>
<th style="padding-right: 0.75em;">
<?= lang('Presupuestos.peso') ?>
</th>
<th style="padding-right: 0.75em; max-width:80px">
<?= lang('Presupuestos.horas') ?>
</th>
<th style="padding-right: 0.75em; max-width:80px">
<?= lang('Presupuestos.precioImpresion') ?>
</th>
<th style="padding-right: 0.75em;">
<?= lang('Presupuestos.total') ?>
</th>
</tr>
</thead>
<tbody>
</tbody>
<tfoot>
<tr>
<td class="dt-result dt-result-text" colspan="14">
<?= lang('Presupuestos.total') ?>
<?= lang("Presupuestos.Guardas") ?>:
</td>
<td id="total_comp_guardas" class="dt-result dt-result-value" colspan="2">
0.00 </td>
</tr>
</tfoot>
</table>
<table id="tableCompGuardas" class="comparator-table table dt-responsive dataTable"
style="width: 100%;">
<thead>
<tr>
<th style="padding-right: 0.75em;">
<?= lang('Presupuestos.tipo') ?>
</th>
<th style="padding-right: 0.75em;">
<?= lang('Presupuestos.paginas') ?>
</th>
<th style="padding-right: 0.75em;">
<?= lang('Presupuestos.papel') ?>
</th>
<th style="padding-right: 0.75em;">
<?= lang('Presupuestos.gramaje') ?>
</th>
<th style="padding-right: 0.75em;">
<?= lang('Presupuestos.marca') ?>
</th>
<th style="padding-right: 0.75em;">
<?= lang('Presupuestos.maquina') ?>
</th>
<th style="padding-right: 0.75em;">
<?= lang('Presupuestos.numeroPliegos') ?>
</th>
<th style="padding-right: 0.75em; max-width:80px">
<?= lang('Presupuestos.pliegosPedido') ?>
</th>
<th style="padding-right: 0.75em; max-width:80px">
<?= lang('Presupuestos.precioPliego') ?>
</th>
<th style="padding-right: 0.75em;">
<?= lang('Presupuestos.libro') ?>
</th>
<th style="padding-right: 0.75em; max-width:80px">
<?= lang('Presupuestos.totalPapelPedido') ?>
</th>
<th style="padding-right: 0.75em;">
<?= lang('Presupuestos.lomo') ?>
</th>
<th style="padding-right: 0.75em;">
<?= lang('Presupuestos.peso') ?>
</th>
<th style="padding-right: 0.75em; max-width:80px">
<?= lang('Presupuestos.horas') ?>
</th>
<th style="padding-right: 0.75em; max-width:80px">
<?= lang('Presupuestos.precioImpresion') ?>
</th>
<th style="padding-right: 0.75em;">
<?= lang('Presupuestos.total') ?>
</th>
</tr>
</thead>
<tbody>
</tbody>
<tfoot>
<tr>
<td class="dt-result dt-result-text" colspan="14">
<?= lang('Presupuestos.total') ?>
<?= lang("Presupuestos.Guardas") ?>:
</td>
<td id="total_comp_guardas" class="dt-result dt-result-value" colspan="2">
0.00 </td>
</tr>
</tfoot>
</table>
<div>
<button type="button" name="insertarGuardasBtn" id="insertarGuardasBtn"
class="btn btn-primary float-end me-sm-3 me-1 mb-3 insertarLinea d-none">
<?= lang('Presupuestos.insertarLinea') . ' ' . strtoupper(lang('Presupuestos.Guardas')) ?>
</button>
<div>
<button type="button" name="insertarGuardasBtn" id="insertarGuardasBtn"
class="btn btn-primary float-end me-sm-3 me-1 mb-3 insertarLinea d-none">
<?= lang('Presupuestos.insertarLinea') . ' ' . strtoupper(lang('Presupuestos.Guardas')) ?>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
<?php endif; ?>
<div class="accordion mt-3" id="accordionCompFaja">

View File

@ -25,7 +25,7 @@
<label for="created_at" class="form-label">
<?= lang('Presupuestos.created_at') ?>
</label>
<?php if(str_contains($formAction,'edit')): ?>
<?php if (str_contains($formAction, 'edit')): ?>
<input readonly style="background: #E8E8E8;" id="updated_at" name="updated_at" maxLength="12" class="form-control" value="">
<?php else: ?>
<input readonly style="background: #E8E8E8;" id="created_at" name="created_at" maxLength="12" class="form-control" value="">
@ -39,12 +39,12 @@
<?= lang('Presupuestos.presupuestoEstado') ?>
</label>
<select disabled id="estado_id" name="estado_id" maxLength="11" style="background-color: #E8E8E8;" class="form-control select2bs" value="">
<option value=1 >
<?=lang('Presupuestos.presupuestoEstadoBorrador') ?>
</option>
<option value=2 >
<?=lang('Presupuestos.presupuestoEstadoAceptado') ?>
</option>
<option value=1>
<?= lang('Presupuestos.presupuestoEstadoBorrador') ?>
</option>
<option value=2>
<?= lang('Presupuestos.presupuestoEstadoAceptado') ?>
</option>
</select>
</div><!--//.mb-3 -->
</div><!--//.col -->
@ -71,7 +71,7 @@
<div class="col-md-12 col-lg-6 px-4">
<div class="mb-3">
<label for="titulo" class="form-label">
<?=lang('Presupuestos.titulo') ?>*
<?= lang('Presupuestos.titulo') ?>*
</label>
<input type="text" id="titulo" name="titulo" maxLength="300" class="form-control" value="">
</div><!--//.mb-3 -->
@ -81,7 +81,7 @@
<div class="col-md-12 col-lg-6 px-4">
<div class="mb-3">
<label for="autor" class="form-label">
<?=lang('Presupuestos.autor') ?>
<?= lang('Presupuestos.autor') ?>
</label>
<input type="text" id="autor" name="autor" maxLength="150" class="form-control" value="">
</div><!--//.mb-3 -->
@ -95,37 +95,37 @@
<div class="col-md-12 col-lg-3 px-4">
<div class="mb-3">
<label for="coleccion" class="form-label">
<?=lang('Presupuestos.coleccion') ?>
<?= lang('Presupuestos.coleccion') ?>
</label>
<input type="text" id="coleccion" name="coleccion" maxLength="255" class="form-control" value="">
</div><!--//.mb-3 -->
</div>
<div class="col-md-12 col-lg-3 px-4">
<div class="col-md-12 col-lg-3 px-4">
<div class="mb-3">
<label for="numeroEdicion" class="form-label">
<?=lang('Presupuestos.numeroEdicion') ?>
<?= lang('Presupuestos.numeroEdicion') ?>
</label>
<input type="text" id="numeroEdicion" name="numero_edicion" maxLength="50" class="form-control" value="">
</div><!--//.mb-3 -->
</div>
<div class="col-md-12 col-lg-3 px-4">
<div class="col-md-12 col-lg-3 px-4">
<div class="mb-3">
<label for="isbn" class="form-label">
<?=lang('Presupuestos.isbn') ?>
<?= lang('Presupuestos.isbn') ?>
</label>
<input type="text" id="isbn" name="isbn" maxLength="50" class="form-control" value="">
<input type="text" id="isbn" name="isbn" maxLength="50" class="form-control" value="">
</div><!--//.mb-3 -->
</div>
<div class="col-md-12 col-lg-3 px-4">
<div class="col-md-12 col-lg-3 px-4">
<div class="mb-3">
<label for="paisId" class="form-label">
<?=lang('Presupuestos.paisId') ?>
<?= lang('Presupuestos.paisId') ?>
</label>
<select id="paisId" name="pais_id" class="form-control select2bs" style="width: 100%;" >
<?php if(isset($pais_default)): ?>
<select id="paisId" name="pais_id" class="form-control select2bs" style="width: 100%;">
<?php if (isset($pais_default)): ?>
<option value="<?= $pais_default_id ?>" selected>
<?= $pais_default ?>
</option>
@ -133,31 +133,43 @@
</select>
</div><!--//.mb-3 -->
</div>
</div> <!--//.row -->
<!-- Fila 3 -->
<div class="row">
<!-- Fila 4 -->
<div class="row">
<div class="col-md-12 col-lg-6 px-4">
<div class="mb-3">
<label for="clienteId" class="form-label">
<?= lang('Presupuestos.clienteId') ?>*
<?php if(isset($cliente_id)):?>
<a href="<?= route_to('editarCliente', $cliente_id); ?>" target="_blank" ><i class="ti ti-file-search ti-sm mx-2""></i></a>
<?php if (isset($cliente_id)): ?>
<a href="<?= route_to('editarCliente', $cliente_id); ?>" target="_blank"><i class="ti ti-file-search ti-sm mx-2""></i></a>
<?php endif; ?>
</label>
<select id="clienteId" name="cliente_id" class="form-control select2bs2" style="width: 100%;">
</select>
</select>
</div><!--//.mb-3 -->
</div><!--//.col -->
<div class="col-md-12 col-lg-6 px-4">
<div class="col-md-12 col-lg-3 px-4">
<div class="mb-3">
<label for="referenciaCliente" class="form-label">
<?=lang('Presupuestos.referenciaCliente') ?>
<?= lang('Presupuestos.referenciaCliente') ?>
</label>
<input type="text" id="referenciaCliente" name="referencia_cliente" maxLength="100" class="form-control" value="">
<input type="text" id="referenciaCliente" name="referencia_cliente" maxLength="100" class="form-control" value="">
</div><!--//.mb-3 -->
</div><!--//.col -->
<div class="col-md-12 col-lg-3 px-4">
<div class="mb-3">
<label for="iskn" class="form-label">
<?= lang('Presupuestos.iskn') ?>
</label>
<input type="text" id="iskn" name="iskn" class="form-control" readonly
value="" maxlength="64"
style="background: #E8E8E8;">
</div><!--//.mb-3 -->
</div><!--//.col -->
@ -167,4 +179,4 @@
</div> <!-- //.accordion-body -->
</div> <!-- //.accordion-collapse -->
</div> <!-- //.accordion-item -->
</div> <!-- //.accordion -->
</div> <!-- //.accordion -->

View File

@ -1,4 +1,4 @@
<div id="addressForm" action='create' class="modal fade addModal">
<div id="addressForm" action='create' data-table="" class="modal fade addModal">
<div class="modal-dialog modal-lg modal-simple">
<div class="modal-content">
<div class="modal-header">
@ -9,14 +9,6 @@
<div id='error-tarifa'></div>
<div class="mb-3" id="direccionFerroProto">
<label for="dirFerroProto" class="form-label">
Dirección Ferro o Prototipo
</label>
<input type="checkbox" id="dirFerroProto" class="form-check-input">
</div><!--//.mb-3 -->
<div class="mb-3">
<label for="add_clientedAdd" class="form-label">
<?= lang('PresupuestosDirecciones.clientedAdd') ?>*

View File

@ -155,7 +155,7 @@
<!-- Configuraciones -->
<div class="row g-3 mb-3">
<div class="col-12">
<a id="pv_bn_pg" href="#" sk-url="<?= str_replace('/0', '', route_to('updatePapelGenerico', 0)); ?>" target="_blank">
<a id="pv_bn_pg" href="#" sk-url="<?= str_replace('0', '', route_to('updatePapelGenerico', 0)); ?>" target="_blank">
<div class="d-grid">
<button type="button" class="btn btn-label-primary">
<?= lang("Presupuestos.previewPapelGenerico") ?>
@ -164,7 +164,7 @@
</a>
</div>
<div class="col-12">
<a id="pv_bn_pi" href="#" sk-url="<?= str_replace('/0', '', route_to('updatePapelImpresion', 0)); ?>" target="_blank">
<a id="pv_bn_pi" href="#" sk-url="<?= str_replace('0', '', route_to('updatePapelImpresion', 0)); ?>" target="_blank">
<div class="d-grid">
<button type="button" class="btn btn-label-primary">
<?= lang("Presupuestos.previewPapelCompra") ?>
@ -173,7 +173,7 @@
</a>
</div>
<div class="col-12">
<a id="pv_bn_mi" href="#" sk-url="<?= str_replace('/0', '', route_to('updateMaquina', 0)); ?>" target="_blank">
<a id="pv_bn_mi" href="#" sk-url="<?= str_replace('0', '', route_to('updateMaquina', 0)); ?>" target="_blank">
<div class="d-grid">
<button type="button" class="btn btn-label-primary">
<?= lang("Presupuestos.previewAreaImpresion") ?>
@ -237,7 +237,7 @@
<!-- Configuraciones -->
<div class="row g-3 mb-3">
<div class="col-12">
<a id="pv_bnhq_pg" href="#" sk-url="<?= str_replace('/0', '', route_to('updatePapelGenerico', 0)); ?>" target="_blank">
<a id="pv_bnhq_pg" href="#" sk-url="<?= str_replace('0', '', route_to('updatePapelGenerico', 0)); ?>" target="_blank">
<div class="d-grid">
<button type="button" class="btn btn-label-primary">
<?= lang("Presupuestos.previewPapelGenerico") ?>
@ -246,7 +246,7 @@
</a>
</div>
<div class="col-12">
<a id="pv_bnhq_pi" href="#" sk-url="<?= str_replace('/0', '', route_to('updatePapelImpresion', 0)); ?>" target="_blank">
<a id="pv_bnhq_pi" href="#" sk-url="<?= str_replace('0', '', route_to('updatePapelImpresion', 0)); ?>" target="_blank">
<div class="d-grid">
<button type="button" class="btn btn-label-primary">
<?= lang("Presupuestos.previewPapelCompra") ?>
@ -255,7 +255,7 @@
</a>
</div>
<div class="col-12">
<a id="pv_bnhq_mi" href="#" sk-url="<?= str_replace('/0', '', route_to('updateMaquina', 0)); ?>" target="_blank">
<a id="pv_bnhq_mi" href="#" sk-url="<?= str_replace('0', '', route_to('updateMaquina', 0)); ?>" target="_blank">
<div class="d-grid">
<button type="button" class="btn btn-label-primary">
<?= lang("Presupuestos.previewAreaImpresion") ?>
@ -319,7 +319,7 @@
<!-- Configuraciones -->
<div class="row g-3 mb-3">
<div class="col-12">
<a id="pv_color_pg" href="#" sk-url="<?= str_replace('/0', '', route_to('updatePapelGenerico', 0)); ?>" target="_blank">
<a id="pv_color_pg" href="#" sk-url="<?= str_replace('0', '', route_to('updatePapelGenerico', 0)); ?>" target="_blank">
<div class="d-grid">
<button type="button" class="btn btn-label-primary">
<?= lang("Presupuestos.previewPapelGenerico") ?>
@ -328,7 +328,7 @@
</a>
</div>
<div class="col-12">
<a id="pv_color_pi" href="#" sk-url="<?= str_replace('/0', '', route_to('updatePapelImpresion', 0)); ?>" target="_blank">
<a id="pv_color_pi" href="#" sk-url="<?= str_replace('0', '', route_to('updatePapelImpresion', 0)); ?>" target="_blank">
<div class="d-grid">
<button type="button" class="btn btn-label-primary">
<?= lang("Presupuestos.previewPapelCompra") ?>
@ -337,7 +337,7 @@
</a>
</div>
<div class="col-12">
<a id="pv_color_mi" href="#" sk-url="<?= str_replace('/0', '', route_to('updateMaquina', 0)); ?>" target="_blank">
<a id="pv_color_mi" href="#" sk-url="<?= str_replace('0', '', route_to('updateMaquina', 0)); ?>" target="_blank">
<div class="d-grid">
<button type="button" class="btn btn-label-primary">
<?= lang("Presupuestos.previewAreaImpresion") ?>
@ -401,7 +401,7 @@
<!-- Configuraciones -->
<div class="row g-3 mb-3">
<div class="col-12">
<a id="pv_colorhq_pg" href="#" sk-url="<?= str_replace('/0', '', route_to('updatePapelGenerico', 0)); ?>" target="_blank">
<a id="pv_colorhq_pg" href="#" sk-url="<?= str_replace('0', '', route_to('updatePapelGenerico', 0)); ?>" target="_blank">
<div class="d-grid">
<button type="button" class="btn btn-label-primary">
<?= lang("Presupuestos.previewPapelGenerico") ?>
@ -410,7 +410,7 @@
</a>
</div>
<div class="col-12">
<a id="pv_colorhq_pi" href="#" sk-url="<?= str_replace('/0', '', route_to('updatePapelImpresion', 0)); ?>" target="_blank">
<a id="pv_colorhq_pi" href="#" sk-url="<?= str_replace('0', '', route_to('updatePapelImpresion', 0)); ?>" target="_blank">
<div class="d-grid">
<button type="button" class="btn btn-label-primary">
<?= lang("Presupuestos.previewPapelCompra") ?>
@ -419,7 +419,7 @@
</a>
</div>
<div class="col-12">
<a id="pv_colorhq_mi" href="#" sk-url="<?= str_replace('/0', '', route_to('updateMaquina', 0)); ?>" target="_blank">
<a id="pv_colorhq_mi" href="#" sk-url="<?= str_replace('0', '', route_to('updateMaquina', 0)); ?>" target="_blank">
<div class="d-grid">
<button type="button" class="btn btn-label-primary">
<?= lang("Presupuestos.previewAreaImpresion") ?>
@ -485,7 +485,7 @@
<!-- Configuraciones -->
<div class="row g-3 mb-3">
<div class="col-12">
<a id="pv_rot_bn_pg" href="#" sk-url="<?= str_replace('/0', '', route_to('updatePapelGenerico', 0)); ?>" target="_blank">
<a id="pv_rot_bn_pg" href="#" sk-url="<?= str_replace('0', '', route_to('updatePapelGenerico', 0)); ?>" target="_blank">
<div class="d-grid">
<button type="button" class="btn btn-label-primary">
<?= lang("Presupuestos.previewPapelGenerico") ?>
@ -494,7 +494,7 @@
</a>
</div>
<div class="col-12">
<a id="pv_rot_bn_pi" href="#" sk-url="<?= str_replace('/0', '', route_to('updatePapelImpresion', 0)); ?>" target="_blank">
<a id="pv_rot_bn_pi" href="#" sk-url="<?= str_replace('0', '', route_to('updatePapelImpresion', 0)); ?>" target="_blank">
<div class="d-grid">
<button type="button" class="btn btn-label-primary">
<?= lang("Presupuestos.previewPapelCompra") ?>
@ -503,7 +503,7 @@
</a>
</div>
<div class="col-12">
<a id="pv_rot_bn_mi" href="#" sk-url="<?= str_replace('/0', '', route_to('updateMaquina', 0)); ?>" target="_blank">
<a id="pv_rot_bn_mi" href="#" sk-url="<?= str_replace('0', '', route_to('updateMaquina', 0)); ?>" target="_blank">
<div class="d-grid">
<button type="button" class="btn btn-label-primary">
<?= lang("Presupuestos.previewAreaImpresion") ?>
@ -565,7 +565,7 @@
<!-- Configuraciones -->
<div class="row g-3 mb-3">
<div class="col-12">
<a id="pv_rot_color_pg" href="#" sk-url="<?= str_replace('/0', '', route_to('updatePapelGenerico', 0)); ?>" target="_blank">
<a id="pv_rot_color_pg" href="#" sk-url="<?= str_replace('0', '', route_to('updatePapelGenerico', 0)); ?>" target="_blank">
<div class="d-grid">
<button type="button" class="btn btn-label-primary">
<?= lang("Presupuestos.previewPapelGenerico") ?>
@ -574,7 +574,7 @@
</a>
</div>
<div class="col-12">
<a id="pv_rot_color_pi" href="#" sk-url="<?= str_replace('/0', '', route_to('updatePapelImpresion', 0)); ?>" target="_blank">
<a id="pv_rot_color_pi" href="#" sk-url="<?= str_replace('0', '', route_to('updatePapelImpresion', 0)); ?>" target="_blank">
<div class="d-grid">
<button type="button" class="btn btn-label-primary">
<?= lang("Presupuestos.previewPapelCompra") ?>
@ -583,7 +583,7 @@
</a>
</div>
<div class="col-12">
<a id="pv_rot_color_mi" href="#" sk-url="<?= str_replace('/0', '', route_to('updateMaquina', 0)); ?>" target="_blank">
<a id="pv_rot_color_mi" href="#" sk-url="<?= str_replace('0', '', route_to('updateMaquina', 0)); ?>" target="_blank">
<div class="d-grid">
<button type="button"
class="btn btn-label-primary">
@ -646,7 +646,7 @@
<!-- Configuraciones -->
<div class="row g-3 mb-3">
<div class="col-12">
<a id="pv_guardas_pg" href="#" sk-url="<?= str_replace('/0', '', route_to('updatePapelGenerico', 0)); ?>" target="_blank">
<a id="pv_guardas_pg" href="#" sk-url="<?= str_replace('0', '', route_to('updatePapelGenerico', 0)); ?>" target="_blank">
<div class="d-grid">
<button type="button" class="btn btn-label-primary">
<?= lang("Presupuestos.previewPapelGenerico") ?>
@ -655,7 +655,7 @@
</a>
</div>
<div class="col-12">
<a id="pv_guardas_pi" href="#" sk-url="<?= str_replace('/0', '', route_to('updatePapelImpresion', 0)); ?>" target="_blank">
<a id="pv_guardas_pi" href="#" sk-url="<?= str_replace('0', '', route_to('updatePapelImpresion', 0)); ?>" target="_blank">
<div class="d-grid">
<button type="button" class="btn btn-label-primary">
<?= lang("Presupuestos.previewPapelCompra") ?>
@ -664,7 +664,7 @@
</a>
</div>
<div class="col-12">
<a id="pv_guardas_mi" href="#" sk-url="<?= str_replace('/0', '', route_to('updateMaquina', 0)); ?>" target="_blank">
<a id="pv_guardas_mi" href="#" sk-url="<?= str_replace('0', '', route_to('updateMaquina', 0)); ?>" target="_blank">
<div class="d-grid">
<button type="button" class="btn btn-label-primary">
<?= lang("Presupuestos.previewAreaImpresion") ?>
@ -728,7 +728,7 @@
<!-- Configuraciones -->
<div class="row g-3 mb-3">
<div class="col-12">
<a id="pv_cubierta_pg" href="#" sk-url="<?= str_replace('/0', '', route_to('updatePapelGenerico', 0)); ?>" target="_blank">
<a id="pv_cubierta_pg" href="#" sk-url="<?= str_replace('0', '', route_to('updatePapelGenerico', 0)); ?>" target="_blank">
<div class="d-grid">
<button type="button" class="btn btn-label-primary">
<?= lang("Presupuestos.previewPapelGenerico") ?>
@ -737,7 +737,7 @@
</a>
</div>
<div class="col-12">
<a id="pv_cubierta_pi" href="#" sk-url="<?= str_replace('/0', '', route_to('updatePapelImpresion', 0)); ?>" target="_blank">
<a id="pv_cubierta_pi" href="#" sk-url="<?= str_replace('0', '', route_to('updatePapelImpresion', 0)); ?>" target="_blank">
<div class="d-grid">
<button type="button" class="btn btn-label-primary">
<?= lang("Presupuestos.previewPapelCompra") ?>
@ -746,7 +746,7 @@
</a>
</div>
<div class="col-12">
<a id="pv_cubierta_mi" href="#" sk-url="<?= str_replace('/0', '', route_to('updateMaquina', 0)); ?>" target="_blank">
<a id="pv_cubierta_mi" href="#" sk-url="<?= str_replace('0', '', route_to('updateMaquina', 0)); ?>" target="_blank">
<div class="d-grid">
<button type="button" class="btn btn-label-primary">
<?= lang("Presupuestos.previewAreaImpresion") ?>
@ -813,7 +813,7 @@
<!-- Configuraciones -->
<div class="row g-3 mb-3">
<div class="col-12">
<a id="pv_ec_pg" href="#" sk-url="<?= str_replace('/0', '', route_to('updatePapelGenerico', 0)); ?>" target="_blank">
<a id="pv_ec_pg" href="#" sk-url="<?= str_replace('0', '', route_to('updatePapelGenerico', 0)); ?>" target="_blank">
<div class="d-grid">
<button type="button" class="btn btn-label-primary">
<?= lang("Presupuestos.previewPapelGenerico") ?>
@ -822,7 +822,7 @@
</a>
</div>
<div class="col-12">
<a id="pv_ec_pi" href="#" sk-url="<?= str_replace('/0', '', route_to('updatePapelImpresion', 0)); ?>" target="_blank">
<a id="pv_ec_pi" href="#" sk-url="<?= str_replace('0', '', route_to('updatePapelImpresion', 0)); ?>" target="_blank">
<div class="d-grid">
<button type="button" class="btn btn-label-primary">
<?= lang("Presupuestos.previewPapelCompra") ?>
@ -831,7 +831,7 @@
</a>
</div>
<div class="col-12">
<a id="pv_ec_mi" href="#" sk-url="<?= str_replace('/0', '', route_to('updateMaquina', 0)); ?>" target="_blank">
<a id="pv_ec_mi" href="#" sk-url="<?= str_replace('0', '', route_to('updateMaquina', 0)); ?>" target="_blank">
<div class="d-grid">
<button type="button" class="btn btn-label-primary">
<?= lang("Presupuestos.previewAreaImpresion") ?>
@ -882,7 +882,7 @@
<!-- Configuraciones -->
<div class="row g-3 mb-3">
<div class="col-12">
<a id="pv_sobrecubierta_pg" href="#" sk-url="<?= str_replace('/0', '', route_to('updatePapelGenerico', 0)); ?>" target="_blank">
<a id="pv_sobrecubierta_pg" href="#" sk-url="<?= str_replace('0', '', route_to('updatePapelGenerico', 0)); ?>" target="_blank">
<div class="d-grid">
<button type="button" class="btn btn-label-primary">
<?= lang("Presupuestos.previewPapelGenerico") ?>
@ -891,7 +891,7 @@
</a>
</div>
<div class="col-12">
<a id="pv_sobrecubierta_pi" href="#" sk-url="<?= str_replace('/0', '', route_to('updatePapelImpresion', 0)); ?>" target="_blank">
<a id="pv_sobrecubierta_pi" href="#" sk-url="<?= str_replace('0', '', route_to('updatePapelImpresion', 0)); ?>" target="_blank">
<div class="d-grid">
<button type="button" class="btn btn-label-primary">
<?= lang("Presupuestos.previewPapelCompra") ?>
@ -900,7 +900,7 @@
</a>
</div>
<div class="col-12">
<a id="pv_sobrecubierta_mi" href="#" sk-url="<?= str_replace('/0', '', route_to('updateMaquina', 0)); ?>" target="_blank">
<a id="pv_sobrecubierta_mi" href="#" sk-url="<?= str_replace('0', '', route_to('updateMaquina', 0)); ?>" target="_blank">
<div class="d-grid">
<button type="button" class="btn btn-label-primary">
<?= lang("Presupuestos.previewAreaImpresion") ?>
@ -963,7 +963,7 @@
<!-- Configuraciones -->
<div class="row g-3 mb-3">
<div class="col-12">
<a id="pv_faja_pg" href="#" sk-url="<?= str_replace('/0', '', route_to('updatePapelGenerico', 0)); ?>" target="_blank">
<a id="pv_faja_pg" href="#" sk-url="<?= str_replace('0', '', route_to('updatePapelGenerico', 0)); ?>" target="_blank">
<div class="d-grid">
<button type="button" class="btn btn-label-primary">
<?= lang("Presupuestos.previewPapelGenerico") ?>
@ -972,7 +972,7 @@
</a>
</div>
<div class="col-12">
<a id="pv_faja_pi" href="#" sk-url="<?= str_replace('/0', '', route_to('updatePapelImpresion', 0)); ?>" target="_blank">
<a id="pv_faja_pi" href="#" sk-url="<?= str_replace('0', '', route_to('updatePapelImpresion', 0)); ?>" target="_blank">
<div class="d-grid">
<button type="button" class="btn btn-label-primary">
<?= lang("Presupuestos.previewPapelCompra") ?>
@ -981,7 +981,7 @@
</a>
</div>
<div class="col-12">
<a id="pv_faja_mi" href="#" sk-url="<?= str_replace('/0', '', route_to('updateMaquina', 0)); ?>" target="_blank">
<a id="pv_faja_mi" href="#" sk-url="<?= str_replace('0', '', route_to('updateMaquina', 0)); ?>" target="_blank">
<div class="d-grid">
<button type="button" class="btn btn-label-primary">
<?= lang("Presupuestos.previewAreaImpresion") ?>

View File

@ -13,92 +13,110 @@
<div class="col-xl-12">
<div class="border rounded p-4 mb-3 pb-3">
<!-- Price Details -->
<dl class="row mb-0">
<dt class="col-5 py-1 fw-normal text-end">Coste papel</dt>
<dd class="py-1 col-6 text-end"><span id="totalCostePapel"
class="autonumeric-resumen-currency"></span></dd>
<dt class="col-5 py-1 fw-normal text-end">Margen papel</dt>
<dd class="col-3 text-end py-1"><span id="porcentajeMargenPapel"
class="autonumeric-resumen-percent"></span></dd>
<dd class="col-3 text-end py-1"><span id="margenPapel"
class="autonumeric-resumen-currency"></span></dd>
<div class="d-flex justify-content-between align-items-center mb-4">
<h5 class="mb-0">Costes detallados</h5>
<button class="btn btn-sm btn-link p-0" type="button" data-bs-toggle="collapse"
data-bs-target="#detallesCostes" aria-expanded="true"
aria-controls="detallesCostes" title="Mostrar/ocultar detalle de precios">
<i class="ti ti-chevron-down"></i>
</button>
</div>
<dt class="col-5 fw-normal text-end">
<a href="javascript:void(0);" data-bs-toggle="collapse" data-bs-target=".costes-impresion" aria-expanded="false" aria-controls="costes-impresion">
<i class="ti ti-list ti-sm mx-2"></i>
</a>
Coste impresión
</dt>
<dd class="col-6 text-end py-1"><span id="totalCosteImpresion"
class="autonumeric-resumen-currency"></span></dd>
<!-- Bloque colapsable, sin <div>, solo usando clases -->
<dt class="col-5 fw-normal text-end collapse costes-impresion">Coste clicks</dt>
<dd class="col-6 text-end py-1 collapse costes-impresion">
<span id="totalCosteClicks" class="autonumeric-resumen-currency"></span>
</dd>
<div id="detallesCostes" class="collapse">
<!-- Price Details -->
<dl class="row mb-0">
<dt class="col-5 py-1 fw-normal text-end">Coste papel</dt>
<dd class="py-1 col-6 text-end"><span id="totalCostePapel"
class="autonumeric-resumen-currency"></span></dd>
<dt class="col-5 py-1 fw-normal text-end">Margen papel</dt>
<dd class="col-3 text-end py-1"><span id="porcentajeMargenPapel"
class="autonumeric-resumen-percent"></span></dd>
<dd class="col-3 text-end py-1"><span id="margenPapel"
class="autonumeric-resumen-currency"></span></dd>
<dt class="col-5 fw-normal text-end collapse costes-impresion">Coste horas</dt>
<dd class="col-6 text-end py-1 collapse costes-impresion">
<span id="totalCosteHoras" class="autonumeric-resumen-currency"></span>
</dd>
<dt class="col-5 fw-normal text-end">
<a href="javascript:void(0);" data-bs-toggle="collapse"
data-bs-target=".costes-impresion" aria-expanded="false"
aria-controls="costes-impresion">
<i class="ti ti-list ti-sm mx-2"></i>
</a>
Coste impresión
</dt>
<dd class="col-6 text-end py-1"><span id="totalCosteImpresion"
class="autonumeric-resumen-currency"></span></dd>
<!-- Bloque colapsable, sin <div>, solo usando clases -->
<dt class="col-5 fw-normal text-end collapse costes-impresion">Coste clicks</dt>
<dd class="col-6 text-end py-1 collapse costes-impresion">
<span id="totalCosteClicks" class="autonumeric-resumen-currency"></span>
</dd>
<dt class="col-5 fw-normal text-end collapse costes-impresion">Coste tinta</dt>
<dd class="col-6 text-end py-1 collapse costes-impresion">
<span id="totalCosteTinta" class="autonumeric-resumen-currency" ></span>
</dd>
<dt class="col-5 fw-normal text-end collapse costes-impresion">Coste horas</dt>
<dd class="col-6 text-end py-1 collapse costes-impresion">
<span id="totalCosteHoras" class="autonumeric-resumen-currency"></span>
</dd>
<dt class="col-5 fw-normal text-end collapse costes-impresion">Coste corte</dt>
<dd class="col-6 text-end py-1 collapse costes-impresion">
<span id="totalCosteCorte" class="autonumeric-resumen-currency"></span>
</dd>
<dt class="col-5 py-1 fw-normal text-end">
<a href="javascript:void(0);" data-bs-toggle="collapse" data-bs-target=".margen-impresion" aria-expanded="false" aria-controls="margen-impresion">
<i class="ti ti-list ti-sm mx-2"></i>
</a>
Margen impresión
</dt>
<dd class="col-3 text-end py-1"><span id="porcentajeMargenImpresion"
class="autonumeric-resumen-percent"></span></dd>
<dd class="col-3 text-end py-1"><span id="margenImpresion"
class="autonumeric-resumen-currency"></span></dd>
<!-- Bloque colapsable, sin <div>, solo usando clases -->
<dt class="col-5 fw-normal text-end collapse margen-impresion">Margen clicks</dt>
<dd class="col-6 text-end py-1 collapse margen-impresion">
<span id="totalMargenClicks" class="autonumeric-resumen-currency"></span>
</dd>
<dt class="col-5 fw-normal text-end collapse costes-impresion">Coste tinta</dt>
<dd class="col-6 text-end py-1 collapse costes-impresion">
<span id="totalCosteTinta" class="autonumeric-resumen-currency"></span>
</dd>
<dt class="col-5 fw-normal text-end collapse margen-impresion">Margen horas</dt>
<dd class="col-6 text-end py-1 collapse margen-impresion">
<span id="totalMargenHoras" class="autonumeric-resumen-currency"></span>
</dd>
<dt class="col-5 fw-normal text-end collapse costes-impresion">Coste corte</dt>
<dd class="col-6 text-end py-1 collapse costes-impresion">
<span id="totalCosteCorte" class="autonumeric-resumen-currency"></span>
</dd>
<dt class="col-5 py-1 fw-normal text-end">
<a href="javascript:void(0);" data-bs-toggle="collapse"
data-bs-target=".margen-impresion" aria-expanded="false"
aria-controls="margen-impresion">
<i class="ti ti-list ti-sm mx-2"></i>
</a>
Margen impresión
</dt>
<dd class="col-3 text-end py-1"><span id="porcentajeMargenImpresion"
class="autonumeric-resumen-percent"></span></dd>
<dd class="col-3 text-end py-1"><span id="margenImpresion"
class="autonumeric-resumen-currency"></span></dd>
<!-- Bloque colapsable, sin <div>, solo usando clases -->
<dt class="col-5 fw-normal text-end collapse margen-impresion">Margen clicks</dt>
<dd class="col-6 text-end py-1 collapse margen-impresion">
<span id="totalMargenClicks" class="autonumeric-resumen-currency"></span>
</dd>
<dt class="col-5 fw-normal text-end collapse margen-impresion">Margen tinta</dt>
<dd class="col-6 text-end py-1 collapse margen-impresion">
<span id="totalMargenTinta" class="autonumeric-resumen-currency" ></span>
</dd>
<dt class="col-5 fw-normal text-end collapse margen-impresion">Margen horas</dt>
<dd class="col-6 text-end py-1 collapse margen-impresion">
<span id="totalMargenHoras" class="autonumeric-resumen-currency"></span>
</dd>
<dt class="col-5 fw-normal text-end collapse margen-impresion">Margen corte</dt>
<dd class="col-6 text-end py-1 collapse margen-impresion">
<span id="totalMargenCorte" class="autonumeric-resumen-currency"></span>
</dd>
<dt class="col-5 fw-normal text-end collapse margen-impresion">Margen tinta</dt>
<dd class="col-6 text-end py-1 collapse margen-impresion">
<span id="totalMargenTinta" class="autonumeric-resumen-currency"></span>
</dd>
<dt class="col-5 fw-normal text-end collapse margen-impresion">Margen corte</dt>
<dd class="col-6 text-end py-1 collapse margen-impresion">
<span id="totalMargenCorte" class="autonumeric-resumen-currency"></span>
</dd>
<dt class="col-5 fw-normal text-end">Coste servicios</dt>
<dd class="col-6 text-end py-1 "><span id="totalServicios"
class="autonumeric-resumen-currency"></span></dd>
<dt class="col-5 fw-normal text-end">Margen servicios</dt>
<dd class="col-3 text-end py-1 "><span id="porcentajeMargenServicios"
class="autonumeric-resumen-percent"></span></dd>
<dd class="col-3 text-end py-1 "><span id="margenServicios"
class="autonumeric-resumen-currency"></span></dd>
<dt class="col-5 fw-normal text-end">Coste de envío</dt>
<dd class="col-6 text-end py-1 "><span id="costeEnvios"
class="autonumeric-resumen-currency"></span></dd>
<dt class="col-5 fw-normal text-end">Margen envío</dt>
<dd class="col-6 text-end py-1 "><span id="margenEnvios"
class="autonumeric-resumen-currency"></span></dd>
</dl>
</div>
<dt class="col-5 fw-normal text-end">Coste servicios</dt>
<dd class="col-6 text-end py-1 "><span id="totalServicios"
class="autonumeric-resumen-currency"></span></dd>
<dt class="col-5 fw-normal text-end">Margen servicios</dt>
<dd class="col-3 text-end py-1 "><span id="porcentajeMargenServicios"
class="autonumeric-resumen-percent"></span></dd>
<dd class="col-3 text-end py-1 "><span id="margenServicios"
class="autonumeric-resumen-currency"></span></dd>
<dt class="col-5 fw-normal text-end">Coste de envío</dt>
<dd class="col-6 text-end py-1 "><span id="costeEnvios"
class="autonumeric-resumen-currency"></span></dd>
<dt class="col-5 fw-normal text-end">Margen envío</dt>
<dd class="col-6 text-end py-1 "><span id="margenEnvios"
class="autonumeric-resumen-currency"></span></dd>
</dl>
<hr class="mx-n4">
@ -111,7 +129,7 @@
class="autonumeric-resumen-percent"></span></dd>
<dd class="col-3 text-end py-1"><span id="totalMargenes"
class="autonumeric-resumen-currency"></span></dd>
<dt class="col-5 fw-normal text-end">Total envío base</dt>
<dt class="col-5 fw-normal text-end">Total envío base</dt>
<dd class="col-6 text-end py-1 "><span id="precioEnvios"
class="autonumeric-resumen-currency"></span></dd>
</dl>
@ -168,7 +186,8 @@
<div class="col-xl-12 mt-3">
<div class="card border border-secondary-subtle rounded-3">
<div class="card-body">
<div id="div_ajustar_error" class="alert alert-danger d-flex align-items-baseline d-none" role="alert">
<div id="div_ajustar_error" class="alert alert-danger d-flex align-items-baseline d-none"
role="alert">
<span class="alert-icon alert-icon-lg text-primary me-2">
<i class="ti ti-ban ti-sm"></i>
</span>
@ -194,15 +213,15 @@
</div>
</div>
<?php /*if ($presupuestoEntity->estado_id == 2): ?>
<div class="row">
<div class="col-sm-6 mb-1">
<label for="totalAceptado"
class="form-label"><?= lang('Presupuestos.totalAceptado') ?></label>
<input disabled type="text" id="totalAceptado" name="totalAceptado"
class="form-control text-center fs-5 autonumeric-resumen-currency" value="" <?php echo ($tipo_impresion_id == 21) ? ' max=80' : '' ?>>
</div>
</div>
<?php endif; */ ?>
<div class="row">
<div class="col-sm-6 mb-1">
<label for="totalAceptado"
class="form-label"><?= lang('Presupuestos.totalAceptado') ?></label>
<input disabled type="text" id="totalAceptado" name="totalAceptado"
class="form-control text-center fs-5 autonumeric-resumen-currency" value="" <?php echo ($tipo_impresion_id == 21) ? ' max=80' : '' ?>>
</div>
</div>
<?php endif; */ ?>
<div class="row">
<p>
<span id="aprobado_by_at"></span>

View File

@ -228,6 +228,7 @@
<!------------------------------------------->
<?= $this->section("additionalInlineJs") ?>
$(document).keypress(function(e) {
var key = e.which;
if (key == 13) // the enter key code

View File

@ -68,6 +68,9 @@
</div>
</div>
<div id="sk-alert-ferro-prototipo1">
</div>
<div id="direccionesFerroPrototipo" class="row col-sm-12 mb-5 justify-content-center d-none">
<div class="col-sm-8 mb-3 d-flex flex-column align-items-center">
<h3 class="mb-1 fw-bold"> Dirección de envío ferro/prototipo</h3>
@ -101,11 +104,14 @@
</div>
<div id="divDireccionesFerroPrototipo"
class="calcular-presupuesto col-sm-12 d-flex flex-column align-items-center div-direcciones-ferro-prototipo">
class="col-sm-12 d-flex flex-column align-items-center div-direcciones-ferro-prototipo">
</div>
</div>
<div id="sk-alert-ferro-prototipo2">
</div>
<div id="direccionesFerroPrototipo2" class="row col-sm-12 mb-5 justify-content-center d-none">
<div class="col-sm-8 mb-3 d-flex flex-column align-items-center">
<h3 class="mb-1 fw-bold"> Dirección de envío ferro/prototipo 2</h3>
@ -146,7 +152,7 @@
</div>
<div id="divDireccionesFerroPrototipo2"
class="calcular-presupuesto col-sm-12 d-flex flex-column align-items-center div-direcciones-ferro-prototipo">
class="col-sm-12 d-flex flex-column align-items-center div-direcciones-ferro-prototipo">
</div>
</div>

View File

@ -136,10 +136,11 @@
<?= lang('Presupuestos.cabezada') ?>
</label>
<select class="form-select select2bs2" id="cabezada" name="cabezada">
<option value="WHI"><?= lang('Presupuestos.blanca') ?></option>
<option value="GRE"><?= lang('Presupuestos.verde') ?></option>
<option value="BLUE"><?= lang('Presupuestos.azul') ?></option>
<option value="REDYEL"><?= lang('Presupuestos.rojaAmarilla') ?></option>
<?php foreach ($cabezadas as $key => $langKey): ?>
<option value="<?= esc($key) ?>">
<?= lang($langKey) ?>
</option>
<?php endforeach; ?>
</select>
</div>

View File

@ -206,7 +206,7 @@
</div>
</div>
<button id="btnUploadFile" class="btn mt-3 btn-primary btn-submit waves-effect waves-light ml-2 ">
<span class="align-middle d-sm-inline-block d-none me-sm-1"><?= lang('App.global_upload_files') ?></span>
<span class="align-middle d-sm-inline-block d-none me-sm-1"><?= lang('App.global_select_files') ?></span>
<i class="ti ti-upload ti-xs"></i>
</button>
<button id="submit-all-files" class="btn mt-3 btn-success btn-submit waves-effect waves-light ml-2">

View File

@ -1,5 +1,9 @@
<div class="row">
<div class="col-md-12">
<?= view("themes/vuexy/components/dropzone",data: ['id' => 'dropzone-ot-files','modelId' => $presupuesto->id]) ?>
<?= view("themes/vuexy/components/dropzone", data: [
'id' => 'dropzone-ot-files',
'modelId' => $presupuesto->id,
'otId' => $ot->id
]) ?>
</div><!--//.col -->
</div><!--//.row -->

View File

@ -11,7 +11,10 @@ if (
auth()->user()->can('maquinas.menu') ||
auth()->user()->can('maquinas-defecto.menu') ||
auth()->user()->can('usuarios.menu') ||
auth()->user()->can('roles-permisos.menu')
auth()->user()->can('roles-permisos.menu') ||
auth()->user()->can('proveedores.menu') ||
auth()->user()->can('ubicaciones.menu') ||
auth()->user()->can('series-facturas.menu')
) {
?>
<li class="menu-item">
@ -63,14 +66,14 @@ if (
</a>
</li>
<?php } ?>
<?php if (auth()->user()->inGroup('admin')) { ?>
<?php if (auth()->user()->inGroup('root')) { ?>
<li class="menu-item">
<a href="<?= route_to("maquinaTareaList") ?>" class="menu-link">
<div> <?= lang("App.menu_maquina_tareas") ?></div>
</a>
</li>
<?php } ?>
<?php if (auth()->user()->inGroup('admin')) { ?>
<?php if (auth()->user()->inGroup('root')) { ?>
<li class="menu-item">
<a href="<?= route_to("imposicionList") ?>" class="menu-link">
<div> <?= lang("App.menu_imposiciones") ?></div>
@ -112,29 +115,28 @@ if (
</a>
</li>
<?php } ?>
<?php if (auth()->user()->inGroup('admin')) { ?>
<?php if (auth()->user()->inGroup('root')) { ?>
<li class="menu-item">
<a href="<?= route_to('erroresPresupuestoIndex') ?>" class="menu-link">
<div> <?= lang("App.menu_error_presupuesto") ?></div>
</a>
</li>
<?php } ?>
<?php if (auth()->user()->inGroup('admin')) { ?>
<?php if (auth()->user()->inGroup('root')) { ?>
<li class="menu-item">
<a href="<?= route_to('variablesIndex') ?>" class="menu-link">
<div> <?= lang("App.menu_variables") ?></div>
</a>
</li>
<?php } ?>
<?php if (auth()->user()->inGroup('admin')) { ?>
<?php if (auth()->user()->inGroup('root')) { ?>
<li class="menu-item">
<a href="<?= route_to('configMessagesIndex') ?>" class="menu-link">
<div> <?= lang("App.menu_config_messages") ?></div>
</a>
</li>
<?php } ?>
<?php if (auth()->user()->inGroup('admin')) { ?>
<?php if (auth()->user()->inGroup('root')) { ?>
<li class="menu-item">
<a href="<?= route_to('festivosList') ?>" class="menu-link">
<div> <?= lang("App.menu_config_holidays") ?></div>

View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html>
<head>
<title>403 Forbidden</title>
</head>
<body>
<p>Directory access is forbidden.</p>
</body>
</html>

BIN
httpdocs/assets/img/pdf.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

View File

@ -59,6 +59,7 @@ class Ajax {
error: this.error
})
}
getPromise() {
if (this.jqXHR) {
this.jqXHR.abort();
@ -71,7 +72,7 @@ class Ajax {
data: this.data,
headers: this.headers,
success: (response) => {
if (this.success) this.success(response);
if (this.success) this.success(response);
resolve(response);
},
error: (xhr) => {

View File

@ -130,4 +130,19 @@ export const alertWarning = (value, target = 'body',options = {}) => {
timerProgressBar: true,
...options
})
}
}
export const alertFileUploadSuccess = (message = "Archivos subidos correctamente.") => {
return Swal.fire({
icon: "success",
title: "Carga finalizada",
text: message,
showConfirmButton: false,
timer: 3000,
customClass: {
popup: 'p-4',
title: 'fs-4 fw-bold text-success',
htmlContainer: 'text-muted',
}
});
};

View File

@ -1,10 +1,8 @@
import Modal from "./modal.js";
import Ajax from "./ajax.js";
class ConfigVariableDatatable
{
constructor(domItem)
{
class ConfigVariableDatatable {
constructor(domItem) {
this.domItem = domItem
this.datatableItem = this.domItem
this.modalItem = $("#modalConfigVariableForm")
@ -14,76 +12,69 @@ class ConfigVariableDatatable
this.formEdit = this.modalItem.find("#formEditConfigVariable")
}
init(){
init() {
this.datatable = this.datatableItem.DataTable({
processing: true,
dom: 'Blrtip',
serverSide: true,
lengthMenu: [ 25, 50, 100, 200 ],
lengthMenu: [25, 50, 100, 200],
pageLength: 50,
language: {
url: "/themes/vuexy/vendor/libs/datatables-sk/plugins/i18n/es-ES.json"
},
columns : [
{data : 'name',searchable:true,sortable:false},
{data : 'value',searchable:true,sortable:false},
{data : 'description',searchable:true,sortable:false},
{data : 'action',sortable:false,searchable:false,
render : (d,t) =>{
columns: [
{ data: 'name', searchable: true, sortable: false },
{ data: 'value', searchable: true, sortable: false },
{ data: 'description', searchable: true, sortable: false },
{
data: 'action', sortable: false, searchable: false,
render: (d, t) => {
return `
<div class="btn-group btn-group-sm">
<a href="javascript:void(0)" data-id="${d}" class="edit-variable"><i class="ti ti-pencil ti-sm mx-2"></i></a>
</div>
`
}
}
},
],
ajax: '/configuracion/variables/datatable'
});
}
events()
{
this.modalItem.on("click",".btn-update-variable",this.handleUpdateVariable.bind(this))
this.datatableItem.on("click",".edit-variable",(e)=> {
events() {
this.modalItem.on("click", ".btn-update-variable", this.handleUpdateVariable.bind(this))
this.datatableItem.on("click", ".edit-variable", (e) => {
e.preventDefault()
this.variableId = $(e.currentTarget).data("id")
this.handleGetVariable()
})
}
handleGetVariable()
{
handleGetVariable() {
const url = `/configuracion/variables/find/${this.variableId}`
let ajax = new Ajax(
url,null,null,
url, null, null,
this.handleGetVariableSuccess.bind(this),
this.handleGetVariableError.bind(this)
)
ajax.get()
}
handleGetVariableSuccess(data){
handleGetVariableSuccess(data) {
this.formEdit[0].reset()
this.modalEdit.toggle()
this.nameInput = this.formEdit
.find("#name")
this.nameInput = this.formEdit.find("#name")
this.nameInput.val(data.name)
this.valueInput = this.formEdit
.find("#value")
this.valueInput.val(data.value)
this.descriptionInput = this.formEdit
.find("#description")
this.renderValueField(data.name, data.value)
this.descriptionInput = this.formEdit.find("#description")
this.descriptionInput.val(data.description)
}
handleGetVariableError(err){}
handleUpdateVariable()
{
handleGetVariableError(err) { }
handleUpdateVariable() {
const url = `/configuracion/variables/edit/${this.variableId}`
const data = {
value : this.valueInput.val(),
description : this.descriptionInput.val(),
value: this.valueInput.val(),
description: this.descriptionInput.val(),
}
let ajax = new Ajax(
url,
@ -94,26 +85,49 @@ class ConfigVariableDatatable
)
ajax.post()
}
handleUpdateVariableSucess(data){
handleUpdateVariableSucess(data) {
this.modalEdit.toggle()
this.datatable.ajax.reload()
}
handleUpdateVariableError(err){}
handleUpdateVariableError(err) { }
handleDeleteVariable()
{
handleDeleteVariable() {
const url = `/configuracion/variables/delete/${this.variableId}`
let ajax = new Ajax(
url,null,null,
url, null, null,
this.handleDeleteVariableSucess.bind(this),
this.handleDeleteVariableError.bind(this)
)
ajax.post()
}
handleDeleteVariableSucess(data){
handleDeleteVariableSucess(data) {
this.datatable.reload()
}
handleDeleteVariableError(err){}
handleDeleteVariableError(err) { }
renderValueField(name, currentValue) {
const wrapper = this.formEdit.find("#value-wrapper");
let html = '';
if (name === 'cabezadas_disponibles') {
html = `<textarea id="value" rows="6" class="form-control">${currentValue}</textarea>`;
} else if (name === 'cabezada_default') {
const options = window.CABEZADAS_OPCIONES || {};
html = `<select id="value" class="form-select">`;
for (const [key, label] of Object.entries(options)) {
const selected = key === currentValue ? 'selected' : '';
html += `<option value="${key}" ${selected}>${label}</option>`;
}
html += `</select>`;
} else {
html = `<input type="text" id="value" class="form-control" value="${currentValue}">`;
}
wrapper.html(html);
this.valueInput = this.formEdit.find("#value"); // Actualiza referencia
}
}
export default ConfigVariableDatatable;

View File

@ -1,72 +1,84 @@
// Importación de utilidades AJAX y alertas personalizadas
import Ajax from '../ajax.js';
import { alertSuccessMessage } from '../alerts/sweetAlert.js'
import { alertFileUploadSuccess, alertWarningMessage } from '../alerts/sweetAlert.js'
// Template HTML para la vista previa de cada archivo en Dropzone
const PREVIEW_TEMPLATE = `
<div class="dz-preview dz-file-preview">
<div class="dz-details">
<div class="dz-thumbnail">
<!---<img data-dz-thumbnail>
<span class="dz-nopreview">No preview</span> --->
<!-- Miniatura de imagen o PDF -->
<div class="dz-success-mark"></div>
<div class="dz-error-mark"></div>
<div class="dz-error-message"><span data-dz-errormessage></span></div>
<div class="progress">
<div class="progress-bar progress-bar-primary" role="progressbar" aria-valuemin="0" aria-valuemax="100" data-dz-uploadprogress></div>
<div class="progress-bar progress-bar-primary" role="progressbar" aria-valuemin="0" aria-valuemax="100" data-dz-uploadprogress></div>
</div>
</div>
<div class="dz-filename" data-dz-name></div>
<!-- Estilo uniforme con Eliminar / Ver -->
<a class="dz-download dz-remove" href="javascript:void(0);" style="text-align:center;">Descargar</a>
<!-- Botón para descargar -->
<a class="dz-download dz-remove" href="javascript:void(0);" style="text-align:center;">Descargar</a>
<div class="dz-size" data-dz-size></div>
</div>
</div>
`;
// Clase principal que maneja el flujo de Dropzone + AJAX
class FileUploadDropzone {
constructor({ domElement, nameId = "presupuesto_id", getUri = null, postUri = null, resourcePath = "presupuestos", otId = null }) {
Dropzone.autoDiscover = false; // Desactiva la auto inicialización de Dropzone
constructor({ domElement, nameId = "presupuesto_id", getUri = null, postUri = null, resourcePath = "presupuestos" }) {
Dropzone.autoDiscover = false;
this.domElement = domElement
this.jqElement = $(domElement)
this.modelId = this.jqElement.data('id')
this.btnSelectFiles = $(`#${domElement.replace('#', '')}_btnUploadFiles`)
this.btnSubmitFile = $(`#${domElement.replace('#', '')}_btnSubmitFiles`)
this.domElement = domElement;
this.jqElement = $(domElement); // Referencia jQuery al elemento
this.modelId = this.jqElement.data('id'); // ID que asocia los archivos a un modelo (presupuesto, pedido, etc.)
// Botones asociados
this.btnSelectFiles = $(`#${domElement.replace('#', '')}_btnUploadFiles`);
this.btnSubmitFile = $(`#${domElement.replace('#', '')}_btnSubmitFiles`);
this.btnDownloadFiles = $(`#${domElement.replace('#', '')}_btnDownloadFiles`);
this.dataPost = {}
this.nameId = nameId;
this.getUri = getUri
this.postUri = postUri
this.dataPost[nameId] = this.modelId;
this.resourcePath = resourcePath
this.nameId = nameId;
this.otId = otId;
this.getUri = getUri;
this.postUri = postUri;
this.resourcePath = resourcePath;
this.dataPost = {};
this.dataPost[nameId] = this.modelId;
}
// Inicializa Dropzone y los eventos externos
init() {
if (this.jqElement.length > 0) {
this.btnSubmitFile.on('click', this._handleUploadFiles.bind(this))
this.btnSelectFiles.on('click', () => {
this.jqElement.trigger('click')
})
this.btnDownloadFiles.on('click', this._handleDownloadFiles.bind(this))
// Vincula botones externos
this.btnSubmitFile.on('click', this._handleUploadFiles.bind(this));
this.btnSelectFiles.on('click', () => this.jqElement.trigger('click'));
this.btnDownloadFiles.on('click', this._handleDownloadFiles.bind(this));
// Inicializa Dropzone
this.dropzone = new Dropzone(this.domElement, {
url: this.postUri,
addRemoveLinks: true,
previewTemplate: PREVIEW_TEMPLATE,
paramName: "file",
uploadMultiple: true,
parallelUploads: 4, // Ajusta este número al máximo número de archivos que esperas subir a la vez
maxFiles: 5, // Ajusta este número al máximo número de archivos que esperas subir a la vez
parallelUploads: 4,
maxFiles: 5,
autoProcessQueue: true,
dictRemoveFile: "Eliminar",
acceptedFiles: 'image/*, application/pdf',
maxFilesize: 5e+7, // Bytes
init: this._handleGetFiles.bind(this)
maxFilesize: 5e+7, // 50 MB
init: this._handleGetFiles.bind(this) // Carga inicial de archivos
});
// Cuando se añade un archivo (manual o programático)
this.dropzone.on("addedfile", this._handleAddedFile.bind(this));
}
}
// Botones "Ver" y "Descargar" para cada archivo
_handleAddedFile(file) {
if (file.hash) {
// Botón Ver
@ -89,78 +101,126 @@ class FileUploadDropzone {
}
}
// Acción del botón "Ver"
onViewButton(file) {
console.log(window.location.protocol + "//" + window.location.host + "/sistema/intranet/" + this.resourcePath + "/" + file.hash)
window.open(window.location.protocol + "//" + window.location.host + "/sistema/intranet/" + this.resourcePath + "/" + file.hash, '_blank');
const url = `${window.location.protocol}//${window.location.host}/sistema/intranet/${this.resourcePath}/${file.hash}`;
window.open(url, '_blank');
}
// Prepara el objeto FormData para el envío
_getDropzoneFilesFormData() {
var files = this.dropzone.files;
const files = this.dropzone.files;
const formData = new FormData();
const oldFiles = [];
var formData = new FormData();
var oldFiles = [];
var counter = 0;
for (var i = 0; i < files.length; i++) {
if (files[i].upload) {
var file = files[i];
for (let file of files) {
if (file.upload) {
formData.append('file[]', file);
counter += 1;
}
else {
oldFiles.push(files[i].name);
} else {
oldFiles.push(file.name);
}
}
formData.append('oldFiles', JSON.stringify(oldFiles));
formData.append('oldFiles', JSON.stringify(oldFiles));
formData.append(this.nameId, this.modelId);
return formData;
}
// Acción al hacer clic en "Subir archivos"
_handleUploadFiles() {
$("#loader").modal('show')
let ajax = new Ajax(this.postUri,
$("#loader").modal('show');
const ajax = new Ajax(
this.postUri,
this._getDropzoneFilesFormData(),
null,
this._handleUploadFilesSuccess.bind(this),
null)
null
);
ajax.ajaxForm("POST");
}
// Éxito tras subir archivos
_handleUploadFilesSuccess(response) {
this.dropZoneClean()
this._handleGetFiles()
alertSuccessMessage(response?.message ?? "Archivos subidos correctamente");
}
_handleUploadFilesError(errors) { }
this.dropZoneClean();
this._handleGetFiles();
const summary = response?.summary || {};
const numOk = summary.subidos_ok || 0;
const numErrLocal = summary.errores_locales || 0;
const numErrRemote = summary.errores_remotos || 0;
const numDeleted = summary.borrados || 0;
const partes = [];
if (numOk > 0) {
partes.push(`Se subió${numOk === 1 ? '' : 'ron'} ${numOk} archivo${numOk === 1 ? '' : 's'} correctamente.`);
}
if (numDeleted > 0) {
partes.push(`Se eliminaron ${numDeleted} archivo${numDeleted === 1 ? '' : 's'} obsoleto${numDeleted === 1 ? '' : 's'}.`);
}
if (numErrLocal > 0) {
partes.push(`${numErrLocal} archivo${numErrLocal === 1 ? '' : 's'} falló${numErrLocal === 1 ? '' : 'n'} en el sistema.`);
}
if (numErrRemote > 0) {
partes.push(`${numErrRemote} fallo${numErrRemote === 1 ? '' : 's'} en la transferencia.`);
}
const mensaje = partes.length > 0
? partes.join(' ')
: response?.message ?? "Archivos actualizados correctamente.";
alertFileUploadSuccess(mensaje);
}
_handleUploadFilesError(errors) {
// No implementado aún
}
// Carga inicial de archivos existentes desde el servidor
_handleGetFiles() {
const ajax = new Ajax(
this.getUri,
this.dataPost,
null,
this._handelGetFilesSuccess.bind(this),
null,
)
ajax.post()
null
);
ajax.post();
}
// Manejo de respuesta del servidor al cargar archivos
_handelGetFilesSuccess(response) {
try {
$("#loader").modal('hide')
const files = JSON.parse(response)
this.dropZoneUpdateFiles(files)
$("#loader").modal('hide');
const files = Array.isArray(response)
? response
: typeof response === 'string'
? JSON.parse(response)
: [];
this.dropZoneUpdateFiles(files);
} catch (error) {
$("#loader").modal('hide')
console.error("Error parseando respuesta:", error);
$("#loader").modal('hide');
}
}
// Manejo del botón "Descargar archivos ZIP"
_handleDownloadFiles() {
$("#loader").modal('show');
$.ajax({
url: `/presupuestoadmin/download_zip`,
url: `/files/download_zip`,
type: 'POST',
data: {
[this.nameId]: this.modelId
[this.nameId]: this.modelId,
'ot_id': this.otId
},
xhrFields: {
responseType: 'blob'
@ -170,7 +230,7 @@ class FileUploadDropzone {
let filename = "archivos.zip";
if (disposition && disposition.indexOf('attachment') !== -1) {
const match = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/.exec(disposition);
if (match != null && match[1]) {
if (match && match[1]) {
filename = match[1].replace(/['"]/g, '');
}
}
@ -185,7 +245,7 @@ class FileUploadDropzone {
window.URL.revokeObjectURL(url);
},
error: () => {
alertWarningMessage("Error al descargar el archivo ZIP.");
alertWarningMessage("Error", "Error al descargar el archivo ZIP.");
},
complete: () => {
$("#loader").modal('hide');
@ -193,28 +253,57 @@ class FileUploadDropzone {
});
}
// Carga archivos simulados (mock) al Dropzone visual
dropZoneUpdateFiles(files) {
files.forEach(file => {
this.dropZoneAddFile(file)
//console.log("Iterando archivo:", file.name);
this.dropZoneAddFile(file);
});
}
// Limpia todos los archivos de Dropzone visualmente
dropZoneClean() {
this.dropzone.files.forEach(file => {
this.dropzone.removeFile(file);
})
});
}
dropZoneAddFile(mockFile) {
this.dropzone.files.push(mockFile); // add to files array
this.dropzone.emit("addedfile", mockFile);
this.dropzone.emit("thumbnail", mockFile, window.location.host + "/sistema/intranet/" + this.resourcePath + "/" + mockFile.hash);
this.dropzone.emit("complete", mockFile);
this.dropzone.options.success.call(this.dropzone, mockFile);
// Inserta un archivo en Dropzone manualmente (mock)
dropZoneAddFile(mockFileData) {
const extension = mockFileData.name.split('.').pop().toLowerCase();
const isImage = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp'].includes(extension);
const isPDF = extension === 'pdf';
const fileUrl = `${window.location.protocol}//${window.location.host}/sistema/intranet/${this.resourcePath}/${mockFileData.hash}`;
const mockFile = {
name: mockFileData.name,
size: mockFileData.size,
type: isImage ? `image/${extension === 'jpg' ? 'jpeg' : extension}` : 'application/pdf',
hash: mockFileData.hash,
upload: false // Impide que se vuelva a subir
};
this.dropzone.emit("addedfile", mockFile);
// Espera a que Dropzone genere el DOM para modificar la miniatura
setTimeout(() => {
if (isImage) {
this.dropzone.emit("thumbnail", mockFile, fileUrl);
} else if (isPDF) {
const preview = mockFile.previewElement?.querySelector('.dz-thumbnail');
if (preview) {
preview.innerHTML = `<img src="/assets/img/pdf.png" alt="PDF" style="width:100%; height:auto;" />`;
}
}
this.dropzone.emit("complete", mockFile);
}, 10);
this.dropzone.files.push(mockFile);
}
}
export default FileUploadDropzone;
// Exporta la clase para usarla en otros módulos JS
export default FileUploadDropzone;

View File

@ -2,4 +2,4 @@ import ConfigVariableDatatable from "../../components/configVariableDatatable.js
const item = new ConfigVariableDatatable($("#tableConfigVariables"))
item.init()
item.events()
item.events()

View File

@ -65,8 +65,8 @@ class PresupuestoAdminEdit {
this.configUploadDropzone = {
domElement: '#dropzone-presupuesto-admin-files',
nameId: "presupuesto_id",
getUri: '/presupuestos/presupuestocliente/get_files',
postUri: '/presupuestos/presupuestocliente/upload_files'
getUri: '/files/get_files',
postUri: '/files/upload_files'
}
if ($(this.configUploadDropzone.domElement).length > 0) {
this.fileUploadDropzone = new FileUploadDropzone(this.configUploadDropzone)
@ -234,6 +234,7 @@ class PresupuestoAdminEdit {
titulo: this.datosGenerales.titulo.val(),
autor: this.datosGenerales.autor.val(),
isbn: this.datosGenerales.isbn.val(),
iskn: this.datosGenerales.iskn.val(),
pais_id: this.datosGenerales.pais.getVal(),
coleccion: this.datosGenerales.coleccion.val(),
numero_edicion: this.datosGenerales.numeroEdicion.val(),
@ -325,6 +326,12 @@ class PresupuestoAdminEdit {
datos.tirada_alternativa_json_data = this.tiradasAlternativas.generate_json_tiradas();
datos.direcciones_fp_checks = JSON.stringify({
"addFP1isAddMain": $('#sameAddPrincipalFP1').prop('checked')? "1":"0",
"addFP2isAddMain": $('#sameAddPrincipalFP2').prop('checked')? "1":"0",
"addFP2isaddFP1": $('#sameAddFP1').prop('checked')? "1":"0",
});
return datos;
}
@ -404,7 +411,9 @@ class PresupuestoAdminEdit {
const totalAceptadoRevisado = response.data.total_aceptado_revisado != null ?
response.data.total_aceptado_revisado : response.data.resumen.total_aceptado;
AutoNumeric.getAutoNumericElement($('#total_aceptado_revisado')[0]).set(totalAceptadoRevisado);
if((!isNaN(totalAceptadoRevisado) && totalAceptadoRevisado !== null) || totalAceptadoRevisado === 0) {
AutoNumeric.getAutoNumericElement($('#total_aceptado_revisado')[0]).set(totalAceptadoRevisado);
}
$('#aprobado_by_at').html(response.data.aprobado_by_at);
@ -421,7 +430,7 @@ class PresupuestoAdminEdit {
self.lineasPresupuesto.cargarDatos(response.data.lineasPresupuesto);
self.servicios.cargar(response.data.servicios);
self.envios.cargar(response.data.direcciones);
self.envios.cargar(response.data.direcciones, response.data.direccionesFP);
self.comparador.cargarDatos(response.data.comparador);

View File

@ -15,6 +15,7 @@ class DatosGenerales{
this.coleccion = this.domItem.find('#coleccion');
this.numeroEdicion = this.domItem.find('#numeroEdicion');
this.isbn = this.domItem.find('#isbn');
this.iskn = this.domItem.find('#iskn');
this.cliente = new ClassSelect($('#clienteId'), '/clientes/cliente/getSelect2', 'Seleccione cliente');
@ -46,6 +47,7 @@ class DatosGenerales{
this.coleccion.val(datos.coleccion);
this.numeroEdicion.val(datos.numero_edicion);
this.isbn.val(datos.isbn);
this.iskn.val(datos.iskn);
this.cliente.setOption(datos.cliente.id, datos.cliente.nombre);

View File

@ -1,5 +1,5 @@
import ClassSelect from '../../../components/select2.js';
import { getToken } from '../../../common/common.js';
import ClassSelect from '../../../components/select2.js';
class DatosLibro {
@ -63,7 +63,9 @@ class DatosLibro {
this.retractilado = this.domItem.find('#retractilado');
this.retractilado5 = this.domItem.find('#retractilado5');
this.prototipo = this.domItem.find('#prototipo');
this.prototipo_2 = this.domItem.find('#prototipo_2');
this.ferro = this.domItem.find('#ferro');
this.ferro_2 = this.domItem.find('#ferro_2');
this.ferroDigital = this.domItem.find('#ferroDigital');
this.marcapaginas = this.domItem.find('#marcapaginas');
@ -157,7 +159,9 @@ class DatosLibro {
this.retractilado.on('change', this.checkRetractilado.bind(this));
this.retractilado5.on('change', this.checkRetractilado.bind(this));
this.ferro.on('change', this.changeFerro.bind(this));
this.ferro_2.on('change', this.changeFerro2.bind(this));
this.prototipo.on('change', this.changePrototipo.bind(this));
this.prototipo_2.on('change', this.changePrototipo2.bind(this));
this.ferroDigital.on('change', this.changeFerroDigital.bind(this));
this.tamanio.item.on('select2:select', this.changeFormato.bind(this));
@ -190,7 +194,7 @@ class DatosLibro {
changeFaja() {
if (this._bloqueoCambioFaja) return;
this._bloqueoCambioFaja = true;
this._bloqueoCambioFaja = true;
if (this.faja.prop('checked')) {
this.div_faja.removeClass('d-none');
@ -246,6 +250,20 @@ class DatosLibro {
if (this.ferro.prop('checked')) {
$(document).trigger('add-servicio-lineas', 'ferro');
this.ferro_2.prop('checked', false);
$(document).trigger('remove-servicio-lineas', 'ferro_2');
this.prototipo.prop('checked', false);
$(document).trigger('remove-servicio-lineas', 'prototipo_2');
this.prototipo_2.prop('checked', false);
$(document).trigger('remove-servicio-lineas', 'prototipo');
$('.datos-envio-fp-1').removeClass('d-none');
$('.datos-envio-fp-2').addClass('d-none');
$('.check-direccion-fp').prop('checked', false);
$('.check-direccion-fp-2').prop('checked', false);
const table_2 = $('#tableOfDireccionesEnvioFP2').DataTable();
table_2.clear().draw();
const table = $('#tableOfDireccionesEnvioFP1').DataTable();
table.columns.adjust().draw();
$(document).trigger('update-presupuesto', {
update_lineas: false,
update_servicios: false,
@ -256,25 +274,63 @@ class DatosLibro {
}
else {
$(document).trigger('remove-servicio-lineas', 'ferro');
if (!this.prototipo.prop('checked')) {
const table = $('#tableOfDireccionesEnvio').DataTable();
const rows = table.rows().data();
for (let i = 0; i < rows.length; i++) {
const rowData = rows[i];
if (rowData.is_ferro_prototipo == 1) {
table.rows(i).remove();
table.draw();
break;
}
}
$(document).trigger('update-presupuesto', {
update_lineas: false,
update_servicios: false,
update_envios: true,
update_resumen: true,
update_tiradas_alternativas: true
});
}
const table = $('#tableOfDireccionesEnvioFP1').DataTable();
table.clear().draw();
$('.datos-envio-fp-1').addClass('d-none');
$(document).trigger('update-presupuesto', {
update_lineas: false,
update_servicios: false,
update_envios: true,
update_resumen: true,
update_tiradas_alternativas: true
});
}
}
changeFerro2() {
if (this.cargando)
return;
if (this.ferro_2.prop('checked')) {
$(document).trigger('add-servicio-lineas', 'ferro_2');
this.ferro.prop('checked', false);
$(document).trigger('remove-servicio-lineas', 'ferro');
this.prototipo.prop('checked', false);
$(document).trigger('remove-servicio-lineas', 'prototipo_2');
this.prototipo_2.prop('checked', false);
$(document).trigger('remove-servicio-lineas', 'prototipo');
$('.datos-envio-fp-1').removeClass('d-none');
$('.datos-envio-fp-2').removeClass('d-none');
$('.check-direccion-fp').prop('checked', false);
$('.check-direccion-fp-2').prop('checked', false);
const table = $('#tableOfDireccionesEnvioFP1').DataTable();
table.columns.adjust().draw();
const table_2 = $('#tableOfDireccionesEnvioFP2').DataTable();
table_2.columns.adjust().draw();
$(document).trigger('update-presupuesto', {
update_lineas: false,
update_servicios: false,
update_envios: true,
update_resumen: false,
update_tiradas_alternativas: false
});
}
else {
$(document).trigger('remove-servicio-lineas', 'ferro_2');
const table = $('#tableOfDireccionesEnvioFP1').DataTable();
table.clear().draw();
const table_2 = $('#tableOfDireccionesEnvioFP2').DataTable();
table_2.clear().draw();
$('.datos-envio-fp-1').addClass('d-none');
$('.datos-envio-fp-2').addClass('d-none');
$(document).trigger('update-presupuesto', {
update_lineas: false,
update_servicios: false,
update_envios: true,
update_resumen: true,
update_tiradas_alternativas: true
});
}
}
@ -298,6 +354,21 @@ class DatosLibro {
if (this.prototipo.prop('checked')) {
$(document).trigger('add-servicio-lineas', 'prototipo');
this.ferro.prop('checked', false);
$(document).trigger('remove-servicio-lineas', 'ferro');
this.ferro_2.prop('checked', false);
$(document).trigger('remove-servicio-lineas', 'ferro_2');
this.prototipo_2.prop('checked', false);
$(document).trigger('remove-servicio-lineas', 'prototipo_2');
$('.datos-envio-fp-1').removeClass('d-none');
$('.datos-envio-fp-2').addClass('d-none');
$('.check-direccion-fp').prop('checked', false);
$('.check-direccion-fp-2').prop('checked', false);
const table = $('#tableOfDireccionesEnvioFP1').DataTable();
table.columns.adjust().draw();
const table_2 = $('#tableOfDireccionesEnvioFP2').DataTable();
table_2.clear().draw();
table_2.columns.adjust().draw();
$(document).trigger('update-presupuesto', {
update_lineas: false,
update_servicios: false,
@ -308,28 +379,64 @@ class DatosLibro {
}
else {
$(document).trigger('remove-servicio-lineas', 'prototipo');
if (!this.ferro.prop('checked')) {
const table = $('#tableOfDireccionesEnvio').DataTable();
const rows = table.rows().data();
for (let i = 0; i < rows.length; i++) {
const rowData = rows[i];
if (rowData.is_ferro_prototipo == 1) {
table.rows(i).remove();
table.draw();
break;
}
}
$(document).trigger('update-presupuesto', {
update_lineas: false,
update_servicios: false,
update_envios: true,
update_resumen: true,
update_tiradas_alternativas: true
});
}
const table = $('#tableOfDireccionesEnvioFP1').DataTable();
table.clear().draw();
$('.datos-envio-fp-1').addClass('d-none');
$(document).trigger('update-presupuesto', {
update_lineas: false,
update_servicios: false,
update_envios: true,
update_resumen: true,
update_tiradas_alternativas: true
});
}
}
changePrototipo2() {
if (this.cargando)
return;
if (this.prototipo_2.prop('checked')) {
$(document).trigger('add-servicio-lineas', 'prototipo_2');
this.ferro.prop('checked', false);
$(document).trigger('remove-servicio-lineas', 'ferro');
this.ferro_2.prop('checked', false);
$(document).trigger('remove-servicio-lineas', 'ferro_2');
this.prototipo.prop('checked', false);
$(document).trigger('remove-servicio-lineas', 'prototipo');
$('.datos-envio-fp-1').removeClass('d-none');
$('.datos-envio-fp-2').removeClass('d-none');
const table = $('#tableOfDireccionesEnvioFP1').DataTable();
table.columns.adjust().draw();
const table_2 = $('#tableOfDireccionesEnvioFP2').DataTable();
table_2.columns.adjust().draw();
$('.check-direccion-fp-2').prop('checked', false);
$(document).trigger('update-presupuesto', {
update_lineas: false,
update_servicios: false,
update_envios: true,
update_resumen: false,
update_tiradas_alternativas: false
});
}
else {
$(document).trigger('remove-servicio-lineas', 'prototipo_2');
const table = $('#tableOfDireccionesEnvioFP1').DataTable();
table.clear().draw();
const table_2 = $('#tableOfDireccionesEnvioFP2').DataTable();
table_2.clear().draw();
$('.datos-envio-fp-1').addClass('d-none');
$('.datos-envio-fp-2').addClass('d-none');
$(document).trigger('update-presupuesto', {
update_lineas: false,
update_servicios: false,
update_envios: true,
update_resumen: true,
update_tiradas_alternativas: true
});
}
}
checkRetractilado(event) {
@ -587,6 +694,8 @@ class DatosLibro {
this.actualizarLimitesPaginas();
}
this.calcularSolapas();
}
updateComparador() {
@ -763,7 +872,9 @@ class DatosLibro {
this.retractilado.prop('checked', datos.retractilado);
this.retractilado5.prop('checked', datos.retractilado5);
this.prototipo.prop('checked', datos.prototipo);
this.prototipo_2.prop('checked', datos.prototipo2);
this.ferro.prop('checked', datos.ferro);
this.ferro_2.prop('checked', datos.ferro2);
this.ferroDigital.prop('checked', datos.ferroDigital);
this.marcapaginas.prop('checked', datos.marcapaginas);
}

View File

@ -14,11 +14,15 @@ class Envios {
this.recogerTaller = $('#recoger_en_taller');
this.table = null;
this.tableFP1 = null;
this.tableFP2 = null;
this.direccionesClienteForm = new ClassSelect($('#add_clientedAdd'), '/misdirecciones/getSelect2', 'Seleccione una direccion', false, {});
this.paisesClienteForm = new ClassSelect($('#add_pais_id'), '/configuracion/paises/menuitems2', 'Seleccione país', false, {});
this.modalYesNo = null;
this.insertarEnvio = $('#insertar_direccion');
this.insertarEnvioFP1 = $('#insertar_direccion_fp1');
this.insertarEnvioFP2 = $('#insertar_direccion_fp2');
this.actionBtns_direcciones = function (data) {
return `
@ -71,7 +75,6 @@ class Envios {
},
{ 'data': 'margen', render: function (data, type, row) { return Math.round(data) } },
{ 'data': 'entregaPieCalle' },
{ 'data': 'is_ferro_prototipo' },
{
data: function (row, type, set, meta) {
return `
@ -79,7 +82,7 @@ class Envios {
<a href="javascript:void(0);"><i class="ti ti-trash ti-sm tiradas-alternativas btn-delete-envio mx-2"></i></a>
`;
},
className: 'row-edit dt-center'
className: 'row-edit'
}
],
columnDefs: [
@ -87,10 +90,12 @@ class Envios {
{
orderable: false,
searchable: false,
// all columns
targets: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14],
//targets: [$('#tableOfDireccionesEnvio').find("tr:first th").length - 1]
},
{
targets: '_all', // Targets all columns
className: 'dt-center' // Adds the 'dt-center' class
}
],
language: {
url: "/themes/vuexy/vendor/libs/datatables-sk/plugins/i18n/es-ES.json"
@ -98,7 +103,7 @@ class Envios {
drawCallback: function (settings) {
const boolCols = [15, 16];
const boolCols = [15];
for (let coln of boolCols) {
self.table.column(coln, { page: 'current' }).nodes().each(function (cell, i) {
cell.innerHTML = cell.innerHTML == '1' ? '<i class="ti ti-check"></i>' : '';
@ -115,20 +120,188 @@ class Envios {
$("#costeEnvios").text(total.toFixed(2) + "€" || "0€");
self.check_unidades_enviadas(null, self.recogerTaller.prop('checked'));
this.api().columns.adjust();
}
});
this.tableFP1 = $('#tableOfDireccionesEnvioFP1').DataTable({
draw: 5,
serverSide: false,
processing: true,
autoWidth: true,
responsive: true,
pageLength: 20,
lengthChange: false,
searching: false,
paging: false,
info: false,
scrollX: true,
ordering: false,
columns: [
{ 'data': 'tarifa_id' },
{ 'data': 'cantidad' },
{ 'data': 'peso' },
{ 'data': 'att' },
{ 'data': 'email' },
{ 'data': 'direccion' },
{ 'data': 'cp' },
{ 'data': 'municipio' },
{ 'data': 'pais' },
{ 'data': 'pais_id', visible: false },
{ 'data': 'telefono' },
{ 'data': 'proveedor' },
{ 'data': 'proveedor_id', visible: false },
{
'data': 'precio', render: function (data, type, row) {
let coste = parseFloat(data).toFixed(2);
let precio = parseFloat(data * (1 + row.margen / 100.0)).toFixed(2);
return coste + "/" + precio;
}
},
{ 'data': 'margen', render: function (data, type, row) { return Math.round(data) } },
{ 'data': 'entregaPieCalle' },
{
data: function (row, type, set, meta) {
return `
<a href="javascript:void(0);"><i class="ti ti-trash ti-sm tiradas-alternativas btn-delete-envio mx-2"></i></a>
`;
},
className: 'row-edit'
}
],
columnDefs: [
{
orderable: false,
searchable: false,
targets: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14],
},
{
targets: '_all', // Targets all columns
className: 'dt-center' // Adds the 'dt-center' class
}
],
language: {
url: "/themes/vuexy/vendor/libs/datatables-sk/plugins/i18n/es-ES.json"
},
drawCallback: function (settings) {
const boolCols = [15];
for (let coln of boolCols) {
self.tableFP1.column(coln, { page: 'current' }).nodes().each(function (cell, i) {
cell.innerHTML = cell.innerHTML == '1' ? '<i class="ti ti-check"></i>' : '';
});
}
this.api().columns.adjust();
if (self.tableFP1.rows().count() > 0) {
$('#rowInsertarEnvioFP1').addClass('d-none');
} else {
$('#rowInsertarEnvioFP1').removeClass('d-none');
}
}
});
this.tableFP2 = $('#tableOfDireccionesEnvioFP2').DataTable({
draw: 5,
serverSide: false,
processing: true,
autoWidth: true,
responsive: true,
pageLength: 20,
lengthChange: false,
searching: false,
paging: false,
info: false,
scrollX: true,
ordering: false,
columns: [
{ 'data': 'tarifa_id' },
{ 'data': 'cantidad' },
{ 'data': 'peso' },
{ 'data': 'att' },
{ 'data': 'email' },
{ 'data': 'direccion' },
{ 'data': 'cp' },
{ 'data': 'municipio' },
{ 'data': 'pais' },
{ 'data': 'pais_id', visible: false },
{ 'data': 'telefono' },
{ 'data': 'proveedor' },
{ 'data': 'proveedor_id', visible: false },
{
'data': 'precio', render: function (data, type, row) {
let coste = parseFloat(data).toFixed(2);
let precio = parseFloat(data * (1 + row.margen / 100.0)).toFixed(2);
return coste + "/" + precio;
}
},
{ 'data': 'margen', render: function (data, type, row) { return Math.round(data) } },
{ 'data': 'entregaPieCalle' },
{
data: function (row, type, set, meta) {
return `
<a href="javascript:void(0);"><i class="ti ti-trash ti-sm tiradas-alternativas btn-delete-envio mx-2"></i></a>
`;
},
className: 'row-edit dt-center'
}
],
columnDefs: [
{
orderable: false,
searchable: false,
targets: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14],
},
{
targets: '_all', // Targets all columns
className: 'dt-center' // Adds the 'dt-center' class
}
],
language: {
url: "/themes/vuexy/vendor/libs/datatables-sk/plugins/i18n/es-ES.json"
},
drawCallback: function (settings) {
const boolCols = [15];
for (let coln of boolCols) {
self.tableFP2.column(coln, { page: 'current' }).nodes().each(function (cell, i) {
cell.innerHTML = cell.innerHTML == '1' ? '<i class="ti ti-check"></i>' : '';
});
}
this.api().columns.adjust();
if (self.tableFP2.rows().count() > 0) {
$('#rowInsertarEnvioFP2').addClass('d-none');
} else {
$('#rowInsertarEnvioFP2').removeClass('d-none');
}
}
});
$(document).on('click', '.btn-delete-envio', function () {
const rowId = $(this).closest('td').parent()[0].sectionRowIndex;
self.table.row(rowId).remove().draw();
$(document).trigger('update-presupuesto', {
update_lineas: false,
update_servicios: false,
update_envios: false,
update_resumen: true,
update_tiradas_alternativas: true
});
const table = $(this).closest('table').DataTable();
table.row(rowId).remove().draw();
if (table.table().node().id == 'tableOfDireccionesEnvios') {
$(document).trigger('update-presupuesto', {
update_lineas: false,
update_servicios: false,
update_envios: false,
update_resumen: true,
update_tiradas_alternativas: true
});
}
else if (table.table().node().id == 'tableOfDireccionesEnvioFP1') {
$('#rowInsertarEnvioFP1').removeClass('d-none');
}
else if (table.table().node().id == 'tableOfDireccionesEnvioFP2') {
$('#rowInsertarEnvioFP2').removeClass('d-none');
}
});
$(document).on('click', '.btn-edit-envio', function () {
@ -165,19 +338,7 @@ class Envios {
$('#add_telefono').val(data.telefono)
$('#add_cantidad').val(data.cantidad)
$('#add_entregaPieCalle').prop('checked', data.entregaPieCalle == 1 ? true : false)
$('#dirFerroProto').prop('checked', data.is_ferro_prototipo == 1 ? true : false)
if (data.is_ferro_prototipo == 1) {
$('#add_cantidad').val(1);
$('#add_cantidad').attr('disabled', true);
$('#dirFerroProto').prop('disabled', true);
$('#direccionFerroProto').removeClass('d-none');
}
else {
$('#add_cantidad').attr('disabled', false);
$('#dirFerroProto').prop('disabled', false);
$('#direccionFerroProto').addClass('d-none');
}
self.direccionesClienteForm.setParams({ 'cliente_id': () => $("#clienteId").select2('data')[0].id });
self.direccionesClienteForm.init();
@ -215,6 +376,8 @@ class Envios {
this.insertarEnvio.on('click', this.addEnvio.bind(this));
this.insertarEnvioFP1.on('click', this.addEnvio.bind(this, 'fp1'));
this.insertarEnvioFP2.on('click', this.addEnvio.bind(this, 'fp2'));
this.initFormularioDireccionEnvio();
@ -225,12 +388,17 @@ class Envios {
$(document).trigger('update-envios-completed');
});
$(document).on('ckeck-lineas-envios', this.check_unidades_enviadas.bind(this));
$('#sameAddPrincipalFP1').on('change', this.sameAddPrincipalFP1.bind(this));
$('#sameAddPrincipalFP2').on('change', this.sameAddPrincipalFP2.bind(this));
$('#sameAddFP1').on('change', this.sameAddFP1.bind(this));
}
addEnvio() {
addEnvio(table = '') {
$("#addressForm").attr('action', 'create');
let newAddDialog = $("#addressForm");
this.direccionesClienteForm.setParams({ 'cliente_id': () => $("#clienteId").select2('data')[0].id });
this.direccionesClienteForm.init();
@ -243,34 +411,27 @@ class Envios {
})
let cantidad_total = 0;
let hasFerroPrototipo = false;
$('#tableOfDireccionesEnvio').DataTable().rows().every(function (rowIdx, tableLoop, rowLoop) {
let data = this.data();
if (data.is_ferro_prototipo == 0)
cantidad_total += parseInt(data.cantidad);
else
hasFerroPrototipo = true;
cantidad_total += parseInt(data.cantidad);
});
const restante = parseInt($('#tirada').val()) - cantidad_total;
$('#add_cantidad').attr('max-value', restante);
$('#add_cantidad').val(restante > 0 ? restante : 0);
if (hasFerroPrototipo) {
$('#dirFerroProto').prop('checked', false);
$('#direccionFerroProto').addClass('d-none');
$('#add_cantidad').attr('disabled', false);
if (table != '') {
$("#addressForm").attr('data-table', table);
$('#add_entregaPieCalle').prop('disabled', true);
$('#add_cantidad').val(1);
$('#add_cantidad').prop('disabled', true);
}
else {
if (restante == 0) {
$('#direccionFerroProto').removeClass('d-none');
$('#dirFerroProto').prop('checked', true);
$('#dirFerroProto').prop('disabled', true);
$('#add_cantidad').attr('disabled', true);
$('#add_cantidad').val(1);
}
$("#addressForm").attr('data-table', '');
$('#add_entregaPieCalle').prop('disabled', false);
$('#add_cantidad').prop('disabled', false);
}
newAddDialog.modal('show');
}
@ -316,18 +477,66 @@ class Envios {
proveedor: data.proveedor,
proveedor_id: data.proveedor_id,
entregaPieCalle: data.entregaPieCalle,
is_ferro_prototipo: data.is_ferro_prototipo,
})
});
})
await $('#tableOfDireccionesEnvioFP1').DataTable().rows().every(async function (rowIdx, tableLoop, rowLoop) {
var data = this.data();
await $.post('/presupuestos/presupuestodirecciones/add',
{
presupuesto_id: id,
tarifa_id: data.tarifa_id,
cantidad: data.cantidad,
peso: data.peso,
att: data.att,
email: data.email,
direccion: data.direccion,
pais_id: data.pais_id,
provincia: data.provincia,
municipio: data.municipio,
cp: data.cp,
telefono: data.telefono,
precio: data.precio,
margen: data.margen,
proveedor: data.proveedor,
proveedor_id: data.proveedor_id,
entregaPieCalle: data.entregaPieCalle,
is_ferro_prototipo: 1,
num_ferro_prototipo: 1
})
});
await $('#tableOfDireccionesEnvioFP2').DataTable().rows().every(async function (rowIdx, tableLoop, rowLoop) {
var data = this.data();
await $.post('/presupuestos/presupuestodirecciones/add',
{
presupuesto_id: id,
tarifa_id: data.tarifa_id,
cantidad: data.cantidad,
peso: data.peso,
att: data.att,
email: data.email,
direccion: data.direccion,
pais_id: data.pais_id,
provincia: data.provincia,
municipio: data.municipio,
cp: data.cp,
telefono: data.telefono,
precio: data.precio,
margen: data.margen,
proveedor: data.proveedor,
proveedor_id: data.proveedor_id,
entregaPieCalle: data.entregaPieCalle,
is_ferro_prototipo: 1,
num_ferro_prototipo: 2
})
});
});
}
async updateTiradaBase() {
if($('#noEnvioBase').val() == 1)
if ($('#noEnvioBase').val() == 1)
return;
const self = this;
@ -421,13 +630,12 @@ class Envios {
'precio': datos_tarifa.precio.toFixed(2),
'margen': datos_tarifa.margen,
'entregaPieCalle': rowData.entregaPieCalle,
'is_ferro_prototipo': rowData.is_ferro_prototipo,
'actionBtns_direcciones': self.actionBtns_direcciones,
})
.draw();
self.check_unidades_enviadas(null,null);
self.check_unidades_enviadas(null, null);
$(document).trigger('update-presupuesto', {
update_lineas: false,
@ -528,6 +736,7 @@ class Envios {
$('#add_telefono').val("");
$('#add_saveDirection').prop('checked', false)
$('#add_entregaPieCalle').prop('checked', false)
$('#addressForm').attr('data-table', '');
});
$('#cancelAdd').on('click', function () {
@ -591,34 +800,86 @@ class Envios {
tarifa_final.cantidad = parseInt($('#add_cantidad').val())
tarifa_final.peso = peso_envio
self.table.row
.add({
'tarifa_id': tarifa_final.id,
'cantidad': tarifa_final.cantidad,
'peso': tarifa_final.peso.toFixed(3),
'att': $('#add_att').val(),
'email': $('#add_email').val(),
'direccion': $('#add_direccion').val(),
'cp': $('#add_cp').val(),
'municipio': $('#add_municipio').val(),
'provincia': $('#add_provincia').val(),
'pais_id': $('#add_pais_id').select2('data')[0].id,
'pais': $('#add_pais_id').select2('data')[0].text,
'telefono': $('#add_telefono').val(),
'proveedor': tarifa_final.proveedor,
'proveedor_id': tarifa_final.proveedor_id,
'precio': tarifa_final.precio,
'margen': tarifa_final.margen,
'entregaPieCalle': $('#add_entregaPieCalle').is(":checked") ? 1 : 0,
'is_ferro_prototipo': $('#dirFerroProto').is(":checked") ? 1 : 0,
'actionBtns_direcciones': `
const sourceTable = $('#addressForm').attr('data-table');
if (sourceTable === '') {
self.table.row
.add({
'tarifa_id': tarifa_final.id,
'cantidad': tarifa_final.cantidad,
'peso': tarifa_final.peso.toFixed(3),
'att': $('#add_att').val(),
'email': $('#add_email').val(),
'direccion': $('#add_direccion').val(),
'cp': $('#add_cp').val(),
'municipio': $('#add_municipio').val(),
'provincia': $('#add_provincia').val(),
'pais_id': $('#add_pais_id').select2('data')[0].id,
'pais': $('#add_pais_id').select2('data')[0].text,
'telefono': $('#add_telefono').val(),
'proveedor': tarifa_final.proveedor,
'proveedor_id': tarifa_final.proveedor_id,
'precio': tarifa_final.precio,
'margen': tarifa_final.margen,
'entregaPieCalle': $('#add_entregaPieCalle').is(":checked") ? 1 : 0,
'actionBtns_direcciones': `
<span class="edit-add"><a href="javascript:void(0);"><i class="ti ti-pencil ti-sm btn-edit-envio mx-2"></i></a></span>
<a href="javascript:void(0);"><i class="ti ti-trash ti-sm tiradas-alternativas btn-delete-envio mx-2"></i></a>
`,
})
.draw();
})
.draw();
}
else if (sourceTable === 'fp1') {
self.tableFP1.row
.add({
'tarifa_id': tarifa_final.id,
'cantidad': tarifa_final.cantidad,
'peso': tarifa_final.peso.toFixed(3),
'att': $('#add_att').val(),
'email': $('#add_email').val(),
'direccion': $('#add_direccion').val(),
'cp': $('#add_cp').val(),
'municipio': $('#add_municipio').val(),
'provincia': $('#add_provincia').val(),
'pais_id': $('#add_pais_id').select2('data')[0].id,
'pais': $('#add_pais_id').select2('data')[0].text,
'telefono': $('#add_telefono').val(),
'proveedor': tarifa_final.proveedor,
'proveedor_id': tarifa_final.proveedor_id,
'precio': 0,
'margen': 0,
'entregaPieCalle': 0,
'actionBtns_direcciones': `
<a href="javascript:void(0);"><i class="ti ti-trash ti-sm tiradas-alternativas btn-delete-envio mx-2"></i></a>
`,
})
.draw();
}
else {
self.tableFP2.row
.add({
'tarifa_id': tarifa_final.id,
'cantidad': tarifa_final.cantidad,
'peso': tarifa_final.peso.toFixed(3),
'att': $('#add_att').val(),
'email': $('#add_email').val(),
'direccion': $('#add_direccion').val(),
'cp': $('#add_cp').val(),
'municipio': $('#add_municipio').val(),
'provincia': $('#add_provincia').val(),
'pais_id': $('#add_pais_id').select2('data')[0].id,
'pais': $('#add_pais_id').select2('data')[0].text,
'telefono': $('#add_telefono').val(),
'proveedor': tarifa_final.proveedor,
'proveedor_id': tarifa_final.proveedor_id,
'precio': 0,
'margen': 0,
'entregaPieCalle': 0,
'actionBtns_direcciones': `
<a href="javascript:void(0);"><i class="ti ti-trash ti-sm tiradas-alternativas btn-delete-envio mx-2"></i></a>
`,
})
.draw();
}
// Se guarda la dirección
if ($('#add_saveDirection').is(":checked") &&
@ -703,13 +964,26 @@ class Envios {
return returnValue
}
cargar(datos) {
cargar(datos, datosFP) {
if (datos.entrega_taller) {
this.recogerTaller.prop('checked', true);
}
else {
this.table.rows.add(datos).draw();
}
if (datosFP.fp1.length > 0) {
this.tableFP1.rows.add(datosFP.fp1).draw();
$('#rowInsertarEnvioFP1').addClass('d-none');
}
if (datosFP.fp2.length > 0) {
this.tableFP2.rows.add(datosFP.fp2).draw();
$('#rowInsertarEnvioFP2').addClass('d-none');
}
if(datosFP.checkboxes){
$('#sameAddPrincipalFP1').prop('checked', datosFP.checkboxes.addFP1isAddMain == "1"? true: false);
$('#sameAddPrincipalFP2').prop('checked', datosFP.checkboxes.addFP2isAddMain == "1"? true: false);
$('#sameAddFP1').prop('checked', datosFP.checkboxes.addFP2isaddFP1 == "1"? true: false);
}
}
check_unidades_enviadas(event, recogerTaller = null) {
@ -719,12 +993,8 @@ class Envios {
}
let cantidad_total = 0
let hasFerroPrototipo = false
this.table.rows().every(function (rowIdx, tableLoop, rowLoop) {
if (this.data().is_ferro_prototipo == 0)
cantidad_total += parseInt(this.data().cantidad);
else
hasFerroPrototipo = true;
cantidad_total += parseInt(this.data().cantidad);
});
const tirada = parseInt($('#tirada').val());
@ -745,14 +1015,59 @@ class Envios {
this.insertarEnvio.removeClass('d-none');
return false;
}
if (($('#ferro').is(':checked') || $('#prototipo').is(':checked')) && !hasFerroPrototipo)
this.insertarEnvio.removeClass('d-none');
else
this.insertarEnvio.addClass('d-none');
$('#alert-envios').html(htmlString);
return true;
}
sameAddPrincipalFP1() {
this.tableFP1.clear().draw();
if ($('#sameAddPrincipalFP1').prop('checked')) {
if (this.table.rows().count() > 0) {
let data = this.table.row(0).data();
data.cantidad = 1; // Set unidades to 1
data.precio = 0;
data.margen = 0;
data.peso = this.get_peso_libro() / 1000;
this.tableFP1.row.add(data).draw();
}
}
}
sameAddPrincipalFP2() {
$('#sameAddFP1').prop('checked', false);
this.tableFP2.clear().draw();
if ($('#sameAddPrincipalFP2').prop('checked')) {
if (this.table.rows().count() > 0) {
let data = this.table.row(0).data();
data.cantidad = 1; // Set unidades to 1
data.precio = 0;
data.margen = 0;
data.peso = this.get_peso_libro() / 1000;
this.tableFP2.row.add(data).draw();
}
}
}
sameAddFP1() {
this.tableFP2.clear().draw();
$('#sameAddPrincipalFP2').prop('checked', false);
if ($('#sameAddFP1').prop('checked')) {
if (this.tableFP1.rows().count() > 0) {
let data = this.tableFP1.row(0).data();
data.cantidad = 1; // Set unidades to 1
data.precio = 0;
data.margen = 0;
data.peso = this.get_peso_libro() / 1000;
this.tableFP2.row.add(data).draw();
}
}
}
}
export default Envios;

View File

@ -119,6 +119,11 @@ class Servicios {
if (!this.checkServiceInTable(this.serviciosExtra.table, id))
this.serviciosExtra.getPresupuestoExtra(id);
}
else if (servicio == 'ferro_2') {
const id = $('#ferro_2').attr('service-id');
if (!this.checkServiceInTable(this.serviciosExtra.table, id))
this.serviciosExtra.getPresupuestoExtra(id);
}
else if (servicio == 'ferroDigital') {
const id = $('#ferroDigital').attr('service-id');
if (!this.checkServiceInTable(this.serviciosExtra.table, id))
@ -129,6 +134,11 @@ class Servicios {
if (!this.checkServiceInTable(this.serviciosExtra.table, id))
this.serviciosExtra.getPresupuestoExtra(id);
}
else if (servicio == 'prototipo_2') {
const id = $('#prototipo_2').attr('service-id');
if (!this.checkServiceInTable(this.serviciosExtra.table, id))
this.serviciosExtra.getPresupuestoExtra(id);
}
else if (servicio == 'retractilado') {
const id = $('#retractilado').attr('service-id');
if (!this.checkServiceInTable(this.serviciosAcabado.table, id))
@ -201,8 +211,18 @@ class Servicios {
}
});
}
if (servicio == 'ferroDigital') {
else if (servicio == 'ferro_2') {
const id = $('#ferro_2').attr('service-id');
this.serviciosExtra.table.rows().every(function () {
let data = this.data();
if (data.tarifa_id == id) {
this.remove();
self.serviciosExtra.table.draw();
return;
}
});
}
else if (servicio == 'ferroDigital') {
const id = $('#ferroDigital').attr('service-id');
this.serviciosExtra.table.rows().every(function () {
let data = this.data();
@ -225,6 +245,17 @@ class Servicios {
}
});
}
else if (servicio == 'prototipo_2') {
const id = $('#prototipo_2').attr('service-id');
this.serviciosExtra.table.rows().every(function () {
var data = this.data();
if (data.tarifa_id == id) {
this.remove();
self.serviciosExtra.table.draw();
return;
}
});
}
else if (servicio == 'retractilado') {
const id = $('#retractilado').attr('service-id');
for (let i = this.serviciosAcabado.table.rows().count(); i >= 0; i--) {

View File

@ -105,27 +105,26 @@ class DatosGenerales {
// check ferro y prototipo
this.domItem.on('change', 'input[type="checkbox"][data-tarifa-extra-excluyente="1"]', (e) => {
if (!this.cargando) {
const current = $(e.target);
if (current.is(':checked')) {
this.domItem.find('input[type="checkbox"][data-tarifa-extra-excluyente="1"]')
.not(current)
.prop('checked', false);
const current = $(e.target);
if ((current.data('tarifa-nombre')?.toString().toLowerCase() || '').includes('2')) {
$('#direccionesFerroPrototipo2').removeClass('d-none');
}
$('#direccionesFerroPrototipo').removeClass('d-none');
if (current.is(':checked')) {
this.domItem.find('input[type="checkbox"][data-tarifa-extra-excluyente="1"]')
.not(current)
.prop('checked', false);
if ((current.data('tarifa-nombre')?.toString().toLowerCase() || '').includes('2')) {
$('#direccionesFerroPrototipo2').removeClass('d-none');
}
else {
if (this.domItem.find('input[type="checkbox"][data-tarifa-extra-excluyente="1"]').prop('checked').length === 0) {
$('#direccionesFerroPrototipo').removeClass('d-none');
}
else {
if (this.domItem.find('input[type="checkbox"][data-tarifa-extra-excluyente="1"]').prop('checked').length === 0) {
$('#direccionesFerroPrototipo').addClass('d-none');
$('#divDireccionesFerroPrototipo').empty();
$('#direccionesFerroPrototipo2').addClass('d-none');
$('#divDireccionesFerroPrototipo2').empty();
}
$('#direccionesFerroPrototipo').addClass('d-none');
$('#divDireccionesFerroPrototipo').empty();
$('#direccionesFerroPrototipo2').addClass('d-none');
$('#divDireccionesFerroPrototipo2').empty();
}
}
});
@ -597,6 +596,7 @@ class DatosGenerales {
if (datos.serviciosExtra.includes(tarifaId)) {
$(this).prop('checked', true);
$(this).trigger('change');
}
});
}
@ -769,7 +769,7 @@ class DatosGenerales {
}
// Para recalcular el presupuesto
$('#paginas').trigger('change');
$('.input-paginas').trigger('change');
}
#handlePaginas() {

Some files were not shown because too many files have changed in this diff Show More