From f0a4f1908998ac456972ad1365b7e1ed82121647 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaime=20Jim=C3=A9nez?= Date: Sun, 13 Apr 2025 20:28:05 +0200 Subject: [PATCH 01/16] vista creada de envios --- ci4/app/Config/Routes.php | 2 + .../Logistica/LogisticaController.php | 40 +++++++++ ci4/app/Language/es/Logistica.php | 17 ++++ .../logistica/viewLogisticaSelectEnvios.php | 83 +++++++++++++++++++ .../form/logistica/viewPanelLogistica.php | 16 ++-- 5 files changed, 151 insertions(+), 7 deletions(-) create mode 100644 ci4/app/Views/themes/vuexy/form/logistica/viewLogisticaSelectEnvios.php diff --git a/ci4/app/Config/Routes.php b/ci4/app/Config/Routes.php index 8b6335a4..6adc2c7b 100644 --- a/ci4/app/Config/Routes.php +++ b/ci4/app/Config/Routes.php @@ -768,6 +768,8 @@ $routes->group('produccion', ['namespace' => 'App\Controllers\Produccion'], func $routes->group('logistica', ['namespace' => 'App\Controllers\Logistica'], function ($routes) { $routes->get('print/label/test', 'LogisticaController::print_test_label'); + $routes->get('panel', 'LogisticaController::panel', ['as' => 'LogisticaPanel']); + $routes->get('selectEnvios/(:any)', 'LogisticaController::selectorEnvios/$1', ['as' => 'selectEnvios']); }); diff --git a/ci4/app/Controllers/Logistica/LogisticaController.php b/ci4/app/Controllers/Logistica/LogisticaController.php index 25f5819d..f59a0788 100644 --- a/ci4/app/Controllers/Logistica/LogisticaController.php +++ b/ci4/app/Controllers/Logistica/LogisticaController.php @@ -15,11 +15,22 @@ class LogisticaController extends BaseController protected string $locale; protected array $viewData; + protected static $controllerSlug = 'logistica'; + protected static $viewPath = 'themes/vuexy/form/logistica/'; + public function initController(RequestInterface $request, ResponseInterface $response, LoggerInterface $logger) { $this->impresoraEtiquetaService = service('impresora_etiqueta'); $this->locale = session()->get('lang'); + $this->viewData['pageTitle'] = lang('Logistica.logistica'); + + // Breadcrumbs + $this->viewData['breadcrumb'] = [ + ['title' => lang("App.menu_logistica"), 'route' => "javascript:void(0);", 'active' => false], + ]; + + parent::initController($request, $response, $logger); } public function print_test_label() @@ -28,4 +39,33 @@ class LogisticaController extends BaseController $responseMessage = $etiquetaData["status"] ? "OK" : "ERROR"; return $this->response->setJSON(["message" => $responseMessage, "data" => $etiquetaData, "status" => $etiquetaData["status"]]); } + + public function panel() + { + $viewData = [ + 'currentModule' => static::$controllerSlug, + 'boxTitle' => lang('Logistica.panel'), + 'pageSubTitle' => 'Panel', + 'usingServerSideDataTable' => true, + ]; + + $viewData = array_merge($this->viewData, $viewData); // merge any possible values from the parent controller class + + return view(static::$viewPath . 'viewPanelLogistica', $viewData); + } + + public function selectorEnvios($tipoEnvio = null) + { + $viewData = [ + 'currentModule' => static::$controllerSlug, + 'boxTitle' => lang('Logistica.envioSimpleMultiple'), + 'usingServerSideDataTable' => true, + 'tipoEnvio' => $tipoEnvio, + ]; + + $viewData = array_merge($this->viewData, $viewData); // merge any possible values from the parent controller class + + return view(static::$viewPath . 'viewLogisticaSelectEnvios', $viewData); + } + } diff --git a/ci4/app/Language/es/Logistica.php b/ci4/app/Language/es/Logistica.php index 3885004a..f7799770 100644 --- a/ci4/app/Language/es/Logistica.php +++ b/ci4/app/Language/es/Logistica.php @@ -9,4 +9,21 @@ return [ 'etiquetasEnvio' => 'Etiquetas de envío', 'envioFerros' => 'Envío de ferros', 'cerrarOTauto' => 'Cerrar OT automáticamente', + 'envioSimpleMultiple' => 'Envío simple/múltiple', + 'nuevoEnvio' => 'Nuevo envío', + 'buscadorPedidosTitle' => 'Código Pedido o ISBN', + 'listadoEnvios' => 'Listado de envíos', + 'idEnvio' => 'ID Envío', + 'numeroPedidos' => 'Nº Pedidos', + 'numeroLineas' => 'Nº Líneas', + 'att' => 'Att', + 'direccion' => 'Dirección', + 'ciudad' => 'Ciudad', + 'pais' => 'País', + 'cp' => 'CP', + 'email' => 'Email', + 'telefono' => 'Teléfono', + 'finalizado' => 'Finalizado', + 'acciones' => 'Acciones', + 'backToPanel' => 'Volver al panel', ]; \ No newline at end of file diff --git a/ci4/app/Views/themes/vuexy/form/logistica/viewLogisticaSelectEnvios.php b/ci4/app/Views/themes/vuexy/form/logistica/viewLogisticaSelectEnvios.php new file mode 100644 index 00000000..5dedb86f --- /dev/null +++ b/ci4/app/Views/themes/vuexy/form/logistica/viewLogisticaSelectEnvios.php @@ -0,0 +1,83 @@ +include("themes/_commonPartialsBs/sweetalert") ?> +include('themes/_commonPartialsBs/datatables') ?> +extend('themes/vuexy/main/defaultlayout') ?> + +section('content'); ?> +
+
+
+
+

+
+
+ +
+

+ +

+ +
+
+ +
+ +
+ + +
+ +
+
+
+
+ + +
+

+ +

+ +
+
+ +
+ + + + + + + + + + + + + + + + + + + +
+ + +
+
+
+
+ +
+ +
+
+ +
+
+ endSection() ?> \ No newline at end of file diff --git a/ci4/app/Views/themes/vuexy/form/logistica/viewPanelLogistica.php b/ci4/app/Views/themes/vuexy/form/logistica/viewPanelLogistica.php index 419584a2..4ba6b66c 100644 --- a/ci4/app/Views/themes/vuexy/form/logistica/viewPanelLogistica.php +++ b/ci4/app/Views/themes/vuexy/form/logistica/viewPanelLogistica.php @@ -14,41 +14,43 @@
-
-
-
-
-
-
-
From c226f031d969c17fe5d288d4383e5351ccd8d718 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaime=20Jim=C3=A9nez?= Date: Mon, 14 Apr 2025 20:07:29 +0200 Subject: [PATCH 02/16] trabajando en selector de pedidos --- .../Logistica/LogisticaController.php | 26 +++++ .../2025-04-14-193000_CreateEnviosTable.php | 104 ++++++++++++++++++ 2 files changed, 130 insertions(+) create mode 100644 ci4/app/Database/Migrations/2025-04-14-193000_CreateEnviosTable.php diff --git a/ci4/app/Controllers/Logistica/LogisticaController.php b/ci4/app/Controllers/Logistica/LogisticaController.php index f59a0788..7813babd 100644 --- a/ci4/app/Controllers/Logistica/LogisticaController.php +++ b/ci4/app/Controllers/Logistica/LogisticaController.php @@ -68,4 +68,30 @@ class LogisticaController extends BaseController return view(static::$viewPath . 'viewLogisticaSelectEnvios', $viewData); } + public function searchPedidoOrISBN($search = ""){ + + $modelPedido = model('App\Models\Pedidos\PedidoModel'); + + $search = trim($search); + $searchClean = str_replace('-', '', $search); + $modelPedido = model('App\Models\Pedidos\PedidoModel'); + + // Builder con joins + $builder = $modelPedido->builder(); + $builder->select('pedidos.*'); + $builder->join('pedidos_linea', 'pedidos_linea.pedido_id = pedidos.id', 'left'); + $builder->join('presupuestos', 'presupuestos.id = pedidos_linea.presupuesto_id', 'left'); + + // Agrupar condiciones: por ID exacto o por ISBN sin guiones + $builder->groupStart() + ->where('pedidos.id', $search) + ->orWhere("REPLACE(presupuestos.isbn, '-', '')", $searchClean) + ->groupEnd(); + + $result = $builder->get()->getResult(); + $response = [ + 'status' => true, + 'data' => $result, + ]; + } } diff --git a/ci4/app/Database/Migrations/2025-04-14-193000_CreateEnviosTable.php b/ci4/app/Database/Migrations/2025-04-14-193000_CreateEnviosTable.php new file mode 100644 index 00000000..3ce4cc6d --- /dev/null +++ b/ci4/app/Database/Migrations/2025-04-14-193000_CreateEnviosTable.php @@ -0,0 +1,104 @@ +forge->addField([ + 'id' => [ + 'type' => 'INT', + 'unsigned' => true, + 'auto_increment' => true, + ], + 'finalizado' => [ + 'type' => 'TINYINT', + 'constraint' => 1, + 'default' => 0, + ], + 'codigo_seguimiento' => [ + 'type' => 'VARCHAR', + 'constraint' => 100, + 'null' => true, + ], + 'proveedor_id' => [ + 'type' => 'INT', + 'unsigned' => true, + 'null' => true, + ], + 'comentarios' => [ + 'type' => 'TEXT', + 'null' => true, + ], + 'att' => [ + 'type' => 'VARCHAR', + 'constraint' => 100, + 'null' => true, + ], + 'direccion' => [ + 'type' => 'VARCHAR', + 'constraint' => 300, + 'null' => true, + ], + 'ciudad' => [ + 'type' => 'VARCHAR', + 'constraint' => 100, + 'null' => true, + ], + 'cp' => [ + 'type' => 'VARCHAR', + 'constraint' => 10, + 'null' => true, + ], + 'email' => [ + 'type' => 'VARCHAR', + 'constraint' => 150, + 'null' => true, + ], + 'telefono' => [ + 'type' => 'VARCHAR', + 'constraint' => 60, + 'null' => true, + ], + 'pais_id' => [ + 'type' => 'INT', + 'unsigned' => true, + 'null' => true, + ], + 'mostrar_precios' => [ + 'type' => 'TINYINT', + 'constraint' => 1, + 'default' => 0, + ], + 'mostrar_iva' => [ + 'type' => 'TINYINT', + 'constraint' => 1, + 'default' => 0, + ], + 'created_at' => [ + 'type' => 'TIMESTAMP', + 'null' => false, + 'default' => '0000-00-00 00:00:00', + ], + 'updated_at' => [ + 'type' => 'TIMESTAMP', + 'null' => false, + 'default' => '0000-00-00 00:00:00', + ], + ]); + + $this->forge->addKey('id', true); + $this->forge->addForeignKey('proveedor_id', 'lg_proveedores', 'id', 'SET NULL', 'SET NULL'); + $this->forge->addForeignKey('pais_id', 'lg_paises', 'id', 'SET NULL', 'SET NULL'); + + $this->forge->createTable('envios'); + } + + public function down() + { + $this->forge->dropTable('envios'); + } +} From 16dc39ee15e595986242e3944d37cd59ee4029f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaime=20Jim=C3=A9nez?= Date: Mon, 14 Apr 2025 22:00:52 +0200 Subject: [PATCH 03/16] generando el grupo de envios --- ci4/app/Config/Routes.php | 2 +- .../Logistica/LogisticaController.php | 33 +++------ .../Presupuestos/Presupuestoadmin.php | 10 +++ ci4/app/Language/es/Logistica.php | 6 ++ ci4/app/Services/LogisticaService.php | 67 +++++++++++++++++++ .../logistica/viewLogisticaSelectEnvios.php | 15 ++++- .../js/safekat/pages/logistica/envio.js | 41 ++++++++++++ 7 files changed, 149 insertions(+), 25 deletions(-) create mode 100644 ci4/app/Services/LogisticaService.php create mode 100644 httpdocs/assets/js/safekat/pages/logistica/envio.js diff --git a/ci4/app/Config/Routes.php b/ci4/app/Config/Routes.php index 1e606ede..5698a9e6 100644 --- a/ci4/app/Config/Routes.php +++ b/ci4/app/Config/Routes.php @@ -774,7 +774,7 @@ $routes->group('logistica', ['namespace' => 'App\Controllers\Logistica'], functi $routes->get('print/label/test', 'LogisticaController::print_test_label'); $routes->get('panel', 'LogisticaController::panel', ['as' => 'LogisticaPanel']); $routes->get('selectEnvios/(:any)', 'LogisticaController::selectorEnvios/$1', ['as' => 'selectEnvios']); - + $routes->get('buscar/(:any)', 'LogisticaController::searchPedidoOrISBN/$1', ['as' => 'buscarPedidoOrISBN']); }); /* diff --git a/ci4/app/Controllers/Logistica/LogisticaController.php b/ci4/app/Controllers/Logistica/LogisticaController.php index 7813babd..98dff187 100644 --- a/ci4/app/Controllers/Logistica/LogisticaController.php +++ b/ci4/app/Controllers/Logistica/LogisticaController.php @@ -4,6 +4,7 @@ namespace App\Controllers\Logistica; use App\Controllers\BaseController; use App\Services\ImpresoraEtiquetaService; +use App\Services\LogisticaService; use CodeIgniter\HTTP\RequestInterface; use CodeIgniter\HTTP\ResponseInterface; use Psr\Log\LoggerInterface; @@ -70,28 +71,14 @@ class LogisticaController extends BaseController public function searchPedidoOrISBN($search = ""){ - $modelPedido = model('App\Models\Pedidos\PedidoModel'); - - $search = trim($search); - $searchClean = str_replace('-', '', $search); - $modelPedido = model('App\Models\Pedidos\PedidoModel'); - - // Builder con joins - $builder = $modelPedido->builder(); - $builder->select('pedidos.*'); - $builder->join('pedidos_linea', 'pedidos_linea.pedido_id = pedidos.id', 'left'); - $builder->join('presupuestos', 'presupuestos.id = pedidos_linea.presupuesto_id', 'left'); - - // Agrupar condiciones: por ID exacto o por ISBN sin guiones - $builder->groupStart() - ->where('pedidos.id', $search) - ->orWhere("REPLACE(presupuestos.isbn, '-', '')", $searchClean) - ->groupEnd(); - - $result = $builder->get()->getResult(); - $response = [ - 'status' => true, - 'data' => $result, - ]; + if(empty($search)){ + $result = [ + 'status' => false, + 'message' => lang('Logistica.errors.noDataToFind'), + ]; + return $this->response->setJSON($result); + } + $result = LogisticaService::findPedidoOrISBN($search); + return $this->response->setJSON($result); } } diff --git a/ci4/app/Controllers/Presupuestos/Presupuestoadmin.php b/ci4/app/Controllers/Presupuestos/Presupuestoadmin.php index 5039d115..5fe536da 100644 --- a/ci4/app/Controllers/Presupuestos/Presupuestoadmin.php +++ b/ci4/app/Controllers/Presupuestos/Presupuestoadmin.php @@ -382,6 +382,16 @@ class Presupuestoadmin extends \App\Controllers\BaseResourceController 'descripcion' => $linea_pedido->concepto ]); + // se actualiza el totalizador del pedido + $total_tirada = $pedidoModel + ->selectSum('cantidad') + ->where('pedido_id', $idPedido) + ->first()->cantidad; + $pedidoModel = model('App\Models\Pedidos\PedidoModel'); + $pedidoModel->update($idPedido, [ + 'total_tirada' => $total_tirada + ]); + // se actualiza la factura $linea_pedido = $this->model->generarLineaPedido($id, true, $idPedido)[0]; $facturaLineaModel = model('App\Models\Facturas\FacturaLineaModel'); diff --git a/ci4/app/Language/es/Logistica.php b/ci4/app/Language/es/Logistica.php index f7799770..d358bb66 100644 --- a/ci4/app/Language/es/Logistica.php +++ b/ci4/app/Language/es/Logistica.php @@ -26,4 +26,10 @@ return [ 'finalizado' => 'Finalizado', 'acciones' => 'Acciones', 'backToPanel' => 'Volver al panel', + + 'errors' => [ + 'noDataToFind' => 'No se ha introducido ningún dato para buscar', + 'notFound' => 'No se encuentra el pedido o ISBN', + 'noAddresses' => 'El pedido no tiene direcciones de envío', + ], ]; \ No newline at end of file diff --git a/ci4/app/Services/LogisticaService.php b/ci4/app/Services/LogisticaService.php new file mode 100644 index 00000000..bb4a193c --- /dev/null +++ b/ci4/app/Services/LogisticaService.php @@ -0,0 +1,67 @@ +builder(); + $builder->select('pedidos.id as pedido_id, pedidos_linea.id as linea_id, presupuestos.id as presupuesto_id'); + $builder->join('pedidos_linea', 'pedidos_linea.pedido_id = pedidos.id', 'left'); + $builder->join('presupuestos', 'presupuestos.id = pedidos_linea.presupuesto_id', 'left'); + + $builder->groupStart() + ->where('pedidos.id', $search) + ->whereIn('pedidos.estado', ['finalizado']) + ->orWhere("REPLACE(presupuestos.isbn, '-', '')", $searchClean) + ->groupEnd(); + + $result = $builder->get()->getResult(); + + if (empty($result)) { + $response = [ + 'status' => false, + 'message' => lang('Logistica.errors.notFound'), + ]; + return $response; + } + + $PresupuestoDireccionesModel = model('App\Models\Presupuestos\PresupuestoDireccionesModel'); + $numDirecciones = $PresupuestoDireccionesModel->where('presupuesto_id', $result[0]->presupuesto_id) + ->countAllResults(); + if ($numDirecciones == 0) { + $response = [ + 'status' => false, + 'message' => lang('Logistica.errors.noAddresses'), + ]; + return $response; + } + + // detectar si el pedido tiene los albaranes generados + $AlbaranModel = model('App\Models\Pedidos\AlbaranModel'); + $numAlbaranes = $AlbaranModel->where('pedido_id', $result[0]->pedido_id) + ->countAllResults(); + + $response = [ + 'status' => true, + 'data' => $result[0], + ]; + + if($numAlbaranes == 0){ + $user = auth()->user()->id; + $AlbaranModel->generarAlbaranes($result[0]->pedido_id, [$result[0]->presupuesto_id], $user); + $response['data']->createAlbaran = true; + } + + return $response; + } +} diff --git a/ci4/app/Views/themes/vuexy/form/logistica/viewLogisticaSelectEnvios.php b/ci4/app/Views/themes/vuexy/form/logistica/viewLogisticaSelectEnvios.php index 5dedb86f..aecb0c00 100644 --- a/ci4/app/Views/themes/vuexy/form/logistica/viewLogisticaSelectEnvios.php +++ b/ci4/app/Views/themes/vuexy/form/logistica/viewLogisticaSelectEnvios.php @@ -11,6 +11,8 @@
+ +

@@ -72,7 +74,8 @@

-
@@ -80,4 +83,14 @@
+ endSection() ?> + + + section('css') ?> + + endSection() ?> + + section('additionalExternalJs') ?> + + endSection() ?> \ No newline at end of file diff --git a/httpdocs/assets/js/safekat/pages/logistica/envio.js b/httpdocs/assets/js/safekat/pages/logistica/envio.js new file mode 100644 index 00000000..5c48cebb --- /dev/null +++ b/httpdocs/assets/js/safekat/pages/logistica/envio.js @@ -0,0 +1,41 @@ +import Ajax from '../../components/ajax.js'; + +$(()=>{ + + $('#buscadorPedidos').on('keydown', function(e) { + if (e.key === 'Enter' || e.keyCode === 13) { + e.preventDefault(); // Evita el submit si está dentro de un form + let search = $(this).val().trim(); + new Ajax( + '/logistica/buscar/'+search, + {}, + {}, + function(response) { + if(response.data.createAlbaran){ + + Swal.fire({ + title: 'Atención!', + text: 'El pedido no contenía ningún albarán. Se han añadido automáticamente.', + icon: 'warning', + showCancelButton: false, + confirmButtonColor: '#3085d6', + confirmButtonText: 'Ok', + customClass: { + confirmButton: 'btn btn-primary me-1', + }, + buttonsStyling: false + }).then(() => { + //window.open(`${urlObj.origin}` + '/presupuestoadmin/edit/' + response.id); + }); + } + + }, + function(xhr, status, error) { + popErrorAlert(error.responseJSON.message); + } + ).get(); + + } + }); + +}); \ No newline at end of file From fedc608463d88e5e63c8fde458874b98178ebdaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaime=20Jim=C3=A9nez?= Date: Tue, 15 Apr 2025 18:48:01 +0200 Subject: [PATCH 04/16] cambios antes del pull --- ci4/app/Services/LogisticaService.php | 37 +++++++++++++++++++ .../presupuestoAdmin/presupuestoAdminEdit.js | 4 +- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/ci4/app/Services/LogisticaService.php b/ci4/app/Services/LogisticaService.php index bb4a193c..5104bc8f 100644 --- a/ci4/app/Services/LogisticaService.php +++ b/ci4/app/Services/LogisticaService.php @@ -64,4 +64,41 @@ class LogisticaService return $response; } + + + + private function generateEnvio($pedido){ + + // Se obtiene los datos de att, direccion, ciudad, cp, telefono, pais_id + $modelPedidoLinea = model('App\Models\Pedidos\PedidoLineaModel'); + $lineasPedido = $modelPedidoLinea->where('pedido_id', $pedido->id) + $multienvio = false; + ->findAll(); + if(empty($lineasPedido)){ + return [ + 'status' => false, + 'message' => lang('Logistica.errors.noLines'), + ]; + } + if(count($lineasPedido) > 1){ + $multienvio = true; + } + if(!$multienvio){ + // solo hay una dirección, se obtiene de los albaranes + $AlbaranModel = model('App\Models\Pedidos\AlbaranModel'); + $datosEnvio = $AlbaranModel + ->select('albaranes.att_albaran as att, albaranes.direccion_albaran as direccion, + presupuestos_direcciones.ciudad as ciudad, presupuestos_direcciones.cp as cp, presupuestos_direcciones.telefono as telefono, + presupuestos_direcciones.pais_id as pais_id, albaranes_linea.cantidad as cantidad, albaranes_linea.cajas as cajas') + ->where('albaranes.pedido_id', $pedido->id) + ->where('albaranes_linea.cajas !=', null) + ->join('albaranes_linea', 'albaranes_linea.albaran_id = albaranes.id') + ->join('presupuestos_direcciones', 'presupuestos_direcciones.id = albaran.presupuesto_id') + ->first(); + } + + + + + } } diff --git a/httpdocs/assets/js/safekat/pages/presupuestoAdmin/presupuestoAdminEdit.js b/httpdocs/assets/js/safekat/pages/presupuestoAdmin/presupuestoAdminEdit.js index 1fe9218c..b441c819 100644 --- a/httpdocs/assets/js/safekat/pages/presupuestoAdmin/presupuestoAdminEdit.js +++ b/httpdocs/assets/js/safekat/pages/presupuestoAdmin/presupuestoAdminEdit.js @@ -129,8 +129,10 @@ class PresupuestoAdminEdit { let totalCostes = AutoNumeric.getAutoNumericElement($('#totalCostes')[0]); let envio_base = AutoNumeric.getAutoNumericElement($('#precioEnvios')[0]); let autoTotalAceptado = AutoNumeric.getAutoNumericElement($('#total_aceptado_revisado')[0]); + let totalMargenes = AutoNumeric.getAutoNumericElement($('#totalMargenes')[0]); let total_aceptado_revisado = autoTotalAceptado.getNumber(); + if (total_aceptado_revisado && total_aceptado_revisado != 0) { const nuevoTotal = totalCostes.getNumber() + envio_base.getNumber(); @@ -140,7 +142,7 @@ class PresupuestoAdminEdit { total_aceptado_revisado = nuevoTotal; } - totalMargenes = total_aceptado_revisado - nuevoTotal; + totalMargenes.set(total_aceptado_revisado - nuevoTotal); } }.bind(this)); From 3ada529b6e9e86f0c3a993676728c8b09a4056f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaime=20Jim=C3=A9nez?= Date: Wed, 16 Apr 2025 18:24:48 +0200 Subject: [PATCH 05/16] trabajando --- ci4/app/Config/Routes.php | 1 + .../Logistica/LogisticaController.php | 38 +++++++- ci4/app/Language/es/Logistica.php | 7 +- ci4/app/Services/LogisticaService.php | 93 +++++++++++++++---- .../js/safekat/pages/logistica/envio.js | 58 +++++++++++- 5 files changed, 173 insertions(+), 24 deletions(-) diff --git a/ci4/app/Config/Routes.php b/ci4/app/Config/Routes.php index 49b5fe10..da335ade 100644 --- a/ci4/app/Config/Routes.php +++ b/ci4/app/Config/Routes.php @@ -781,6 +781,7 @@ $routes->group('logistica', ['namespace' => 'App\Controllers\Logistica'], functi $routes->get('panel', 'LogisticaController::panel', ['as' => 'LogisticaPanel']); $routes->get('selectEnvios/(:any)', 'LogisticaController::selectorEnvios/$1', ['as' => 'selectEnvios']); $routes->get('buscar/(:any)', 'LogisticaController::searchPedidoOrISBN/$1', ['as' => 'buscarPedidoOrISBN']); + $routes->get('datatableEnvios', 'LogisticaController::datatable_envios'); }); /* diff --git a/ci4/app/Controllers/Logistica/LogisticaController.php b/ci4/app/Controllers/Logistica/LogisticaController.php index 98dff187..53776b1c 100644 --- a/ci4/app/Controllers/Logistica/LogisticaController.php +++ b/ci4/app/Controllers/Logistica/LogisticaController.php @@ -8,6 +8,7 @@ use App\Services\LogisticaService; use CodeIgniter\HTTP\RequestInterface; use CodeIgniter\HTTP\ResponseInterface; use Psr\Log\LoggerInterface; +use Hermawan\DataTables\DataTable; class LogisticaController extends BaseController { @@ -69,16 +70,45 @@ class LogisticaController extends BaseController return view(static::$viewPath . 'viewLogisticaSelectEnvios', $viewData); } - public function searchPedidoOrISBN($search = ""){ + public function searchPedidoOrISBN($search = "") + { - if(empty($search)){ + if (empty($search)) { $result = [ 'status' => false, 'message' => lang('Logistica.errors.noDataToFind'), ]; - return $this->response->setJSON($result); + return $this->response->setJSON($result); } $result = LogisticaService::findPedidoOrISBN($search); - return $this->response->setJSON($result); + return $this->response->setJSON($result); + } + + public function datatable_envios() + { + $model = model('App\Models\Logistica\EnvioModel'); + $q = $model->getDatatableQuery(); + + + $result = DataTable::of($q) + ->edit( + "finalizado", + function ($row, $meta) { + if ($row->finalizado == 1) + return ''; + else + return ''; + } + ) + ->add("action", callback: function ($q) { + + return ' +
+ +
+ '; + }); + + return $result->toJson(returnAsObject: true); } } diff --git a/ci4/app/Language/es/Logistica.php b/ci4/app/Language/es/Logistica.php index d358bb66..e3fa7838 100644 --- a/ci4/app/Language/es/Logistica.php +++ b/ci4/app/Language/es/Logistica.php @@ -26,10 +26,13 @@ return [ 'finalizado' => 'Finalizado', 'acciones' => 'Acciones', 'backToPanel' => 'Volver al panel', - + 'no' => 'No', + 'si' => 'Sí', + 'errors' => [ + 'noAlbaranes' => 'No se han encontrado albaranes para este pedido', 'noDataToFind' => 'No se ha introducido ningún dato para buscar', - 'notFound' => 'No se encuentra el pedido o ISBN', + 'notFound' => 'No se encuentra el pedido o ISBN, o el pedido aún no se ha finalizado', 'noAddresses' => 'El pedido no tiene direcciones de envío', ], ]; \ No newline at end of file diff --git a/ci4/app/Services/LogisticaService.php b/ci4/app/Services/LogisticaService.php index 5104bc8f..7d102ee5 100644 --- a/ci4/app/Services/LogisticaService.php +++ b/ci4/app/Services/LogisticaService.php @@ -62,43 +62,104 @@ class LogisticaService $response['data']->createAlbaran = true; } + $response_envio = LogisticaService::generateEnvio($result[0]->pedido_id); + if($response_envio['status'] == false){ + $response = [ + 'status' => false, + 'message' => $response_envio['message'], + ]; + return $response; + } + else{ + $response['data']->id_envio = $response_envio['data']['id_envio']; + $response['data']->multienvio = $response_envio['data']['multienvio']; + } + return $response; } - private function generateEnvio($pedido){ + private static function generateEnvio($pedido_id){ // Se obtiene los datos de att, direccion, ciudad, cp, telefono, pais_id - $modelPedidoLinea = model('App\Models\Pedidos\PedidoLineaModel'); - $lineasPedido = $modelPedidoLinea->where('pedido_id', $pedido->id) + $AlbaranModel = model('App\Models\Pedidos\AlbaranModel'); + $lineasAlbaran = $AlbaranModel->where('pedido_id', $pedido_id) + ->join('albaranes_lineas', 'albaranes_lineas.albaran_id = albaranes.id') + ->join('pedidos', 'pedidos.id = albaranes.pedido_id') + ->where('pedidos.estado', 'finalizado') + ->countAllResults(); + $multienvio = false; - ->findAll(); - if(empty($lineasPedido)){ + + if($lineasAlbaran == 0){ return [ 'status' => false, - 'message' => lang('Logistica.errors.noLines'), + 'message' => lang('Logistica.errors.noAlbaranes'), ]; } - if(count($lineasPedido) > 1){ + if($lineasAlbaran > 1){ $multienvio = true; } if(!$multienvio){ // solo hay una dirección, se obtiene de los albaranes - $AlbaranModel = model('App\Models\Pedidos\AlbaranModel'); + $datosEnvio = $AlbaranModel ->select('albaranes.att_albaran as att, albaranes.direccion_albaran as direccion, - presupuestos_direcciones.ciudad as ciudad, presupuestos_direcciones.cp as cp, presupuestos_direcciones.telefono as telefono, - presupuestos_direcciones.pais_id as pais_id, albaranes_linea.cantidad as cantidad, albaranes_linea.cajas as cajas') - ->where('albaranes.pedido_id', $pedido->id) - ->where('albaranes_linea.cajas !=', null) - ->join('albaranes_linea', 'albaranes_linea.albaran_id = albaranes.id') - ->join('presupuestos_direcciones', 'presupuestos_direcciones.id = albaran.presupuesto_id') + presupuesto_direcciones.provincia as ciudad, presupuesto_direcciones.cp as cp, presupuesto_direcciones.telefono as telefono, presupuesto_direcciones.email as email, + presupuesto_direcciones.pais_id as pais_id, albaranes_lineas.cantidad as cantidad, albaranes_lineas.cajas as cajas') + ->where('albaranes.pedido_id', $pedido_id) + ->where('albaranes_lineas.cajas !=', null) + ->join('albaranes_lineas', 'albaranes_lineas.albaran_id = albaranes.id') + ->join('presupuesto_direcciones', 'presupuesto_direcciones.presupuesto_id = albaranes.presupuesto_id') ->first(); + + // se genera un nuevo envio con estos datos + $EnvioModel = model('App\Models\Logistica\EnvioModel'); + $EnvioModel->set('att', $datosEnvio->att); + $EnvioModel->set('direccion', $datosEnvio->direccion); + $EnvioModel->set('ciudad', $datosEnvio->ciudad); + $EnvioModel->set('cp', $datosEnvio->cp); + $EnvioModel->set('telefono', $datosEnvio->telefono); + $EnvioModel->set('email', $datosEnvio->email); + $EnvioModel->set('pais_id', $datosEnvio->pais_id); + $EnvioModel->set('cantidad', $datosEnvio->cantidad); + $EnvioModel->set('cajas', $datosEnvio->cajas); + $EnvioModel->set('created_at', date('Y-m-d H:i:s')); + $EnvioModel->set('updated_at', date('Y-m-d H:i:s')); + $EnvioModel->insert(); + $idEnvio = $EnvioModel->insertID(); + + // se genera la linea de envio + $EnvioLineasModel = model('App\Models\Logistica\EnvioLineaModel'); + $EnvioLineasModel->set('envio_id', $idEnvio); + $EnvioLineasModel->set('pedido_id', $pedido_id); + $EnvioLineasModel->set('unidades_envio', $datosEnvio->cantidad); + $EnvioLineasModel->set('unidades_total', $datosEnvio->cantidad); + $EnvioLineasModel->set('cajas', $datosEnvio->cajas); + $EnvioLineasModel->set('unidades_cajas', $datosEnvio->cajas); + $EnvioLineasModel->set('created_at', date('Y-m-d H:i:s')); + $EnvioLineasModel->set('updated_at', date('Y-m-d H:i:s')); + $EnvioLineasModel->set('created_by', auth()->user()->id); + $EnvioLineasModel->set('updated_by', auth()->user()->id); + $EnvioLineasModel->insert(); + + return [ + 'status' => true, + 'data' => [ + 'id_envio' => $idEnvio, + 'multienvio' => false, + ], + ]; + } - - + if(empty($datosEnvio)){ + return [ + 'status' => false, + 'message' => lang('Logistica.errors.noAddresses'), + ]; + } } } diff --git a/httpdocs/assets/js/safekat/pages/logistica/envio.js b/httpdocs/assets/js/safekat/pages/logistica/envio.js index 5c48cebb..9dcfb3c8 100644 --- a/httpdocs/assets/js/safekat/pages/logistica/envio.js +++ b/httpdocs/assets/js/safekat/pages/logistica/envio.js @@ -11,7 +11,10 @@ $(()=>{ {}, {}, function(response) { - if(response.data.createAlbaran){ + if(!response.status){ + popErrorAlert(response.message); + } + if(response.data && response.data.createAlbaran){ Swal.fire({ title: 'Atención!', @@ -31,11 +34,62 @@ $(()=>{ }, function(xhr, status, error) { - popErrorAlert(error.responseJSON.message); + if(status == 'error' && typeof(error)== 'string') + popErrorAlert(error); + else + popErrorAlert(error.responseJSON.message); } ).get(); } }); + + const tableEnvios = $('#tableOfEnvios').DataTable({ + processing: true, + serverSide: true, + autoWidth: true, + responsive: true, + scrollX: true, + orderCellsTop: true, + lengthMenu: [5, 10, 25, 50, 75, 100, 250, 500, 1000, 2500], + pageLength: 50, + "dom": 'lBrtip', + "ajax": { + "url": "/logistica/datatableEnvios", + }, + "columns": [ + { "data": "id" }, + { "data": "pedidos" }, + { "data": "num_lineas" }, + { "data": "att" }, + { "data": "direccion" }, + { "data": "ciudad" }, + { "data": "pais" }, + { "data": "cp" }, + { "data": "email" }, + { "data": "telefono" }, + { + "data": "finalizado", + "className": "text-center", + }, + { "data": "action" } + + ], + "language": { + url: "/themes/vuexy/vendor/libs/datatables-sk/plugins/i18n/es-ES.json" + }, + "columnDefs": [ + { + orderable: false, + searchable: false, + targets: [11] + }, + ], + "order": [[0, "desc"]], + }); + + $(document).on('click', '.btn-edit', function (e) { + window.location.href = '/logistica/envio/' + $(this).attr('data-id'); + }); }); \ No newline at end of file From 3949607a3c490198fafc84a49cb0604234506275 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaime=20Jim=C3=A9nez?= Date: Thu, 17 Apr 2025 13:47:26 +0200 Subject: [PATCH 06/16] =?UTF-8?q?trabajando=20en=20a=C3=B1adir=20lineas=20?= =?UTF-8?q?a=20envio?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ci4/app/Config/Routes.php | 3 + .../Logistica/LogisticaController.php | 70 ++++++- ci4/app/Language/es/Logistica.php | 25 ++- ci4/app/Services/LogisticaService.php | 190 ++++++++++++------ .../js/safekat/pages/logistica/envio.js | 17 +- 5 files changed, 223 insertions(+), 82 deletions(-) diff --git a/ci4/app/Config/Routes.php b/ci4/app/Config/Routes.php index da335ade..7b31629b 100644 --- a/ci4/app/Config/Routes.php +++ b/ci4/app/Config/Routes.php @@ -782,6 +782,9 @@ $routes->group('logistica', ['namespace' => 'App\Controllers\Logistica'], functi $routes->get('selectEnvios/(:any)', 'LogisticaController::selectorEnvios/$1', ['as' => 'selectEnvios']); $routes->get('buscar/(:any)', 'LogisticaController::searchPedidoOrISBN/$1', ['as' => 'buscarPedidoOrISBN']); $routes->get('datatableEnvios', 'LogisticaController::datatable_envios'); + $routes->get('datatableLineasEnvios/(:num)', 'LogisticaController::datatable_enviosEdit/$1'); + $routes->get('envio/(:num)', 'LogisticaController::editEnvio/$1'); + $routes->get('selectAddLinea', 'LogisticaController::selectAddEnvioLinea'); }); /* diff --git a/ci4/app/Controllers/Logistica/LogisticaController.php b/ci4/app/Controllers/Logistica/LogisticaController.php index 53776b1c..27d101d8 100644 --- a/ci4/app/Controllers/Logistica/LogisticaController.php +++ b/ci4/app/Controllers/Logistica/LogisticaController.php @@ -70,7 +70,7 @@ class LogisticaController extends BaseController return view(static::$viewPath . 'viewLogisticaSelectEnvios', $viewData); } - public function searchPedidoOrISBN($search = "") + public function searchPedidoOrISBN($search = "", $envio_id = null) { if (empty($search)) { @@ -80,10 +80,27 @@ class LogisticaController extends BaseController ]; return $this->response->setJSON($result); } - $result = LogisticaService::findPedidoOrISBN($search); + $result = LogisticaService::findPedidoOrISBN($search, $envio_id); return $this->response->setJSON($result); } + public function selectAddEnvioLinea(){ + + if ($this->request->isAJAX()) { + $query = LogisticaService::findLineaEnvio($this->request->getGet('direccion'))->orderBy("nombre", "asc"); + if ($this->request->getGet("q")) { + $query->groupStart() + ->orLike("pedidos.id", $this->request->getGet("q")) + ->orLike("presupuestos.titulo", $this->request->getGet("q")) + ->groupEnd(); + } + + return $this->response->setJSON($query->get()->getResultObject()); + } else { + return $this->failUnauthorized('Invalid request', 403); + } + } + public function datatable_envios() { $model = model('App\Models\Logistica\EnvioModel'); @@ -111,4 +128,53 @@ class LogisticaController extends BaseController return $result->toJson(returnAsObject: true); } + + public function editEnvio($id = null){ + + if (empty($id)) { + return redirect()->to(base_url('logistica/selectEnvios/simple'))->with('error', lang('Logistica.errors.noEnvio')); + } + $model = model('App\Models\Logistica\EnvioModel'); + $envioEntity = $model->select('envios.*, lg_paises.nombre as pais') + ->join('lg_paises', 'lg_paises.id = envios.pais_id', 'left') + ->where('envios.id', $id) + ->first(); + if (empty($envioEntity)) { + return redirect()->to(base_url('logistica/selectEnvios/simple'))->with('error', lang('Logistica.errors.noEnvio')); + } + + $viewData = [ + 'currentModule' => static::$controllerSlug, + 'boxTitle' => '' . ' '. lang('Logistica.envio') . ' [' . $envioEntity->id . ']: ' . $envioEntity->direccion, + 'usingServerSideDataTable' => true, + 'envioEntity' => $envioEntity, + ]; + + $viewData = array_merge($this->viewData, $viewData); // merge any possible values from the parent controller class + + return view(static::$viewPath . 'viewEnvioEditForm', $viewData); + } + + public function datatable_enviosEdit($idEnvio) + { + $model = model('App\Models\Logistica\EnvioLineaModel'); + $q = $model->getDatatableQuery($idEnvio); + + + $result = DataTable::of($q) + ->add("rowSelected",callback: function ($q) { + return ''; + } + ) + ->add("action", callback: function ($q) { + + return ' +
+ +
+ '; + }); + + return $result->toJson(returnAsObject: true); + } } diff --git a/ci4/app/Language/es/Logistica.php b/ci4/app/Language/es/Logistica.php index e3fa7838..501049f3 100644 --- a/ci4/app/Language/es/Logistica.php +++ b/ci4/app/Language/es/Logistica.php @@ -29,10 +29,31 @@ return [ 'no' => 'No', 'si' => 'Sí', + 'envio' => 'Envío', + 'addLineasEnvio' => 'Añadir líneas al envío', + 'addLineasText'=> 'La siguiente lista muestra los envíos del cliente a la misma dirección de envío. Si desea añadir líneas a un envío existente, seleccione el envío y haga clic en "Añadir líneas al envío". Si desea crear un nuevo envío, haga clic en "Añadir".', + 'add' => 'Añadir', + + 'datosEnvio' => 'Datos del envío', + 'lineasEnvio' => 'Líneas del envío', + 'comentariosEnvio' => 'Comentarios del envío', + 'guardar' => 'Guardar', + + 'pedido' => 'Pedido', + 'presupuesto' => 'Presupuesto', + 'unidadesEnvio' => 'Unidades envío', + 'unidadesEnviadas' => 'Unidades enviadas', + 'titulo' => 'Título', + 'unidadesTotales' => 'Total unidades', + 'eliminar' => 'Eliminar', + 'generarAlbaran' => 'Generar albarán', + 'imprimirEtiquetas' => 'Imprimir etiquetas', + 'buttonsActions' => 'Acciones sobre las filas seleccionadas', + 'errors' => [ - 'noAlbaranes' => 'No se han encontrado albaranes para este pedido', + 'noEnvio' => 'No se ha encontrado el envio', 'noDataToFind' => 'No se ha introducido ningún dato para buscar', - 'notFound' => 'No se encuentra el pedido o ISBN, o el pedido aún no se ha finalizado', + 'notFound' => 'No se encuentra el pedido o ISBN, el pedido aún no se ha finalizado o no tiene envíos pendientes', 'noAddresses' => 'El pedido no tiene direcciones de envío', ], ]; \ No newline at end of file diff --git a/ci4/app/Services/LogisticaService.php b/ci4/app/Services/LogisticaService.php index 7d102ee5..e219e765 100644 --- a/ci4/app/Services/LogisticaService.php +++ b/ci4/app/Services/LogisticaService.php @@ -8,22 +8,35 @@ class LogisticaService { public static function findPedidoOrISBN($search) { + $multienvio = false; + $modelPedido = model('App\Models\Pedidos\PedidoModel'); - + $search = trim($search); $searchClean = str_replace('-', '', $search); $modelPedido = model('App\Models\Pedidos\PedidoModel'); $builder = $modelPedido->builder(); - $builder->select('pedidos.id as pedido_id, pedidos_linea.id as linea_id, presupuestos.id as presupuesto_id'); + + $builder->select([ + 'pedidos.id as pedido_id', + 'pedidos_linea.id as linea_id', + 'pedidos_linea.cantidad as cantidad_linea', + 'presupuestos.id as presupuesto_id', + ]); + $builder->join('pedidos_linea', 'pedidos_linea.pedido_id = pedidos.id', 'left'); $builder->join('presupuestos', 'presupuestos.id = pedidos_linea.presupuesto_id', 'left'); - + $builder->join('envios_lineas', 'envios_lineas.pedido_id = pedidos_linea.pedido_id', 'left'); + $builder->groupStart() ->where('pedidos.id', $search) ->whereIn('pedidos.estado', ['finalizado']) ->orWhere("REPLACE(presupuestos.isbn, '-', '')", $searchClean) - ->groupEnd(); + ->groupEnd(); + + $builder->groupBy('pedidos_linea.id'); + $builder->having('IFNULL(SUM(envios_lineas.unidades_envio), 0) < cantidad_linea', null, false); $result = $builder->get()->getResult(); @@ -44,76 +57,122 @@ class LogisticaService 'message' => lang('Logistica.errors.noAddresses'), ]; return $response; + } else if ($numDirecciones > 1) { + $multienvio = true; } - // detectar si el pedido tiene los albaranes generados - $AlbaranModel = model('App\Models\Pedidos\AlbaranModel'); - $numAlbaranes = $AlbaranModel->where('pedido_id', $result[0]->pedido_id) - ->countAllResults(); - $response = [ 'status' => true, 'data' => $result[0], - ]; + ]; - if($numAlbaranes == 0){ - $user = auth()->user()->id; - $AlbaranModel->generarAlbaranes($result[0]->pedido_id, [$result[0]->presupuesto_id], $user); - $response['data']->createAlbaran = true; - } - $response_envio = LogisticaService::generateEnvio($result[0]->pedido_id); - if($response_envio['status'] == false){ + $response_envio = LogisticaService::generateEnvio($result[0]->pedido_id, $multienvio); + if ($response_envio['status'] == false) { $response = [ 'status' => false, 'message' => $response_envio['message'], ]; return $response; - } - else{ + } else { $response['data']->id_envio = $response_envio['data']['id_envio']; $response['data']->multienvio = $response_envio['data']['multienvio']; } - return $response; + return $response; } + public static function findLineaEnvio($direccion){ - private static function generateEnvio($pedido_id){ - - // Se obtiene los datos de att, direccion, ciudad, cp, telefono, pais_id - $AlbaranModel = model('App\Models\Pedidos\AlbaranModel'); - $lineasAlbaran = $AlbaranModel->where('pedido_id', $pedido_id) - ->join('albaranes_lineas', 'albaranes_lineas.albaran_id = albaranes.id') - ->join('pedidos', 'pedidos.id = albaranes.pedido_id') - ->where('pedidos.estado', 'finalizado') - ->countAllResults(); + $modelPedido = model('App\Models\Pedidos\PedidoModel'); - $multienvio = false; + $builder = $modelPedido->builder(); + + $builder->select(" + CONCAT( + '[' , + pedidos.id, ']', + ' - ', + presupuestos.titulo, + ) as name, + pedidos.id as pedido_id"); + + $builder->join('pedidos_linea', 'pedidos_linea.pedido_id = pedidos.id', 'left'); + $builder->join('presupuestos', 'presupuestos.id = pedidos_linea.presupuesto_id', 'left'); + $builder->join('envios_lineas', 'envios_lineas.pedido_id = pedidos_linea.pedido_id', 'left'); + $builder->join('presupuesto_direcciones', 'presupuesto_direcciones.id = envios_lineas.presupuesto_direcciones_id', 'left'); + + $builder->groupBy('pedidos_linea.id'); + $builder->having('IFNULL(SUM(envios_lineas.unidades_envio), 0) < cantidad_linea', null, false); + $builder->where('pedidos.estado', 'finalizado'); + $builder->where('presupuesto_direcciones.direccion', $direccion); + + return $builder; - if($lineasAlbaran == 0){ - return [ - 'status' => false, - 'message' => lang('Logistica.errors.noAlbaranes'), - ]; - } - if($lineasAlbaran > 1){ - $multienvio = true; - } - if(!$multienvio){ + } + + + + } + + /*$builder->select([ + 'pedidos.id as pedido_id', + 'pedidos_linea.id as linea_id', + 'pedidos_linea.cantidad as total_unidades', + 'IFNULL(( + SELECT SUM(t_sub.unidades_envio) + FROM " . envios_lineas . " t_sub + JOIN envios e ON e.id = t_sub.envio_id + WHERE e.finalizado = 1 + AND t_sub.pedido_id = t1.pedido_id + AND t_sub.presupuesto_direcciones_id = t1.presupuesto_direcciones_id + ), 0) as unidades_enviadas', + 'cantidad_linea - IFNULL(SUM(envios_lineas.unidades_envio), 0) as unidades_envio', + 'presupuestos.id as presupuesto_id', + ]); + + $builder->join('pedidos_linea', 'pedidos_linea.pedido_id = pedidos.id', 'left'); + $builder->join('presupuestos', 'presupuestos.id = pedidos_linea.presupuesto_id', 'left'); + $builder->join('envios_lineas', 'envios_lineas.pedido_id = pedidos_linea.pedido_id', 'left'); + + $builder->groupBy('pedidos_linea.id'); + $builder->having('IFNULL(SUM(envios_lineas.unidades_envio), 0) < cantidad_linea', null, false); + $builder->where('pedidos.estado', 'finalizado'); + + $result = $builder->get()->getResult(); + */ + + + private static function generateEnvio($pedido_id, $multienvio = false) + { + + $presupuestoDireccionesModel = model('App\Models\Presupuestos\PresupuestoDireccionesModel'); + + if (!$multienvio) { // solo hay una dirección, se obtiene de los albaranes - - $datosEnvio = $AlbaranModel - ->select('albaranes.att_albaran as att, albaranes.direccion_albaran as direccion, - presupuesto_direcciones.provincia as ciudad, presupuesto_direcciones.cp as cp, presupuesto_direcciones.telefono as telefono, presupuesto_direcciones.email as email, - presupuesto_direcciones.pais_id as pais_id, albaranes_lineas.cantidad as cantidad, albaranes_lineas.cajas as cajas') - ->where('albaranes.pedido_id', $pedido_id) - ->where('albaranes_lineas.cajas !=', null) - ->join('albaranes_lineas', 'albaranes_lineas.albaran_id = albaranes.id') - ->join('presupuesto_direcciones', 'presupuesto_direcciones.presupuesto_id = albaranes.presupuesto_id') + + $datosEnvio = $presupuestoDireccionesModel + ->select(' + presupuesto_direcciones.id as presupuesto_direcciones_id, + presupuesto_direcciones.att, + presupuesto_direcciones.direccion, + presupuesto_direcciones.provincia as ciudad, + presupuesto_direcciones.cp, + presupuesto_direcciones.telefono, + presupuesto_direcciones.email, + presupuesto_direcciones.pais_id, + presupuesto_direcciones.cantidad - IFNULL(SUM(envios_lineas.unidades_envio), 0) as cantidad, + presupuesto_direcciones.cantidad as cantidad_total + ') + ->join('pedidos_linea', 'pedidos_linea.presupuesto_id = presupuesto_direcciones.presupuesto_id') + ->join('pedidos', 'pedidos.id = pedidos_linea.pedido_id') + ->join('envios_lineas', 'envios_lineas.pedido_id = pedidos.id AND envios_lineas.presupuesto_direcciones_id = presupuesto_direcciones.id', 'left') + ->where('pedidos.id', $pedido_id) + ->groupBy('presupuesto_direcciones.id') // Necesario por el uso de SUM ->first(); + // se genera un nuevo envio con estos datos $EnvioModel = model('App\Models\Logistica\EnvioModel'); $EnvioModel->set('att', $datosEnvio->att); @@ -124,7 +183,8 @@ class LogisticaService $EnvioModel->set('email', $datosEnvio->email); $EnvioModel->set('pais_id', $datosEnvio->pais_id); $EnvioModel->set('cantidad', $datosEnvio->cantidad); - $EnvioModel->set('cajas', $datosEnvio->cajas); + $EnvioModel->set('cajas', 1); + $EnvioModel->set('multienvio', $multienvio ? 1 : 0); $EnvioModel->set('created_at', date('Y-m-d H:i:s')); $EnvioModel->set('updated_at', date('Y-m-d H:i:s')); $EnvioModel->insert(); @@ -132,18 +192,22 @@ class LogisticaService // se genera la linea de envio $EnvioLineasModel = model('App\Models\Logistica\EnvioLineaModel'); - $EnvioLineasModel->set('envio_id', $idEnvio); - $EnvioLineasModel->set('pedido_id', $pedido_id); - $EnvioLineasModel->set('unidades_envio', $datosEnvio->cantidad); - $EnvioLineasModel->set('unidades_total', $datosEnvio->cantidad); - $EnvioLineasModel->set('cajas', $datosEnvio->cajas); - $EnvioLineasModel->set('unidades_cajas', $datosEnvio->cajas); - $EnvioLineasModel->set('created_at', date('Y-m-d H:i:s')); - $EnvioLineasModel->set('updated_at', date('Y-m-d H:i:s')); - $EnvioLineasModel->set('created_by', auth()->user()->id); - $EnvioLineasModel->set('updated_by', auth()->user()->id); - $EnvioLineasModel->insert(); - + $EnvioLineasModel->save([ + 'envio_id' => $idEnvio, + 'pedido_id' => $pedido_id, + 'unidades_envio' => $datosEnvio->cantidad, + 'unidades_total' => $datosEnvio->cantidad_total, + 'cajas' => 1, + 'unidades_cajas' => 1, + 'created_at' => date('Y-m-d H:i:s'), + 'updated_at' => date('Y-m-d H:i:s'), + 'created_by' => auth()->user()->id, + 'updated_by' => auth()->user()->id, + 'presupuesto_direcciones_id' => (int) $datosEnvio->presupuesto_direcciones_id + ]); + + + return [ 'status' => true, 'data' => [ @@ -154,7 +218,7 @@ class LogisticaService } - if(empty($datosEnvio)){ + if (empty($datosEnvio)) { return [ 'status' => false, 'message' => lang('Logistica.errors.noAddresses'), diff --git a/httpdocs/assets/js/safekat/pages/logistica/envio.js b/httpdocs/assets/js/safekat/pages/logistica/envio.js index 9dcfb3c8..75b25796 100644 --- a/httpdocs/assets/js/safekat/pages/logistica/envio.js +++ b/httpdocs/assets/js/safekat/pages/logistica/envio.js @@ -14,22 +14,9 @@ $(()=>{ if(!response.status){ popErrorAlert(response.message); } - if(response.data && response.data.createAlbaran){ + if(response.data){ - Swal.fire({ - title: 'Atención!', - text: 'El pedido no contenía ningún albarán. Se han añadido automáticamente.', - icon: 'warning', - showCancelButton: false, - confirmButtonColor: '#3085d6', - confirmButtonText: 'Ok', - customClass: { - confirmButton: 'btn btn-primary me-1', - }, - buttonsStyling: false - }).then(() => { - //window.open(`${urlObj.origin}` + '/presupuestoadmin/edit/' + response.id); - }); + window.open(`${urlObj.origin}` + '/logistica/envio/' + response.id); } }, From 15f6d0d675109c9c22f5430c78f1ebe2d8c0ebc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaime=20Jim=C3=A9nez?= Date: Fri, 18 Apr 2025 10:36:06 +0200 Subject: [PATCH 07/16] =?UTF-8?q?voy=20a=20a=C3=B1adir=20grupos=20de=20caj?= =?UTF-8?q?as?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ci4/app/Config/Routes.php | 1 + .../Logistica/LogisticaController.php | 23 ++- ci4/app/Language/es/Logistica.php | 1 + ci4/app/Services/LogisticaService.php | 154 ++++++++++++------ .../js/safekat/pages/logistica/envio.js | 2 +- 5 files changed, 125 insertions(+), 56 deletions(-) diff --git a/ci4/app/Config/Routes.php b/ci4/app/Config/Routes.php index 7b31629b..a139d54e 100644 --- a/ci4/app/Config/Routes.php +++ b/ci4/app/Config/Routes.php @@ -785,6 +785,7 @@ $routes->group('logistica', ['namespace' => 'App\Controllers\Logistica'], functi $routes->get('datatableLineasEnvios/(:num)', 'LogisticaController::datatable_enviosEdit/$1'); $routes->get('envio/(:num)', 'LogisticaController::editEnvio/$1'); $routes->get('selectAddLinea', 'LogisticaController::selectAddEnvioLinea'); + $routes->get('addLineaEnvio', 'LogisticaController::addEnvioLinea'); }); /* diff --git a/ci4/app/Controllers/Logistica/LogisticaController.php b/ci4/app/Controllers/Logistica/LogisticaController.php index 27d101d8..93242261 100644 --- a/ci4/app/Controllers/Logistica/LogisticaController.php +++ b/ci4/app/Controllers/Logistica/LogisticaController.php @@ -80,14 +80,14 @@ class LogisticaController extends BaseController ]; return $this->response->setJSON($result); } - $result = LogisticaService::findPedidoOrISBN($search, $envio_id); + $result = LogisticaService::findPedidoOrISBN($search); return $this->response->setJSON($result); } public function selectAddEnvioLinea(){ if ($this->request->isAJAX()) { - $query = LogisticaService::findLineaEnvio($this->request->getGet('direccion'))->orderBy("nombre", "asc"); + $query = LogisticaService::findLineaEnvioPorEnvio($this->request->getGet('envio'))->orderBy("name", "asc"); if ($this->request->getGet("q")) { $query->groupStart() ->orLike("pedidos.id", $this->request->getGet("q")) @@ -95,7 +95,24 @@ class LogisticaController extends BaseController ->groupEnd(); } - return $this->response->setJSON($query->get()->getResultObject()); + $result = $query->get()->getResultObject(); + + return $this->response->setJSON($result); + } else { + return $this->failUnauthorized('Invalid request', 403); + } + } + + public function addEnvioLinea(){ + + if ($this->request->isAJAX()) { + $pedido_id = $this->request->getGet('pedido_id'); + $envio_id = $this->request->getGet('envio_id'); + $envioModel = model('App\Models\Logistica\EnvioModel'); + $direccion = $envioModel->find($envio_id)->direccion; + + $result = LogisticaService::addLineaEnvio($envio_id, $pedido_id, $direccion); + return $this->response->setJSON($result); } else { return $this->failUnauthorized('Invalid request', 403); } diff --git a/ci4/app/Language/es/Logistica.php b/ci4/app/Language/es/Logistica.php index 501049f3..223ea607 100644 --- a/ci4/app/Language/es/Logistica.php +++ b/ci4/app/Language/es/Logistica.php @@ -12,6 +12,7 @@ return [ 'envioSimpleMultiple' => 'Envío simple/múltiple', 'nuevoEnvio' => 'Nuevo envío', 'buscadorPedidosTitle' => 'Código Pedido o ISBN', + 'buscadorPedidosTitle2' => 'Código Pedido o título', 'listadoEnvios' => 'Listado de envíos', 'idEnvio' => 'ID Envío', 'numeroPedidos' => 'Nº Pedidos', diff --git a/ci4/app/Services/LogisticaService.php b/ci4/app/Services/LogisticaService.php index e219e765..2e24af50 100644 --- a/ci4/app/Services/LogisticaService.php +++ b/ci4/app/Services/LogisticaService.php @@ -83,65 +83,113 @@ class LogisticaService } - public static function findLineaEnvio($direccion){ + public static function findLineaEnvioPorEnvio(int $envio_id) + { + $db = \Config\Database::connect(); + $builder = $db->table('envios e_main'); + + $builder->select(" + CONCAT('[', p.id, '] - ', pr.titulo) AS name, + p.id AS id, + pl.id AS linea_id, + pl.cantidad, + ( + SELECT IFNULL(SUM(el.unidades_envio), 0) + FROM envios_lineas el + JOIN envios e ON e.id = el.envio_id + WHERE el.pedido_id = p.id + AND e.direccion = e_main.direccion + ) AS unidades_enviadas, + (pl.cantidad - ( + SELECT IFNULL(SUM(el2.unidades_envio), 0) + FROM envios_lineas el2 + JOIN envios e2 ON e2.id = el2.envio_id + WHERE el2.pedido_id = p.id + AND e2.direccion = e_main.direccion + )) AS unidades_pendientes + "); + + $builder->join('envios_lineas el_main', 'el_main.envio_id = e_main.id'); + $builder->join('pedidos p', 'p.id = el_main.pedido_id'); + $builder->join('pedidos_linea pl', 'pl.pedido_id = p.id'); + $builder->join('presupuestos pr', 'pr.id = pl.presupuesto_id'); + + $builder->where('p.estado', 'finalizado'); + $builder->where('e_main.id', $envio_id); + + $builder->groupBy('pl.id'); + $builder->having('unidades_enviadas < pl.cantidad', null, false); + $builder->orderBy('name', 'ASC'); + + return $builder; + } + + public static function addLineaEnvio($envio_id = null, $pedido_id = null, $direccion = null) + { $modelPedido = model('App\Models\Pedidos\PedidoModel'); $builder = $modelPedido->builder(); $builder->select(" - CONCAT( - '[' , - pedidos.id, ']', - ' - ', - presupuestos.titulo, - ) as name, - pedidos.id as pedido_id"); - - $builder->join('pedidos_linea', 'pedidos_linea.pedido_id = pedidos.id', 'left'); - $builder->join('presupuestos', 'presupuestos.id = pedidos_linea.presupuesto_id', 'left'); - $builder->join('envios_lineas', 'envios_lineas.pedido_id = pedidos_linea.pedido_id', 'left'); - $builder->join('presupuesto_direcciones', 'presupuesto_direcciones.id = envios_lineas.presupuesto_direcciones_id', 'left'); - - $builder->groupBy('pedidos_linea.id'); - $builder->having('IFNULL(SUM(envios_lineas.unidades_envio), 0) < cantidad_linea', null, false); - $builder->where('pedidos.estado', 'finalizado'); - $builder->where('presupuesto_direcciones.direccion', $direccion); - - return $builder; - - } - - - - } - - /*$builder->select([ - 'pedidos.id as pedido_id', - 'pedidos_linea.id as linea_id', - 'pedidos_linea.cantidad as total_unidades', - 'IFNULL(( - SELECT SUM(t_sub.unidades_envio) - FROM " . envios_lineas . " t_sub - JOIN envios e ON e.id = t_sub.envio_id - WHERE e.finalizado = 1 - AND t_sub.pedido_id = t1.pedido_id - AND t_sub.presupuesto_direcciones_id = t1.presupuesto_direcciones_id - ), 0) as unidades_enviadas', - 'cantidad_linea - IFNULL(SUM(envios_lineas.unidades_envio), 0) as unidades_envio', - 'presupuestos.id as presupuesto_id', - ]); + pedidos.id as pedido_id, + pedidos_linea.id as linea_id, + pedidos_linea.cantidad as total_unidades, + ( + SELECT IFNULL(SUM(el.unidades_envio), 0) + FROM envios_lineas el + JOIN envios e ON e.id = el.envio_id + WHERE el.pedido_id = pedidos.id + AND e.finalizado = 1 + AND TRIM(e.direccion) = '" . addslashes(trim($direccion)) . "' + ) as unidades_enviadas, + pedidos_linea.cantidad - IFNULL(SUM(envios_lineas.unidades_envio), 0) as unidades_envio, + presupuestos.id as presupuesto_id + "); $builder->join('pedidos_linea', 'pedidos_linea.pedido_id = pedidos.id', 'left'); $builder->join('presupuestos', 'presupuestos.id = pedidos_linea.presupuesto_id', 'left'); $builder->join('envios_lineas', 'envios_lineas.pedido_id = pedidos_linea.pedido_id', 'left'); $builder->groupBy('pedidos_linea.id'); - $builder->having('IFNULL(SUM(envios_lineas.unidades_envio), 0) < cantidad_linea', null, false); + $builder->having('IFNULL(SUM(envios_lineas.unidades_envio), 0) < pedidos_linea.cantidad', null, false); $builder->where('pedidos.estado', 'finalizado'); + $builder->where('pedidos.id', $pedido_id); + + $result = $builder->get()->getResultObject(); + + if (empty($result)) { + return [ + 'status' => false, + 'message' => lang('Logistica.errors.notFound'), + ]; + } else { + $EnvioLineasModel = model('App\Models\Logistica\EnvioLineaModel'); + $EnvioLineasModel->save([ + 'envio_id' => $envio_id, + 'pedido_id' => $result[0]->pedido_id, + 'unidades_envio' => $result[0]->unidades_envio, + 'unidades_total' => $result[0]->total_unidades, + 'cajas' => 1, + 'unidades_cajas' => 1, + 'created_at' => date('Y-m-d H:i:s'), + 'updated_at' => date('Y-m-d H:i:s'), + 'created_by' => auth()->user()->id, + 'updated_by' => auth()->user()->id, + 'presupuesto_id' => $result[0]->presupuesto_id, + ]); + } + + return [ + 'status' => true, + 'data' => [ + 'unidades_envio' => $result[0]->unidades_envio, + 'unidades_enviadas' => $result[0]->unidades_enviadas, + 'total_unidades' => $result[0]->total_unidades, + ] + ]; + } - $result = $builder->get()->getResult(); - */ private static function generateEnvio($pedido_id, $multienvio = false) @@ -154,7 +202,7 @@ class LogisticaService $datosEnvio = $presupuestoDireccionesModel ->select(' - presupuesto_direcciones.id as presupuesto_direcciones_id, + presupuestos.id as presupuesto_id, presupuesto_direcciones.att, presupuesto_direcciones.direccion, presupuesto_direcciones.provincia as ciudad, @@ -167,12 +215,14 @@ class LogisticaService ') ->join('pedidos_linea', 'pedidos_linea.presupuesto_id = presupuesto_direcciones.presupuesto_id') ->join('pedidos', 'pedidos.id = pedidos_linea.pedido_id') - ->join('envios_lineas', 'envios_lineas.pedido_id = pedidos.id AND envios_lineas.presupuesto_direcciones_id = presupuesto_direcciones.id', 'left') + ->join('presupuestos', 'pedidos_linea.presupuesto_id = presupuestos.id') + ->join('envios_lineas', 'envios_lineas.pedido_id = pedidos.id', 'left') + ->join('envios', 'envios.id = envios_lineas.envio_id', 'left') ->where('pedidos.id', $pedido_id) ->groupBy('presupuesto_direcciones.id') // Necesario por el uso de SUM ->first(); - + // se genera un nuevo envio con estos datos $EnvioModel = model('App\Models\Logistica\EnvioModel'); $EnvioModel->set('att', $datosEnvio->att); @@ -203,7 +253,7 @@ class LogisticaService 'updated_at' => date('Y-m-d H:i:s'), 'created_by' => auth()->user()->id, 'updated_by' => auth()->user()->id, - 'presupuesto_direcciones_id' => (int) $datosEnvio->presupuesto_direcciones_id + 'presupuesto_id' => (int) $datosEnvio->presupuesto_id ]); @@ -211,9 +261,9 @@ class LogisticaService return [ 'status' => true, 'data' => [ - 'id_envio' => $idEnvio, - 'multienvio' => false, - ], + 'id_envio' => $idEnvio, + 'multienvio' => false, + ], ]; } diff --git a/httpdocs/assets/js/safekat/pages/logistica/envio.js b/httpdocs/assets/js/safekat/pages/logistica/envio.js index 75b25796..0a9d1c27 100644 --- a/httpdocs/assets/js/safekat/pages/logistica/envio.js +++ b/httpdocs/assets/js/safekat/pages/logistica/envio.js @@ -16,7 +16,7 @@ $(()=>{ } if(response.data){ - window.open(`${urlObj.origin}` + '/logistica/envio/' + response.id); + window.open(`${window.location.origin}/logistica/envio/${response.data.id_envio}`); } }, From 0b04e6dabdbfcb50aa814a02865528ee0318888a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaime=20Jim=C3=A9nez?= Date: Fri, 18 Apr 2025 13:38:06 +0200 Subject: [PATCH 08/16] terminada envio lineas --- ci4/app/Config/Routes.php | 4 + .../Logistica/LogisticaController.php | 124 +++- .../2025-04-16-193000_AddEnvioColumns.php | 29 + .../2025-04-18-100000_AddEnviosLineas.php | 41 ++ ci4/app/Entities/Logistica/EnvioEntity.php | 33 + .../Entities/Logistica/EnvioLineaEntity.php | 23 + ci4/app/Language/es/Logistica.php | 1 + ci4/app/Models/Logistica/EnvioLineaModel.php | 77 +++ ci4/app/Models/Logistica/EnvioModel.php | 55 ++ ci4/app/Services/LogisticaService.php | 2 +- .../form/logistica/viewEnvioEditForm.php | 243 +++++++ .../vuexy/form/logistica/viewEnvioForm.php | 97 +++ .../js/safekat/pages/logistica/envioEdit.js | 598 ++++++++++++++++++ httpdocs/themes/vuexy/css/safekat.css | 5 + 14 files changed, 1313 insertions(+), 19 deletions(-) create mode 100644 ci4/app/Database/Migrations/2025-04-16-193000_AddEnvioColumns.php create mode 100644 ci4/app/Database/Migrations/2025-04-18-100000_AddEnviosLineas.php create mode 100644 ci4/app/Entities/Logistica/EnvioEntity.php create mode 100644 ci4/app/Entities/Logistica/EnvioLineaEntity.php create mode 100644 ci4/app/Models/Logistica/EnvioLineaModel.php create mode 100644 ci4/app/Models/Logistica/EnvioModel.php create mode 100644 ci4/app/Views/themes/vuexy/form/logistica/viewEnvioEditForm.php create mode 100644 ci4/app/Views/themes/vuexy/form/logistica/viewEnvioForm.php create mode 100644 httpdocs/assets/js/safekat/pages/logistica/envioEdit.js diff --git a/ci4/app/Config/Routes.php b/ci4/app/Config/Routes.php index a139d54e..f2aa64e6 100644 --- a/ci4/app/Config/Routes.php +++ b/ci4/app/Config/Routes.php @@ -786,6 +786,10 @@ $routes->group('logistica', ['namespace' => 'App\Controllers\Logistica'], functi $routes->get('envio/(:num)', 'LogisticaController::editEnvio/$1'); $routes->get('selectAddLinea', 'LogisticaController::selectAddEnvioLinea'); $routes->get('addLineaEnvio', 'LogisticaController::addEnvioLinea'); + $routes->post('updateCajaLinea', 'LogisticaController::setCajaLinea'); + $routes->post('deleteLineasEnvio', 'LogisticaController::deleteLineas'); + $routes->post('updateUnidadesEnvio', 'LogisticaController::updateUnidadesEnvio'); + $routes->post('updateComentariosEnvio', 'LogisticaController::saveComments'); }); /* diff --git a/ci4/app/Controllers/Logistica/LogisticaController.php b/ci4/app/Controllers/Logistica/LogisticaController.php index 93242261..d9faff2f 100644 --- a/ci4/app/Controllers/Logistica/LogisticaController.php +++ b/ci4/app/Controllers/Logistica/LogisticaController.php @@ -84,26 +84,29 @@ class LogisticaController extends BaseController return $this->response->setJSON($result); } - public function selectAddEnvioLinea(){ + public function selectAddEnvioLinea() + { if ($this->request->isAJAX()) { - $query = LogisticaService::findLineaEnvioPorEnvio($this->request->getGet('envio'))->orderBy("name", "asc"); + $query = LogisticaService::findLineaEnvioPorEnvio($this->request->getGet('envio')); if ($this->request->getGet("q")) { $query->groupStart() - ->orLike("pedidos.id", $this->request->getGet("q")) - ->orLike("presupuestos.titulo", $this->request->getGet("q")) + ->orLike("p.id", $this->request->getGet("q")) + ->orLike("pr.titulo", $this->request->getGet("q")) ->groupEnd(); } - $result = $query->get()->getResultObject(); - + + $result = $query->orderBy("name", "asc")->get()->getResultObject(); + return $this->response->setJSON($result); } else { return $this->failUnauthorized('Invalid request', 403); } } - public function addEnvioLinea(){ + public function addEnvioLinea() + { if ($this->request->isAJAX()) { $pedido_id = $this->request->getGet('pedido_id'); @@ -123,20 +126,20 @@ class LogisticaController extends BaseController $model = model('App\Models\Logistica\EnvioModel'); $q = $model->getDatatableQuery(); - + $result = DataTable::of($q) ->edit( "finalizado", function ($row, $meta) { - if ($row->finalizado == 1) + if ($row->finalizado == 1) return ''; else return ''; } ) ->add("action", callback: function ($q) { - - return ' + + return '
@@ -146,7 +149,8 @@ class LogisticaController extends BaseController return $result->toJson(returnAsObject: true); } - public function editEnvio($id = null){ + public function editEnvio($id = null) + { if (empty($id)) { return redirect()->to(base_url('logistica/selectEnvios/simple'))->with('error', lang('Logistica.errors.noEnvio')); @@ -159,10 +163,11 @@ class LogisticaController extends BaseController if (empty($envioEntity)) { return redirect()->to(base_url('logistica/selectEnvios/simple'))->with('error', lang('Logistica.errors.noEnvio')); } + $envioEntity->nextCaja = model('App\Models\Logistica\EnvioLineaModel')->getMaxCaja(); $viewData = [ 'currentModule' => static::$controllerSlug, - 'boxTitle' => '' . ' '. lang('Logistica.envio') . ' [' . $envioEntity->id . ']: ' . $envioEntity->direccion, + 'boxTitle' => '' . ' ' . lang('Logistica.envio') . ' [' . $envioEntity->id . ']: ' . $envioEntity->direccion, 'usingServerSideDataTable' => true, 'envioEntity' => $envioEntity, ]; @@ -177,15 +182,17 @@ class LogisticaController extends BaseController $model = model('App\Models\Logistica\EnvioLineaModel'); $q = $model->getDatatableQuery($idEnvio); - + $result = DataTable::of($q) - ->add("rowSelected",callback: function ($q) { - return ''; + ->add( + "rowSelected", + callback: function ($q) { + return ''; } ) ->add("action", callback: function ($q) { - - return ' + + return '
@@ -194,4 +201,85 @@ class LogisticaController extends BaseController return $result->toJson(returnAsObject: true); } + + public function setCajaLinea() + { + + if ($this->request->isAJAX()) { + $id = $this->request->getPost('id'); + $caja = $this->request->getPost('caja'); + + + $model = model('App\Models\Logistica\EnvioLineaModel'); + $result = $model->update($id, [ + 'cajas' => $caja, + ]); + return $this->response->setJSON([ + "status" => $result, + ]); + } else { + return $this->failUnauthorized('Invalid request', 403); + } + } + + public function deleteLineas() + { + if ($this->request->isAJAX()) { + $ids = $this->request->getPost('ids'); + $model = model('App\Models\Logistica\EnvioLineaModel'); + $result = $model->delete($ids); + return $this->response->setJSON([ + "status" => $result, + ]); + } else { + return $this->failUnauthorized('Invalid request', 403); + } + } + + public function updateUnidadesEnvio() + { + $id = $this->request->getPost('id'); + $unidades = $this->request->getPost('unidades_envio'); + + if (!$id || !$unidades || intval($unidades) <= 0) { + return $this->response->setJSON([ + 'status' => false, + 'message' => 'Datos inválidos' + ]); + } + + $model = model('App\Models\Logistica\EnvioLineaModel'); + $updated = $model->update($id, [ + 'unidades_envio' => $unidades, + ]); + + return $this->response->setJSON([ + 'status' => $updated, + 'message' => $updated ? 'Actualizado' : 'Error al actualizar' + ]); + } + + public function saveComments() + { + $id = $this->request->getPost('id'); + $comments = $this->request->getPost('comentarios'); + + if (!$id || !$comments) { + return $this->response->setJSON([ + 'status' => false, + 'message' => 'Datos inválidos' + ]); + } + + $model = model('App\Models\Logistica\EnvioModel'); + $updated = $model->update($id, [ + 'comentarios' => $comments, + ]); + + return $this->response->setJSON([ + 'status' => $updated, + 'message' => $updated ? 'Actualizado' : 'Error al actualizar' + ]); + } + } diff --git a/ci4/app/Database/Migrations/2025-04-16-193000_AddEnvioColumns.php b/ci4/app/Database/Migrations/2025-04-16-193000_AddEnvioColumns.php new file mode 100644 index 00000000..039609e1 --- /dev/null +++ b/ci4/app/Database/Migrations/2025-04-16-193000_AddEnvioColumns.php @@ -0,0 +1,29 @@ +forge->addColumn("envios", + ["multienvio" => [ + "type" => "TINYINT", + "unsigned" => true, + "null" => false, + "default" => 0, + ]] + ); + + + } + + public function down() + { + $this->forge->dropColumn("envios", ['multienvio']); + + } +} diff --git a/ci4/app/Database/Migrations/2025-04-18-100000_AddEnviosLineas.php b/ci4/app/Database/Migrations/2025-04-18-100000_AddEnviosLineas.php new file mode 100644 index 00000000..e2ce8bbf --- /dev/null +++ b/ci4/app/Database/Migrations/2025-04-18-100000_AddEnviosLineas.php @@ -0,0 +1,41 @@ +forge->addField([ + 'id' => ['type' => 'INT', 'auto_increment' => true], + 'envio_id' => ['type' => 'INT', 'unsigned' => true], + 'pedido_id' => ['type' => 'INT', 'unsigned' => true], + 'presupuesto_id' => ['type' => 'INT', 'unsigned' => true], + 'unidades_envio' => ['type' => 'INT', 'default' => 0], + 'unidades_total' => ['type' => 'INT', 'default' => 0], + 'cajas' => ['type' => 'INT', 'default' => 0], + 'unidades_cajas' => ['type' => 'INT', 'default' => 0], + 'created_at' => ['type' => 'DATETIME', 'null' => true], + 'updated_at' => ['type' => 'DATETIME', 'null' => true], + 'created_by' => ['type' => 'INT', 'unsigned' => true, 'null' => true], + 'updated_by' => ['type' => 'INT', 'unsigned' => true, 'null' => true], + ]); + + $this->forge->addKey('id', true); // Primary Key + + // Foreign Keys + $this->forge->addForeignKey('presupuesto_id', 'presupuestos', 'id', 'CASCADE', 'CASCADE'); + $this->forge->addForeignKey('pedido_id', 'pedidos', 'id', 'CASCADE', 'CASCADE'); + $this->forge->addForeignKey('created_by', 'users', 'id', 'SET NULL', 'CASCADE'); + $this->forge->addForeignKey('updated_by', 'users', 'id', 'SET NULL', 'CASCADE'); + + $this->forge->createTable('envios_lineas'); + } + + public function down() + { + $this->forge->dropTable('envios_lineas'); + } +} diff --git a/ci4/app/Entities/Logistica/EnvioEntity.php b/ci4/app/Entities/Logistica/EnvioEntity.php new file mode 100644 index 00000000..c35b2271 --- /dev/null +++ b/ci4/app/Entities/Logistica/EnvioEntity.php @@ -0,0 +1,33 @@ + 0, + 'mostrar_precios' => 0, + 'mostrar_iva' => 0, + ]; + + protected $casts = [ + 'id' => 'int', + 'finalizado' => 'boolean', + 'codigo_seguimiento'=> 'string', + 'proveedor_id' => 'int', + 'comentarios' => 'string', + 'att' => 'string', + 'direccion' => 'string', + 'ciudad' => 'string', + 'cp' => 'string', + 'email' => 'string', + 'telefono' => 'string', + 'pais_id' => 'int', + 'mostrar_precios' => 'boolean', + 'mostrar_iva' => 'boolean', + 'created_at' => 'datetime', + 'updated_at' => 'datetime', + ]; +} diff --git a/ci4/app/Entities/Logistica/EnvioLineaEntity.php b/ci4/app/Entities/Logistica/EnvioLineaEntity.php new file mode 100644 index 00000000..bc258aad --- /dev/null +++ b/ci4/app/Entities/Logistica/EnvioLineaEntity.php @@ -0,0 +1,23 @@ + 'int', + 'envio_id' => 'int', + 'pedido_id' => 'int', + 'presupuesto_id' => 'int', + 'unidades_envio' => 'int', + 'unidades_total' => 'int', + 'cajas' => 'int', + 'unidades_cajas' => 'int', + 'created_by' => 'int', + 'updated_by' => 'int', + 'created_at' => 'datetime', + 'updated_at' => 'datetime', + ]; +} diff --git a/ci4/app/Language/es/Logistica.php b/ci4/app/Language/es/Logistica.php index 223ea607..a9cb7db5 100644 --- a/ci4/app/Language/es/Logistica.php +++ b/ci4/app/Language/es/Logistica.php @@ -50,6 +50,7 @@ return [ 'generarAlbaran' => 'Generar albarán', 'imprimirEtiquetas' => 'Imprimir etiquetas', 'buttonsActions' => 'Acciones sobre las filas seleccionadas', + 'addCaja' => 'Añadir caja', 'errors' => [ 'noEnvio' => 'No se ha encontrado el envio', diff --git a/ci4/app/Models/Logistica/EnvioLineaModel.php b/ci4/app/Models/Logistica/EnvioLineaModel.php new file mode 100644 index 00000000..6b31d8d4 --- /dev/null +++ b/ci4/app/Models/Logistica/EnvioLineaModel.php @@ -0,0 +1,77 @@ +db + ->table($this->table . " t1") + ->select( + "t1.id, t1.pedido_id as pedido, t3.id as presupuesto,t1.cajas, + t3.titulo as titulo, t1.unidades_envio as unidadesEnvio, t1.unidades_total as unidadesTotal, + IFNULL(( + SELECT SUM(t_sub.unidades_envio) + FROM " . $this->table . " t_sub + JOIN envios e ON e.id = t_sub.envio_id + JOIN presupuesto_direcciones d ON d.presupuesto_id = t_sub.presupuesto_id + WHERE e.finalizado = 1 + AND t_sub.pedido_id = t1.pedido_id + AND e.direccion = d.direccion COLLATE utf8mb3_general_ci + ), 0) as unidadesEnviadas, + IFNULL(( + SELECT ROUND(SUM(peso) / 1000, 1) + FROM presupuesto_linea + WHERE presupuesto_id = t3.id + ), 0) AS pesoUnidad" + ); + $builder->join("presupuestos t3", "t1.presupuesto_id = t3.id", "left"); + + $builder->where("t1.envio_id", $envio_id); + + return $builder; + } + + public function getMaxCaja() + { + $builder = $this->db + ->table($this->table . " t1"); + $builder->selectMax('CAST(t1.cajas AS UNSIGNED)', 'max_caja'); + $builder->where('t1.cajas IS NOT NULL'); + $query = $builder->get(); + $row = $query->getRow(); + + $maxCaja = is_numeric($row->max_caja) ? (int) $row->max_caja : 0; + + return $maxCaja + 1; + } +} diff --git a/ci4/app/Models/Logistica/EnvioModel.php b/ci4/app/Models/Logistica/EnvioModel.php new file mode 100644 index 00000000..445c4f77 --- /dev/null +++ b/ci4/app/Models/Logistica/EnvioModel.php @@ -0,0 +1,55 @@ +db + ->table($this->table . " t1") + ->select( + "t1.id, GROUP_CONCAT(DISTINCT t2.pedido_id) AS pedidos, + COUNT(t2.id) AS num_lineas, + t1.att, t1.direccion, t1.ciudad, t3.nombre as pais, t1.cp, t1.email, t1.telefono, t1.finalizado" + ); + $builder->join("envios_lineas t2", "t2.envio_id = t1.id", "left"); + $builder->join("lg_paises t3", "t3.id = t1.pais_id", "left"); + + $builder->groupBy("t1.id"); + return $builder; + } +} diff --git a/ci4/app/Services/LogisticaService.php b/ci4/app/Services/LogisticaService.php index 2e24af50..73e6c27d 100644 --- a/ci4/app/Services/LogisticaService.php +++ b/ci4/app/Services/LogisticaService.php @@ -170,7 +170,7 @@ class LogisticaService 'pedido_id' => $result[0]->pedido_id, 'unidades_envio' => $result[0]->unidades_envio, 'unidades_total' => $result[0]->total_unidades, - 'cajas' => 1, + 'cajas' => null, 'unidades_cajas' => 1, 'created_at' => date('Y-m-d H:i:s'), 'updated_at' => date('Y-m-d H:i:s'), diff --git a/ci4/app/Views/themes/vuexy/form/logistica/viewEnvioEditForm.php b/ci4/app/Views/themes/vuexy/form/logistica/viewEnvioEditForm.php new file mode 100644 index 00000000..0684a072 --- /dev/null +++ b/ci4/app/Views/themes/vuexy/form/logistica/viewEnvioEditForm.php @@ -0,0 +1,243 @@ +include("themes/_commonPartialsBs/sweetalert") ?> +include('themes/_commonPartialsBs/datatables') ?> +include("themes/_commonPartialsBs/select2bs5") ?> +extend('themes/vuexy/main/defaultlayout') ?> + + +section('content'); ?> +
+
+
+
+

+
+
+ + + + + + +
+
+

+ +

+ +
+
+
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+
+ +
+
+ + +
+ +
+
+
+ +
+
+
+
+ +
+
+

+ +

+ +
+ +
+
+

+
+
+ +
+
+ + +
+
+ +
+
+ +
+
+
+ + +
+
+

+ +

+ +
+
+
+

+
+
+
+ +
+
+ +
+
+ +
+ +
+ +
+ +
+
+ + + + + + + + + + + + + + + + + + + + +
+ +
+
+
+
+
+ +
+ +
+
+
+endSection() ?> + +section('css') ?> + + + + +endSection() ?> + +section('additionalExternalJs') ?> + + + + + + +endSection() ?> \ No newline at end of file diff --git a/ci4/app/Views/themes/vuexy/form/logistica/viewEnvioForm.php b/ci4/app/Views/themes/vuexy/form/logistica/viewEnvioForm.php new file mode 100644 index 00000000..8aee1d7a --- /dev/null +++ b/ci4/app/Views/themes/vuexy/form/logistica/viewEnvioForm.php @@ -0,0 +1,97 @@ +include("themes/_commonPartialsBs/sweetalert") ?> +include('themes/_commonPartialsBs/datatables') ?> +extend('themes/vuexy/main/defaultlayout') ?> + +section('content'); ?> +
+
+
+
+

+
+
+ + + +
+

+ +

+ +
+
+ +
+ +
+ + +
+ +
+
+
+
+ + +
+

+ +

+ +
+
+ +
+ + + + + + + + + + + + + + + + + + + +
+ + +
+
+
+
+ +
+ +
+
+ +
+
+
+endSection() ?> + + +section('css') ?> + +endSection() ?> + +section('additionalExternalJs') ?> + + +endSection() ?> \ No newline at end of file diff --git a/httpdocs/assets/js/safekat/pages/logistica/envioEdit.js b/httpdocs/assets/js/safekat/pages/logistica/envioEdit.js new file mode 100644 index 00000000..e1e38ea3 --- /dev/null +++ b/httpdocs/assets/js/safekat/pages/logistica/envioEdit.js @@ -0,0 +1,598 @@ +import ClassSelect from '../../components/select2.js'; +import Ajax from '../../components/ajax.js'; + +class EnvioEdit { + + + constructor() { + + this.tableCols = [ + { data: "rowSelected" }, + { data: "cajas", defaultContent: ""}, + { data: "pedido" }, + { data: "presupuesto" }, + { data: "titulo" }, + { data: "unidadesEnvio" }, + { data: "unidadesEnviadas" }, + { data: "unidadesTotal" }, + { data: "action" }, + { data: "id" }, + { data: "pesoUnidad" } + ]; + + this.table = null; + + this.buscarPedidos = new ClassSelect($("#buscadorPedidos"), '/logistica/selectAddLinea', "", true, { 'envio': $("#id").val() }); + + this.contadorCajas = parseInt($("#nextCaja").val()) || 1; + this.btnAddLinea = $("#btnAddLinea"); + this.btnAddCaja = $("#btnAddCaja"); + this.btnDeleteLinea = $("#btnEliminarLineas"); + this.btnGuardarComentarios = $("#guardarComentarios"); + } + + init() { + + this.table = $('#tableLineasEnvio').DataTable({ + processing: true, + serverSide: true, + autoWidth: true, + responsive: true, + scrollX: true, + orderCellsTop: true, + lengthMenu: [5, 10, 25, 50, 75, 100, 250, 500, 1000, 2500], + pageLength: 50, + "dom": 'lrtip', + "ajax": { + "url": "/logistica/datatableLineasEnvios/" + $('#id').val(), + }, + "columns": this.tableCols, + "language": { + url: "/themes/vuexy/vendor/libs/datatables-sk/plugins/i18n/es-ES.json" + }, + rowGroup: { + dataSrc: 'cajas', + startRender: function (rows, group) { + const nombreGrupo = group === null || group === '' || group === 'null' || group.toUpperCase() === 'NO GROUP' + ? 'SIN ASIGNAR' + : group; + let totalUnidades = 0; + let totalPeso = 0; + rows.data().each(function (row) { + const unidades = parseInt(row.unidadesEnvio) || 0; + totalUnidades += unidades; + totalPeso += parseFloat(row.pesoUnidad) * unidades || 0; + }); + + return `CAJA: ${nombreGrupo} [unidades: ${totalUnidades}, peso: ${totalPeso.toFixed(1)} kg]`; + } + }, + "columnDefs": [ + { + "targets": [0, 8], + "className": "text-center", + "orderable": false, + "searchable": false, + }, + { + "targets": [2, 3, 5, 6, 7], + "className": "text-center", + }, + { + targets: [1, 9, 10], + visible: false + } + ], + "order": [[1, "asc"]], + "orderFixed": [ [1, 'asc'] ], + }); + + + $('#tableLineasEnvio').on('draw.dt', () => { + const table = this.table; + + this._aplicarDroppableEnGrupos(table); + + // Aplica draggable a filas si aún no lo tienen + this.table.rows({ page: 'current' }).every(function () { + const $row = $(this.node()); + if (!$row.hasClass('draggable-applied')) { + $row.addClass('draggable-applied'); + $row.draggable({ + helper: 'clone', + revert: 'invalid', + start: () => $row.css('opacity', 0.5), + stop: () => $row.css('opacity', 1) + }); + } + }); + + document.querySelectorAll('.peso-grupo').forEach(el => { + const valor = parseFloat(el.getAttribute('data-valor')) || 0; + + new AutoNumeric(el, valor, { + decimalPlaces: 1, + digitGroupSeparator: ',', + decimalCharacter: '.', + minimumValue: '0', + suffixText: '', + modifyValueOnWheel: false + }); + }); + }); + + $(document).on('click', '.btn-edit', (e) => { + const table = this.table; + const id = $(e.currentTarget).data('id'); + const row = table.row($(e.currentTarget).closest('tr')); + const rowData = row.data(); + + Swal.fire({ + title: 'Editar unidades a enviar', + input: 'number', + inputLabel: `Unidades actuales: ${rowData.unidadesEnvio}`, + inputValue: rowData.unidadesEnvio, + inputAttributes: { + min: 1 + }, + showCancelButton: true, + confirmButtonText: 'Guardar', + cancelButtonText: 'Cancelar', + inputValidator: (value) => { + if (!value || parseInt(value) <= 0) { + return 'Debes ingresar un valor mayor a 0'; + } + }, + customClass: { + confirmButton: 'btn btn-primary me-1', + cancelButton: 'btn btn-secondary' + }, + buttonsStyling: false + }).then((result) => { + if (result.isConfirmed) { + const nuevasUnidades = parseInt(result.value); + + $.post('/logistica/updateUnidadesEnvio', { + id: rowData.id, + unidades_envio: nuevasUnidades + }, function (response) { + if (response.status) { + table.draw(false); + } else { + Swal.fire({ + title: 'Error', + text: response.message, + icon: 'error', + showCancelButton: false, + confirmButtonColor: '#3085d6', + confirmButtonText: 'Ok', + customClass: { + confirmButton: 'btn btn-primary me-1', + }, + buttonsStyling: false + }); + } + }).fail(() => { + Swal.fire({ + title: 'Error', + text: 'No se pudo actualizar el dato.', + icon: 'error', + showCancelButton: false, + confirmButtonColor: '#3085d6', + confirmButtonText: 'Ok', + customClass: { + confirmButton: 'btn btn-primary me-1', + }, + buttonsStyling: false + }); + }); + } + }); + }); + + this.buscarPedidos.init(); + + this.btnAddLinea.on('click', this._addEnvioLinea.bind(this)); + this.btnAddCaja.on('click', this._addCaja.bind(this)); + this.btnDeleteLinea.on('click', this._deleteLineas.bind(this)); + this.btnGuardarComentarios.on('click', () => { + + $.post('/logistica/updateComentariosEnvio', { + id: $('#id').val(), + comentarios: $('#comentarios').val() + }, function (response) { + if (response.status) { + popSuccessAlert('Comentarios guardados correctamente'); + } else { + popErrorAlert(response.message); + } + }).fail((error) => { + popErrorAlert(error.responseJSON.message); + }); + }); + + } + + _deleteLineas() { + const table = this.table; + const selectedRows = table.rows({ page: 'current' }).nodes().filter((node) => { + const checkbox = $(node).find('.checkbox-linea-envio'); + return checkbox.is(':checked'); + }); + const ids = selectedRows.map((node) => { + const rowData = table.row(node).data(); + return rowData.id; + } + ).toArray(); + if (ids.length > 0) { + Swal.fire({ + + title: 'Eliminar líneas de envío', + text: '¿Está seguro de que desea eliminar las líneas seleccionadas?', + icon: 'warning', + showCancelButton: true, + confirmButtonText: 'Sí', + cancelButtonText: 'Cancelar', + customClass: { + confirmButton: 'btn btn-danger me-1', + cancelButton: 'btn btn-secondary' + }, + buttonsStyling: false + }).then((result) => { + if (result.isConfirmed) { + $.post('/logistica/deleteLineasEnvio', { + + ids: ids + }, function (response) { + if (response.status) { + table.draw(false); + } + else { + Swal.fire({ + title: 'Error', + text: response.message, + icon: 'error', + showCancelButton: false, + confirmButtonColor: '#3085d6', + confirmButtonText: 'Ok', + customClass: { + confirmButton: 'btn btn-primary me-1', + }, + buttonsStyling: false + }); + table.ajax.reload(); + } + }).fail(() => { + Swal.fire({ + title: 'Error', + text: 'No se pudo eliminar la línea de envío.', + icon: 'error', + showCancelButton: false, + confirmButtonColor: '#3085d6', + confirmButtonText: 'Ok', + customClass: { + confirmButton: 'btn btn-primary me-1', + }, + buttonsStyling: false + }); + table.ajax.reload(); + }); + } + }); + } else { + Swal.fire({ + title: 'Sin filas seleccionadas', + text: 'Marca al menos una línea para eliminarla.', + icon: 'info', + showCancelButton: false, + confirmButtonColor: '#3085d6', + confirmButtonText: 'Ok', + customClass: { + confirmButton: 'btn btn-primary me-1', + }, + buttonsStyling: false + }); + } + } + + + _addCaja() { + + const table = this.table; + this.contadorCajas = this._calcularSiguienteNumeroCaja(); + const contadorCajas = this.contadorCajas; + let moved = false; + + // Recorremos todas las filas visibles + table.rows({ page: 'current' }).every(function () { + const $row = $(this.node()); + const checkbox = $row.find('.checkbox-linea-envio'); + + if (checkbox.is(':checked')) { + const rowData = this.data(); + + $.post('/logistica/updateCajaLinea', { + id: rowData.id, + caja: contadorCajas + }, function (response) { + if (response.status) { + table.draw(false); + } else { + Swal.fire({ + title: 'Error', + text: response.message, + icon: 'error', + showCancelButton: false, + confirmButtonColor: '#3085d6', + confirmButtonText: 'Ok', + customClass: { + confirmButton: 'btn btn-primary me-1', + }, + buttonsStyling: false + }); + table.ajax.reload(); + } + }).fail(() => { + Swal.fire({ + title: 'Error', + text: 'No se pudo actualizar el grupo.', + icon: 'error', + showCancelButton: false, + confirmButtonColor: '#3085d6', + confirmButtonText: 'Ok', + customClass: { + confirmButton: 'btn btn-primary me-1', + }, + buttonsStyling: false + }); + table.ajax.reload(); + }); + + moved = true; + } + }); + + if (moved) { + table.draw(false); // Redibuja sin cambiar de página + this.contadorCajas++; + } else { + Swal.fire({ + title: 'Sin filas seleccionadas', + text: 'Marca al menos una línea para moverla a una nueva caja.', + icon: 'info', + showCancelButton: false, + confirmButtonColor: '#3085d6', + confirmButtonText: 'Ok', + customClass: { + confirmButton: 'btn btn-primary me-1', + }, + buttonsStyling: false + }); + } + } + + + _aplicarDroppableEnGrupos(table) { + const self = this; + setTimeout(() => { + $('.dtrg-group').each(function () { + const $grupo = $(this); + let nombreGrupo = $grupo.text().toUpperCase().replace('CAJA:', '').trim(); + if (nombreGrupo === 'SIN ASIGNAR') { + nombreGrupo = null; + } + + // Evitar aplicar múltiples veces + if (!$grupo.hasClass('droppable-applied')) { + $grupo.addClass('droppable-applied'); + + $grupo.droppable({ + accept: 'tr:not(.dtrg-group)', + hoverClass: 'table-primary', + drop: function (event, ui) { + + const row = table.row(ui.draggable); + const rowData = row.data(); + + rowData.cajas = nombreGrupo; + row.data(rowData).invalidate(); + + $.post('/logistica/updateCajaLinea', { + id: rowData.id, + caja: nombreGrupo + }, function (response) { + if (response.status) { + self._reordenarCajas(); + + } else { + Swal.fire({ + title: 'Error', + text: response.message, + icon: 'error', + showCancelButton: false, + confirmButtonColor: '#3085d6', + confirmButtonText: 'Ok', + customClass: { + confirmButton: 'btn btn-primary me-1', + }, + buttonsStyling: false + }); + table.ajax.reload(); + } + }).fail(() => { + Swal.fire({ + title: 'Error filas seleccionadas', + text: 'No se pudo actualizar el grupo.', + icon: 'error', + showCancelButton: false, + confirmButtonColor: '#3085d6', + confirmButtonText: 'Ok', + customClass: { + confirmButton: 'btn btn-primary me-1', + }, + buttonsStyling: false + }); + table.ajax.reload(); + }); + } + }); + } + }); + }, 50); // pequeño delay para asegurar que el DOM esté listo + } + + _addEnvioLinea() { + + if(!this.buscarPedidos.getVal()) { + Swal.fire({ + title: 'Atención!', + text: 'Debe seleccionar un pedido antes de añadir una línea de envío.', + icon: 'info', + showCancelButton: false, + confirmButtonColor: '#3085d6', + confirmButtonText: 'Ok', + customClass: { + confirmButton: 'btn btn-primary me-1', + }, + buttonsStyling: false + }); + + return; + } + + new Ajax('/logistica/addLineaEnvio', { + 'envio_id': $('#id').val(), + 'pedido_id': this.buscarPedidos.getVal(), + 'direccion': $("#direccion").val() + }, {}, + (response) => { + if (response.status) { + if (parseInt(response.data.total_unidades) > parseInt(response.data.unidades_envio)) { + const text = `
+ Se ha añadido un nuevo envío parcial:\n +
    +
  • Unidades totales en pedido: {unidadesTotal}
  • +
  • Unidades añadidos: {unidadesEnvio}
  • +
  • Unidades enviadas: {unidadesEnviadas}
  • +
  • Unidades en envíos no finalizados: {unidadesPendientes}
  • +
+
`; + const unidades_pendientes = parseInt(response.data.total_unidades) - + parseInt(response.data.unidades_enviadas) - parseInt(response.data.unidades_envio); + const textFinal = text.replace('{unidadesTotal}', response.data.total_unidades) + .replace('{unidadesEnvio}', response.data.unidades_envio) + .replace('{unidadesEnviadas}', response.data.unidades_enviadas) + .replace('{unidadesPendientes}', unidades_pendientes); + Swal.fire({ + title: 'Atención!', + html: textFinal, + icon: 'info', + showCancelButton: false, + confirmButtonColor: '#3085d6', + confirmButtonText: 'Ok', + customClass: { + confirmButton: 'btn btn-primary me-1', + }, + buttonsStyling: false + }); + } + this.table.draw(); + this.buscarPedidos.empty(); + } else { + Swal.fire({ + title: 'Atención!', + text: response.message, + icon: 'info', + showCancelButton: false, + confirmButtonColor: '#3085d6', + confirmButtonText: 'Ok', + customClass: { + confirmButton: 'btn btn-primary me-1', + }, + buttonsStyling: false + }); + } + }, (error) => { + console.error(error); + }).get(); + } + + + _calcularSiguienteNumeroCaja() { + const cajasUsadas = new Set(); + + this.table.rows().every(function () { + const data = this.data(); + const caja = data.cajas; + + if (caja !== null && caja !== '' && !isNaN(parseInt(caja))) { + cajasUsadas.add(parseInt(caja)); + } + }); + + // Buscar el menor número libre empezando desde 1 + let i = 1; + while (cajasUsadas.has(i)) { + i++; + } + + return i; + } + + _reordenarCajas() { + const table = this.table; + const mapaOriginalANuevo = {}; + const cajasDetectadas = []; + + // 1. Recolectar cajas distintas en orden + table.rows().every(function () { + const data = this.data(); + const caja = data.cajas; + + if (caja !== null && caja !== '' && !isNaN(parseInt(caja))) { + const cajaNum = parseInt(caja); + if (!cajasDetectadas.includes(cajaNum)) { + cajasDetectadas.push(cajaNum); + } + } + }); + + cajasDetectadas.sort((a, b) => a - b); + + // 2. Construir mapa de renumeración + cajasDetectadas.forEach((valorOriginal, idx) => { + mapaOriginalANuevo[valorOriginal] = idx + 1; + }); + + // 3. Aplicar cambios si hace falta + table.rows().every(function () { + const data = this.data(); + const original = parseInt(data.cajas); + const nuevo = mapaOriginalANuevo[original]; + + if (original !== nuevo) { + data.cajas = nuevo; + + // Persistir en backend + $.post('/logistica/updateCajaLinea', { + id: data.id, + caja: nuevo + }); + + this.data(data).invalidate(); + } + }); + + // 4. Actualizar contador interno + this.contadorCajas = cajasDetectadas.length + 1; + + table.draw(false); + } + +} + +document.addEventListener('DOMContentLoaded', function () { + new EnvioEdit().init(); +}); + +export default EnvioEdit; \ No newline at end of file diff --git a/httpdocs/themes/vuexy/css/safekat.css b/httpdocs/themes/vuexy/css/safekat.css index b72fa913..084a7518 100644 --- a/httpdocs/themes/vuexy/css/safekat.css +++ b/httpdocs/themes/vuexy/css/safekat.css @@ -130,4 +130,9 @@ .beta { color: orangered !important; +} + +.dtrg-group.ui-droppable-hover { + background-color: #d1ecf1 !important; + cursor: move; } \ No newline at end of file From 46c29f3c134b7a0b4e106bc705c54e2fd36f16e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaime=20Jim=C3=A9nez?= Date: Fri, 18 Apr 2025 13:42:45 +0200 Subject: [PATCH 09/16] =?UTF-8?q?a=C3=B1adidos=20links=20al=20pedido=20y?= =?UTF-8?q?=20al=20presupuesto?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/Logistica/LogisticaController.php | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/ci4/app/Controllers/Logistica/LogisticaController.php b/ci4/app/Controllers/Logistica/LogisticaController.php index d9faff2f..32e71498 100644 --- a/ci4/app/Controllers/Logistica/LogisticaController.php +++ b/ci4/app/Controllers/Logistica/LogisticaController.php @@ -197,7 +197,19 @@ class LogisticaController extends BaseController '; - }); + }) + ->edit( + "pedido", + function ($row, $meta) { + return '' . $row->pedido . ''; + } + ) + ->edit( + "presupuesto", + function ($row, $meta) { + return '' . $row->presupuesto . ''; + } + );; return $result->toJson(returnAsObject: true); } From 65c9b34f5600d2e3c1b2f1e567b182bd8266f8c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaime=20Jim=C3=A9nez?= Date: Fri, 18 Apr 2025 13:52:49 +0200 Subject: [PATCH 10/16] =?UTF-8?q?a=C3=B1adido=20switch=20a=20los=20grupos?= =?UTF-8?q?=20para=20seleccionar?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../js/safekat/pages/logistica/envioEdit.js | 79 +++++++++++++++++-- 1 file changed, 71 insertions(+), 8 deletions(-) diff --git a/httpdocs/assets/js/safekat/pages/logistica/envioEdit.js b/httpdocs/assets/js/safekat/pages/logistica/envioEdit.js index e1e38ea3..f9debeb4 100644 --- a/httpdocs/assets/js/safekat/pages/logistica/envioEdit.js +++ b/httpdocs/assets/js/safekat/pages/logistica/envioEdit.js @@ -8,7 +8,7 @@ class EnvioEdit { this.tableCols = [ { data: "rowSelected" }, - { data: "cajas", defaultContent: ""}, + { data: "cajas", defaultContent: "" }, { data: "pedido" }, { data: "presupuesto" }, { data: "titulo" }, @@ -64,7 +64,15 @@ class EnvioEdit { totalPeso += parseFloat(row.pesoUnidad) * unidades || 0; }); - return `CAJA: ${nombreGrupo} [unidades: ${totalUnidades}, peso: ${totalPeso.toFixed(1)} kg]`; + return ` + + `; } }, "columnDefs": [ @@ -84,9 +92,28 @@ class EnvioEdit { } ], "order": [[1, "asc"]], - "orderFixed": [ [1, 'asc'] ], + "orderFixed": [[1, 'asc']], }); + $('#tableLineasEnvio').on('change', '.switch-grupo', function () { + const grupo = $(this).data('grupo'); + const checked = $(this).is(':checked'); + + const table = $('#tableLineasEnvio').DataTable(); + + table.rows().every(function () { + const rowData = this.data(); + const node = $(this.node()); + + const valorCaja = (rowData.cajas === null || rowData.cajas === '' || rowData.cajas === 0 || rowData.cajas === '0') + ? 'SIN ASIGNAR' + : rowData.cajas; + + if (valorCaja == grupo) { + node.find('.checkbox-linea-envio').prop('checked', checked); + } + }); + }); $('#tableLineasEnvio').on('draw.dt', () => { const table = this.table; @@ -119,6 +146,42 @@ class EnvioEdit { modifyValueOnWheel: false }); }); + + $('#tableLineasEnvio').on('change', '.checkbox-linea-envio', function () { + const $row = $(this).closest('tr'); + const table = $('#tableLineasEnvio').DataTable(); + const rowData = table.row($row).data(); + + const valorCaja = (rowData.cajas === null || rowData.cajas === '' || rowData.cajas === 0 || rowData.cajas === '0') + ? 'SIN ASIGNAR' + : rowData.cajas; + + // 1. Filtrar todas las filas del mismo grupo + let total = 0; + let seleccionadas = 0; + + table.rows().every(function () { + const data = this.data(); + const grupo = (data.cajas === null || data.cajas === '' || data.cajas === 0 || data.cajas === '0') + ? 'SIN ASIGNAR' + : data.cajas; + + if (grupo == valorCaja) { + total++; + if ($(this.node()).find('.checkbox-linea-envio').is(':checked')) { + seleccionadas++; + } + } + }); + + // 2. Actualizar el checkbox del grupo + const checkGrupo = $(`.switch-grupo[data-grupo="${valorCaja}"]`); + if (seleccionadas === total) { + checkGrupo.prop('checked', true); + } else { + checkGrupo.prop('checked', false); + } + }); }); $(document).on('click', '.btn-edit', (e) => { @@ -126,7 +189,7 @@ class EnvioEdit { const id = $(e.currentTarget).data('id'); const row = table.row($(e.currentTarget).closest('tr')); const rowData = row.data(); - + Swal.fire({ title: 'Editar unidades a enviar', input: 'number', @@ -151,7 +214,7 @@ class EnvioEdit { }).then((result) => { if (result.isConfirmed) { const nuevasUnidades = parseInt(result.value); - + $.post('/logistica/updateUnidadesEnvio', { id: rowData.id, unidades_envio: nuevasUnidades @@ -188,7 +251,7 @@ class EnvioEdit { }); } }); - }); + }); this.buscarPedidos.init(); @@ -196,7 +259,7 @@ class EnvioEdit { this.btnAddCaja.on('click', this._addCaja.bind(this)); this.btnDeleteLinea.on('click', this._deleteLineas.bind(this)); this.btnGuardarComentarios.on('click', () => { - + $.post('/logistica/updateComentariosEnvio', { id: $('#id').val(), comentarios: $('#comentarios').val() @@ -443,7 +506,7 @@ class EnvioEdit { _addEnvioLinea() { - if(!this.buscarPedidos.getVal()) { + if (!this.buscarPedidos.getVal()) { Swal.fire({ title: 'Atención!', text: 'Debe seleccionar un pedido antes de añadir una línea de envío.', From 61abcb3dbdec6237701b001ebc84193c43027282 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaime=20Jim=C3=A9nez?= Date: Sun, 20 Apr 2025 20:02:14 +0200 Subject: [PATCH 11/16] trabajando en albaranes. Voy a quitar las cajas --- ci4/app/Config/Routes.php | 17 +- .../Logistica/LogisticaController.php | 37 +- ci4/app/Controllers/Pdf/PrintAlbaranes.php | 8 +- ci4/app/Controllers/Pedidos/Albaran.php | 388 --------- ci4/app/Entities/Logistica/EnvioEntity.php | 1 + ci4/app/Entities/Pedidos/AlbaranEntity.php | 46 - .../Entities/Pedidos/AlbaranLineaEntity.php | 40 - ci4/app/Language/es/Logistica.php | 2 + ci4/app/Models/Logistica/EnvioLineaModel.php | 5 +- ci4/app/Models/Logistica/EnvioModel.php | 1 + ci4/app/Models/Pedidos/AlbaranLineaModel.php | 66 -- ci4/app/Models/Pedidos/AlbaranModel.php | 161 ---- ci4/app/Services/LogisticaService.php | 66 +- .../form/logistica/viewEnvioEditForm.php | 76 +- .../vuexy/form/pedidos/_albaranesItems.php | 787 ------------------ .../vuexy/form/pedidos/_lineasItems.php | 2 +- .../vuexy/form/pedidos/viewPedidoForm.php | 3 - .../js/safekat/pages/logistica/envioEdit.js | 293 +++++-- 18 files changed, 345 insertions(+), 1654 deletions(-) delete mode 100644 ci4/app/Controllers/Pedidos/Albaran.php delete mode 100644 ci4/app/Entities/Pedidos/AlbaranEntity.php delete mode 100644 ci4/app/Entities/Pedidos/AlbaranLineaEntity.php delete mode 100644 ci4/app/Models/Pedidos/AlbaranLineaModel.php delete mode 100644 ci4/app/Models/Pedidos/AlbaranModel.php diff --git a/ci4/app/Config/Routes.php b/ci4/app/Config/Routes.php index f2aa64e6..e7f8686b 100644 --- a/ci4/app/Config/Routes.php +++ b/ci4/app/Config/Routes.php @@ -505,15 +505,12 @@ $routes->group('pedidos', ['namespace' => 'App\Controllers\Pedidos'], function ( $routes->resource('pedidos', ['namespace' => 'App\Controllers\Pedidos', 'controller' => 'Pedido', 'except' => 'show,new,create,update']); -$routes->group('albaranes', ['namespace' => 'App\Controllers\Pedidos'], function ($routes) { - $routes->post('add', 'Albaran::add', ['as' => 'crearAlbaranesPedido']); - $routes->post('update/(:any)', 'Albaran::update/$1', ['as' => 'actualizarAlbaran']); - $routes->post('updateLinea/(:any)', 'Albaran::updateLinea/$1', ['as' => 'actualizarLineaAlbaran']); - $routes->post('deletelinea', 'Albaran::borrarlinea', ['as' => 'borrarAlbaranLinea']); - $routes->get('delete/(:any)', 'Albaran::delete/$1', ['as' => 'borrarAlbaran']); - $routes->get('getalbaranes/(:any)', 'Albaran::getAlbaranes/$1', ['as' => 'getAlbaranes']); - $routes->get('nuevalinea/(:any)', 'Albaran::addLinea/$1', ['as' => 'addAlbaranLinea']); - $routes->post('nuevalinea/(:any)', 'Albaran::addLinea/$1', ['as' => 'addIVA']); +$routes->group('albaranes', ['namespace' => 'App\Controllers\Albaranes'], function ($routes) { + $routes->post('generarAlbaran', 'Albaran::generateAlbaran', ['as' => 'generarAlbaran']); + $routes->get('albaranesEnvio', 'Albaran::getAlbaranes'); + $routes->get('datatablesAlbaranLinea', 'Albaran::datatablesLineasAlbaran'); + $routes->post('updateAlbaran', 'Albaran::updateAlbaran'); + $routes->post('borrarAlbaranLinea', 'Albaran::borrarLinea'); }); $routes->resource('albaranes', ['namespace' => 'App\Controllers\Pedidos', 'controller' => 'Albaran', 'except' => 'show,new,create,update']); @@ -788,7 +785,7 @@ $routes->group('logistica', ['namespace' => 'App\Controllers\Logistica'], functi $routes->get('addLineaEnvio', 'LogisticaController::addEnvioLinea'); $routes->post('updateCajaLinea', 'LogisticaController::setCajaLinea'); $routes->post('deleteLineasEnvio', 'LogisticaController::deleteLineas'); - $routes->post('updateUnidadesEnvio', 'LogisticaController::updateUnidadesEnvio'); + $routes->post('updateLineaEnvio', 'LogisticaController::updateLineaEnvio'); $routes->post('updateComentariosEnvio', 'LogisticaController::saveComments'); }); diff --git a/ci4/app/Controllers/Logistica/LogisticaController.php b/ci4/app/Controllers/Logistica/LogisticaController.php index 32e71498..cb03b5a4 100644 --- a/ci4/app/Controllers/Logistica/LogisticaController.php +++ b/ci4/app/Controllers/Logistica/LogisticaController.php @@ -164,7 +164,7 @@ class LogisticaController extends BaseController return redirect()->to(base_url('logistica/selectEnvios/simple'))->with('error', lang('Logistica.errors.noEnvio')); } $envioEntity->nextCaja = model('App\Models\Logistica\EnvioLineaModel')->getMaxCaja(); - + $viewData = [ 'currentModule' => static::$controllerSlug, 'boxTitle' => '' . ' ' . lang('Logistica.envio') . ' [' . $envioEntity->id . ']: ' . $envioEntity->direccion, @@ -190,14 +190,6 @@ class LogisticaController extends BaseController return ''; } ) - ->add("action", callback: function ($q) { - - return ' -
- -
- '; - }) ->edit( "pedido", function ($row, $meta) { @@ -209,7 +201,23 @@ class LogisticaController extends BaseController function ($row, $meta) { return '' . $row->presupuesto . ''; } - );; + ) + ->edit( + "cajas", + function ($row, $meta) { + return ''; + } + )->edit( + "unidadesEnvio", + function ($row, $meta) { + return ''; + } + ) + ->edit('cajasRaw', function ($row) { + return is_null($row->cajas) ? '__SIN__ASIGNAR__' : $row->cajas; + }); return $result->toJson(returnAsObject: true); } @@ -248,12 +256,13 @@ class LogisticaController extends BaseController } } - public function updateUnidadesEnvio() + public function updateLineaEnvio() { $id = $this->request->getPost('id'); - $unidades = $this->request->getPost('unidades_envio'); + $fieldName = $this->request->getPost('name'); + $fieldValue = $this->request->getPost('value'); - if (!$id || !$unidades || intval($unidades) <= 0) { + if (!$id || !$fieldName || ($fieldName=='unidades_envio' && !$fieldValue)) { return $this->response->setJSON([ 'status' => false, 'message' => 'Datos inválidos' @@ -262,7 +271,7 @@ class LogisticaController extends BaseController $model = model('App\Models\Logistica\EnvioLineaModel'); $updated = $model->update($id, [ - 'unidades_envio' => $unidades, + "" . $fieldName => $fieldValue==""? null: $fieldValue, ]); return $this->response->setJSON([ diff --git a/ci4/app/Controllers/Pdf/PrintAlbaranes.php b/ci4/app/Controllers/Pdf/PrintAlbaranes.php index 506d9114..f5d88265 100644 --- a/ci4/app/Controllers/Pdf/PrintAlbaranes.php +++ b/ci4/app/Controllers/Pdf/PrintAlbaranes.php @@ -11,8 +11,8 @@ class PrintAlbaranes extends BaseController public function index($albaran_id) { - $albaranModel = model('App\Models\Pedidos\AlbaranModel'); - $lineasAlbaranModel = model('App\Models\Pedidos\AlbaranLineaModel'); + $albaranModel = model('App\Models\Albaranes\AlbaranModel'); + $lineasAlbaranModel = model('App\Models\Albaranes\AlbaranLineaModel'); $data['albaran'] = $albaranModel->getResourceForPdf($albaran_id)->get()->getRow(); $data['albaranLineas'] = $lineasAlbaranModel->getResourceForPdf($albaran_id)->get()->getResultObject(); @@ -25,8 +25,8 @@ class PrintAlbaranes extends BaseController { // Cargar modelos - $albaranModel = model('App\Models\Pedidos\AlbaranModel'); - $lineasAlbaranModel = model('App\Models\Pedidos\AlbaranLineaModel'); + $albaranModel = model('App\Models\Albaranes\AlbaranModel'); + $lineasAlbaranModel = model('App\Models\Albaranes\AlbaranLineaModel'); // Informacion del presupuesto $data['albaran'] = $albaranModel->getResourceForPdf($albaran_id)->get()->getRow(); diff --git a/ci4/app/Controllers/Pedidos/Albaran.php b/ci4/app/Controllers/Pedidos/Albaran.php deleted file mode 100644 index f5af3504..00000000 --- a/ci4/app/Controllers/Pedidos/Albaran.php +++ /dev/null @@ -1,388 +0,0 @@ -request->isAJAX()) { - - $newTokenHash = csrf_hash(); - $csrfTokenName = csrf_token(); - - $model_linea = model('App\Models\Pedidos\AlbaranLineaModel'); - $model_linea->where('albaran_id', $id)->delete(); - - $this->model->where('id', $id)->delete(); - - $data = [ - 'error' => 0, - $csrfTokenName => $newTokenHash - ]; - return $this->respond($data); - } - else { - return $this->failUnauthorized('Invalid request', 403); - } - } - - public function addLinea($albaran_id){ - - if ($this->request->isAJAX()) { - - $model_linea = model('App\Models\Pedidos\AlbaranLineaModel'); - $newTokenHash = csrf_hash(); - $csrfTokenName = csrf_token(); - - // si es un post, es el iva - if($this->request->getPost()){ - $reqData = $this->request->getPost(); - $albaran_id = $reqData['albaran_id'] ?? 0; - - $albaran = $this->model->find($albaran_id); - if($albaran == false){ - $data = [ - 'error' => 'Albaran no encontrado', - $csrfTokenName => $newTokenHash - ]; - return $this->respond($data); - } - $presupuesto_model = model('App\Models\Presupuestos\PresupuestoModel'); - $presupuesto = $presupuesto_model->find($albaran->presupuesto_id); - if($presupuesto == false){ - $data = [ - 'error' => 'Presupuesto no encontrado', - $csrfTokenName => $newTokenHash - ]; - return $this->respond($data); - } - $iva_reducido = $presupuesto->iva_reducido; - $lineas = $model_linea->where('albaran_id', $albaran_id)->findAll(); - $total = 0; - foreach($lineas as $linea){ - $total += $linea->total; - } - $iva = $iva_reducido? $total * 4.0 / 100: $total * 21.0 / 100; - $data_linea= [ - 'albaran_id' => $albaran_id, - 'titulo' => $iva_reducido?lang('Pedidos.iva4'):lang('Pedidos.iva21'), - 'cantidad' => 1, - 'precio_unidad' => round($iva,2), - 'total' => round($iva,2), - 'user_created_id' => auth()->user()->id, - 'user_updated_id' => auth()->user()->id - ]; - $id_linea = $model_linea->insert($data_linea); - $linea = $model_linea->find($id_linea); - $data = [ - 'error' => 0, - 'data' => $linea, - $csrfTokenName => $newTokenHash - ]; - return $this->respond($data); - } - else{ - $linea = [ - 'albaran_id' => $albaran_id, - 'user_created_id' => auth()->user()->id, - 'user_updated_id' => auth()->user()->id - ]; - $id_linea = $model_linea->insert($linea); - $data = $model_linea->find($id_linea); - - $data = [ - 'error' => 0, - 'data' => $data, - $csrfTokenName => $newTokenHash - ]; - return $this->respond($data); - } - } - else { - return $this->failUnauthorized('Invalid request', 403); - } - } - - public function add() - { - if ($this->request->isAJAX()) { - - $user = auth()->user()->id; - - $newTokenHash = csrf_hash(); - $csrfTokenName = csrf_token(); - - $reqData = $this->request->getPost(); - $pedido_id = $reqData['pedido_id'] ?? 0; - $presupuestos_id = $reqData['presupuestos_id'] ?? 0; - - $return_data = $this->model->generarAlbaranes($pedido_id, $presupuestos_id, $user); - $data = [ - 'data' => $return_data, - $csrfTokenName => $newTokenHash - ]; - - return $this->respond($data); - - } - else { - return $this->failUnauthorized('Invalid request', 403); - } - } - - public function update($id = null){ - - if ($this->request->isAJAX()) { - $newTokenHash = csrf_hash(); - $csrfTokenName = csrf_token(); - - if ($id == null) : - $data = [ - 'error' => 2, - $csrfTokenName => $newTokenHash - ]; - return $this->respond($data); - endif; - $id = filter_var($id, FILTER_SANITIZE_URL); - $albaranEntity = $this->model->find($id); - - if ($albaranEntity == false) : - $message = lang('Basic.global.notFoundWithIdErr', [mb_strtolower(lang('Pedidos.albaran')), $id]); - $data = [ - 'error' => $message, - $csrfTokenName => $newTokenHash - ]; - return $this->respond($data); - endif; - - if ($this->request->getPost()) : - - $nullIfEmpty = true; // !(phpversion() >= '8.1'); - - $postData = $this->request->getPost(); - - $sanitizedData = $this->sanitized($postData, $nullIfEmpty); - - // JJO - $sanitizedData['user_updated_id'] = auth()->user()->id; - - $noException = true; - if ($successfulResult = $this->canValidate()) : // if ($successfulResult = $this->validate($this->formValidationRules) ) : - - if ($this->canValidate()) : - try { - $successfulResult = $this->model->skipValidation(true)->update($id, $sanitizedData); - } catch (\Exception $e) { - $noException = false; - $this->dealWithException($e); - } - else: - $this->viewData['warningMessage'] = lang('Basic.global.formErr1', [mb_strtolower(lang('Pedidos.albaran'))]); - $this->session->setFlashdata('formErrors', $this->model->errors()); - - endif; - - $albaranEntity->fill($sanitizedData); - - endif; - if ($noException && $successfulResult) : - $id = $albaranEntity->id ?? $id; - $message = lang('Basic.global.updateSuccess', [lang('Basic.global.record')]) . '.'; - - $data = [ - 'error' => 0, - $csrfTokenName => $newTokenHash - ]; - return $this->respond($data); - - endif; // $noException && $successfulResult - endif; // ($requestMethod === 'post') - - $data = [ - 'error' => 1, - $csrfTokenName => $newTokenHash - ]; - return $this->respond($data); - } - else { - return $this->failUnauthorized('Invalid request', 403); - } - } - - - public function updateLinea($id = null){ - - if ($this->request->isAJAX()) { - - $model_linea = model('App\Models\Pedidos\AlbaranLineaModel'); - $newTokenHash = csrf_hash(); - $csrfTokenName = csrf_token(); - - if ($id == null) : - $data = [ - 'error' => 2, - $csrfTokenName => $newTokenHash - ]; - return $this->respond($data); - endif; - $id = filter_var($id, FILTER_SANITIZE_URL); - $albaranEntity = $model_linea->find($id); - - if ($albaranEntity == false) : - $message = lang('Basic.global.notFoundWithIdErr', [mb_strtolower(lang('Pedidos.albaran')), $id]); - $data = [ - 'error' => $message, - $csrfTokenName => $newTokenHash - ]; - return $this->respond($data); - endif; - - if ($this->request->getPost()) : - - $nullIfEmpty = true; // !(phpversion() >= '8.1'); - - $postData = $this->request->getPost(); - - $sanitizedData = $this->sanitized($postData, $nullIfEmpty); - - // JJO - $sanitizedData['user_updated_id'] = auth()->user()->id; - - $noException = true; - if ($successfulResult = $this->canValidate()) : // if ($successfulResult = $this->validate($this->formValidationRules) ) : - - if ($this->canValidate()) : - try { - $successfulResult = $model_linea->skipValidation(true)->update($id, $sanitizedData); - } catch (\Exception $e) { - $noException = false; - $this->dealWithException($e); - } - else: - $this->viewData['warningMessage'] = lang('Basic.global.formErr1', [mb_strtolower(lang('Pedidos.albaran'))]); - $this->session->setFlashdata('formErrors', $model_linea->errors()); - - endif; - - $albaranEntity->fill($sanitizedData); - - endif; - if ($noException && $successfulResult) : - $id = $albaranEntity->id ?? $id; - $message = lang('Basic.global.updateSuccess', [lang('Basic.global.record')]) . '.'; - - $data = [ - 'error' => 0, - $csrfTokenName => $newTokenHash - ]; - return $this->respond($data); - - endif; // $noException && $successfulResult - endif; // ($requestMethod === 'post') - - $data = [ - 'error' => 1, - $csrfTokenName => $newTokenHash - ]; - return $this->respond($data); - } - else { - return $this->failUnauthorized('Invalid request', 403); - } - } - - public function borrarLinea(){ - if ($this->request->isAJAX()) { - - $model_linea = model('App\Models\Pedidos\AlbaranLineaModel'); - $newTokenHash = csrf_hash(); - $csrfTokenName = csrf_token(); - - $reqData = $this->request->getPost(); - $id = $reqData['id'] ?? 0; - $id = filter_var($id, FILTER_SANITIZE_URL); - $albaranLineaEntity = $model_linea->find($id); - - if ($albaranLineaEntity == false) : - $message = lang('Basic.global.notFoundWithIdErr', [mb_strtolower(lang('Pedidos.albaran')), $id]); - $message = lang('Basic.global.notFoundWithIdErr', [mb_strtolower(lang('Pedidos.albaran')), $id]); - $data = [ - 'error' => $message, - $csrfTokenName => $newTokenHash - ]; - return $this->respond($data); - endif; - - $successfulResult = $model_linea->skipValidation(true)->update($id, ['deleted_at' => date('Y-m-d H:i:s')]); - - if ($successfulResult) : - $data = [ - 'error' => 0, - $csrfTokenName => $newTokenHash - ]; - else: - $data = [ - 'error' => 1, - $csrfTokenName => $newTokenHash - ]; - endif; - return $this->respond($data); - } - else { - return $this->failUnauthorized('Invalid request', 403); - } - } - - public function getAlbaranes($pedido_id = null){ - if ($this->request->isAJAX()) { - - $model_linea = model('App\Models\Pedidos\AlbaranLineaModel'); - $newTokenHash = csrf_hash(); - $csrfTokenName = csrf_token(); - - $returnData = []; - $albaranes = $this->model->asArray()->where('pedido_id', $pedido_id)->findAll(); - - foreach($albaranes as $albaran){ - $albaran['fecha_albaran'] = $albaran['updated_at']; - array_push($returnData, - [ - 'albaran' => $albaran, - 'lineas' => $model_linea->asArray()->where('albaran_id', $albaran['id'])->findAll()] - ); - } - - $data = [ - 'data' => $returnData, - $csrfTokenName => $newTokenHash - ]; - return $this->respond($data); - } - else { - return $this->failUnauthorized('Invalid request', 403); - } - } -} - \ No newline at end of file diff --git a/ci4/app/Entities/Logistica/EnvioEntity.php b/ci4/app/Entities/Logistica/EnvioEntity.php index c35b2271..5ff38b95 100644 --- a/ci4/app/Entities/Logistica/EnvioEntity.php +++ b/ci4/app/Entities/Logistica/EnvioEntity.php @@ -17,6 +17,7 @@ class EnvioEntity extends Entity 'finalizado' => 'boolean', 'codigo_seguimiento'=> 'string', 'proveedor_id' => 'int', + 'cliente_id' => 'int', 'comentarios' => 'string', 'att' => 'string', 'direccion' => 'string', diff --git a/ci4/app/Entities/Pedidos/AlbaranEntity.php b/ci4/app/Entities/Pedidos/AlbaranEntity.php deleted file mode 100644 index bdff8334..00000000 --- a/ci4/app/Entities/Pedidos/AlbaranEntity.php +++ /dev/null @@ -1,46 +0,0 @@ - null, - 'pedido_id' => null, - 'presupuesto_id' => null, - 'presupuesto_direccion_id' => null, - 'cliente_id' => null, - 'serie_id' => null, - 'numero_albaran' => null, - 'mostrar_precios' => null, - 'total' => null, - 'direccion_albaran' => null, - 'att_albaran' => null, - 'user_created_id' => null, - 'user_updated_id' => null, - 'created_at' => null, - 'updated_at' => null, - 'deleted_at' => null, - ]; - - protected $dates = ['created_at', 'updated_at', 'deleted_at']; - - protected $casts = [ - 'id' => 'integer', - 'pedido_id' => '?integer', - 'presupuesto_id' => '?integer', - 'presupuesto_direccion_id' => '?integer', - 'cliente_id' => '?integer', - 'serie_id' => '?integer', - 'numero_albaran' => '?string', - 'mostrar_precios' => '?boolean', - 'total' => 'float', - 'direccion_albaran' => '?string', - 'att_albaran' => '?string', - 'user_created_id' => 'integer', - 'user_updated_id' => 'integer', - ]; - - // Agrega tus métodos personalizados aquí -} diff --git a/ci4/app/Entities/Pedidos/AlbaranLineaEntity.php b/ci4/app/Entities/Pedidos/AlbaranLineaEntity.php deleted file mode 100644 index c2137df8..00000000 --- a/ci4/app/Entities/Pedidos/AlbaranLineaEntity.php +++ /dev/null @@ -1,40 +0,0 @@ - null, - 'albaran_id' => null, - 'titulo' => null, - 'isbn' => null, - 'ref_cliente' => null, - 'cantidad' => null, - 'cajas' => null, - 'ejemplares_por_caja' => null, - 'precio_unidad' => null, - 'total' => null, - 'user_created_id' => null, - 'user_updated_id' => null, - 'created_at' => null, - 'updated_at' => null, - 'deleted_at' => null, - ]; - - protected $casts = [ - 'id' => 'integer', - 'albaran_id' => '?integer', - 'titulo' => 'string', - 'isbn' => '?string', - 'ref_cliente' => '?string', - 'cantidad' => '?integer', - 'cajas' => '?integer', - 'ejemplares_por_caja' => '?integer', - 'precio_unidad' => 'float', - 'total' => 'float', - 'user_created_id' => 'integer', - 'user_updated_id' => 'integer', - ]; -} \ No newline at end of file diff --git a/ci4/app/Language/es/Logistica.php b/ci4/app/Language/es/Logistica.php index a9cb7db5..059e1d34 100644 --- a/ci4/app/Language/es/Logistica.php +++ b/ci4/app/Language/es/Logistica.php @@ -51,6 +51,8 @@ return [ 'imprimirEtiquetas' => 'Imprimir etiquetas', 'buttonsActions' => 'Acciones sobre las filas seleccionadas', 'addCaja' => 'Añadir caja', + 'numCaja' => 'Número de caja', + 'selectAll' => 'Seleccionar todo', 'errors' => [ 'noEnvio' => 'No se ha encontrado el envio', diff --git a/ci4/app/Models/Logistica/EnvioLineaModel.php b/ci4/app/Models/Logistica/EnvioLineaModel.php index 6b31d8d4..e642a5fe 100644 --- a/ci4/app/Models/Logistica/EnvioLineaModel.php +++ b/ci4/app/Models/Logistica/EnvioLineaModel.php @@ -37,8 +37,9 @@ class EnvioLineaModel extends Model $builder = $this->db ->table($this->table . " t1") ->select( - "t1.id, t1.pedido_id as pedido, t3.id as presupuesto,t1.cajas, - t3.titulo as titulo, t1.unidades_envio as unidadesEnvio, t1.unidades_total as unidadesTotal, + "t1.id, t1.pedido_id as pedido, t3.id as presupuesto,t1.cajas, t1.cajas as cajasRaw, + t3.titulo as titulo, t1.unidades_envio as unidadesEnvio, t1.unidades_envio as unidadesEnvioRaw, + t1.unidades_total as unidadesTotal, IFNULL(( SELECT SUM(t_sub.unidades_envio) FROM " . $this->table . " t_sub diff --git a/ci4/app/Models/Logistica/EnvioModel.php b/ci4/app/Models/Logistica/EnvioModel.php index 445c4f77..2dbcf385 100644 --- a/ci4/app/Models/Logistica/EnvioModel.php +++ b/ci4/app/Models/Logistica/EnvioModel.php @@ -19,6 +19,7 @@ class EnvioModel extends Model 'codigo_seguimiento', 'proveedor_id', 'comentarios', + 'cliente_id', 'att', 'direccion', 'ciudad', diff --git a/ci4/app/Models/Pedidos/AlbaranLineaModel.php b/ci4/app/Models/Pedidos/AlbaranLineaModel.php deleted file mode 100644 index 9253b2a2..00000000 --- a/ci4/app/Models/Pedidos/AlbaranLineaModel.php +++ /dev/null @@ -1,66 +0,0 @@ -db - - ->table($this->table . " t1") - ->select( - "t1.id AS id, t1.albaran_id AS albaran_id, t1.titulo AS titulo, t1.isbn AS isbn, - t1.ref_cliente AS ref_cliente, t1.cantidad AS cantidad, t1.cajas AS cajas, - t1.ejemplares_por_caja AS ejemplares_por_caja, t1.precio_unidad AS precio_unidad, - t1.total AS total" - ); - - $builder->where("t1.deleted_at IS NULL"); - $builder->where("t1.albaran_id", $albaran_id); - - return $builder; - } - -} \ No newline at end of file diff --git a/ci4/app/Models/Pedidos/AlbaranModel.php b/ci4/app/Models/Pedidos/AlbaranModel.php deleted file mode 100644 index 5ac511e2..00000000 --- a/ci4/app/Models/Pedidos/AlbaranModel.php +++ /dev/null @@ -1,161 +0,0 @@ -find($presupuestos_id); - - $return_data = []; - - foreach ($presupuestos as $presupuesto) { - - $envios = $model_presupuesto_direcciones->where('presupuesto_id', $presupuesto->id)->findAll(); - - foreach($envios as $envio){ - - // se buscan los albaranes en este presupuesto con la misma direccion y con el mismo presupuesto_id en albaran - // en albaran linea para obtener la cantidad total enviada - $model_albaran = model('App\Models\Pedidos\AlbaranModel'); - $model_albaran_linea = model('App\Models\Pedidos\AlbaranLineaModel'); - $albaranes = $model_albaran->where('presupuesto_id', $presupuesto->id) - ->where('presupuesto_direccion_id', $envio->id)->findAll(); - // se suman las cantidades de los albaranes - $cantidad_enviada = 0; - foreach($albaranes as $albaran){ - $lineas = $model_albaran_linea->where('albaran_id', $albaran->id)->findAll(); - foreach($lineas as $linea){ - $cantidad_enviada += $linea->cantidad; - } - } - - if($cantidad_enviada >= intval($envio->cantidad)){ - continue; - } - // calculo precio_unidad - $precio_unidad = $presupuesto->total_aceptado/$presupuesto->tirada; - - $albaran_linea = []; - $albaran_linea = [ - 'titulo' => $presupuesto->titulo, - 'isbn' => $presupuesto->isbn, - 'ref_cliente' => $presupuesto->ref_cliente, - 'cantidad' => intval($envio->cantidad)-$cantidad_enviada, - 'cajas' => 1, - 'ejemplares_por_caja' => intval($envio->cantidad)-$cantidad_enviada, - 'precio_unidad' => $precio_unidad, - 'total' => $precio_unidad * $envio->cantidad, - 'user_created_id' => $user_id, - 'user_updated_id' => $user_id, - ]; - - - $serie = $model_series->find(11); - $numero_albaran = str_replace('{number}', $serie->next, $serie->formato); - $numero_albaran = str_replace( '{year}', date("Y"), $numero_albaran); - - $serie->next = $serie->next + 1; - $model_series->save($serie); - - $albaran = [ - 'pedido_id' => $pedido_id, - 'presupuesto_id' => $presupuesto->id, - 'presupuesto_direccion_id' => $envio->id, - 'cliente_id' => $presupuesto->cliente_id, - 'serie_id' => 11, // Serie de albaranes - 'numero_albaran' => $numero_albaran, - 'mostrar_precios' => 0, - 'total' => $albaran_linea['total'], - 'direccion_albaran' => $envio->direccion, - 'att_albaran' => $envio->att, - 'user_created_id' => $user_id, - 'user_updated_id' => $user_id, - 'fecha_albaran' => date('d/m/Y'), - ]; - - $id_albaran = $this->insert($albaran); - $model_albaran_linea = model('App\Models\Pedidos\AlbaranLineaModel'); - $albaran['id'] = $id_albaran; - $albaran_linea['albaran_id'] = $id_albaran; - $id_albaran_linea =$model_albaran_linea->insert($albaran_linea); - $albaran_linea['id'] = $id_albaran_linea; - - array_push($return_data, ["albaran"=>$albaran, "lineas" =>[$albaran_linea]]); - } - } - - return $return_data; - } - - /** - * Get resource data for creating PDFs. - * - * @param string $search - * - * @return \CodeIgniter\Database\BaseBuilder - */ - public function getResourceForPdf($albaran_id = -1) - { - $builder = $this->db - - ->table($this->table . " t1") - ->select( - "t1.id AS id, t1.pedido_id AS pedido_id, t1.presupuesto_id AS presupuesto_id, - t1.presupuesto_direccion_id AS presupuesto_direccion_id, t1.cliente_id AS cliente_id, - t1.serie_id AS serie_id, t1.numero_albaran AS numero_albaran, t1.mostrar_precios AS mostrar_precios, - t1.total AS total, t1.direccion_albaran AS direccion_albaran, t1.att_albaran AS att_albaran, - t1.user_created_id AS user_created_id, t1.user_updated_id AS user_updated_id, - t1.created_at AS created_at, t1.updated_at AS updated_at, - t2.nombre AS cliente" - ); - $builder->join("clientes t2", "t1.cliente_id = t2.id", "left"); - - $builder->where("t1.deleted_at IS NULL"); - $builder->where("t1.id", $albaran_id); - - return $builder; - } -} \ No newline at end of file diff --git a/ci4/app/Services/LogisticaService.php b/ci4/app/Services/LogisticaService.php index 73e6c27d..3cbab564 100644 --- a/ci4/app/Services/LogisticaService.php +++ b/ci4/app/Services/LogisticaService.php @@ -86,45 +86,51 @@ class LogisticaService public static function findLineaEnvioPorEnvio(int $envio_id) { $db = \Config\Database::connect(); + $subCliente = $db->table('envios') + ->select('cliente_id') + ->where('id', $envio_id) + ->getCompiledSelect(); $builder = $db->table('envios e_main'); $builder->select(" - CONCAT('[', p.id, '] - ', pr.titulo) AS name, - p.id AS id, - pl.id AS linea_id, - pl.cantidad, - ( - SELECT IFNULL(SUM(el.unidades_envio), 0) - FROM envios_lineas el - JOIN envios e ON e.id = el.envio_id - WHERE el.pedido_id = p.id - AND e.direccion = e_main.direccion - ) AS unidades_enviadas, - (pl.cantidad - ( + CONCAT('[', p.id, '] - ', pr.titulo) AS name, + pl.id AS id, + pl.cantidad, + ( + SELECT IFNULL(SUM(el.unidades_envio), 0) + FROM envios_lineas el + JOIN envios e ON e.id = el.envio_id + WHERE el.pedido_id = p.id + AND e.direccion = e_main.direccion + AND pr.cliente_id = ($subCliente) + ) AS unidades_enviadas, + ( + pl.cantidad - ( SELECT IFNULL(SUM(el2.unidades_envio), 0) FROM envios_lineas el2 JOIN envios e2 ON e2.id = el2.envio_id WHERE el2.pedido_id = p.id AND e2.direccion = e_main.direccion - )) AS unidades_pendientes - "); + AND pr.cliente_id = ($subCliente) + ) + ) AS unidades_pendientes + "); - $builder->join('envios_lineas el_main', 'el_main.envio_id = e_main.id'); - $builder->join('pedidos p', 'p.id = el_main.pedido_id'); - $builder->join('pedidos_linea pl', 'pl.pedido_id = p.id'); + $builder->join('pedidos_linea pl', '1=1'); // para incluir líneas sin envío aún + $builder->join('pedidos p', 'p.id = pl.pedido_id'); $builder->join('presupuestos pr', 'pr.id = pl.presupuesto_id'); - - $builder->where('p.estado', 'finalizado'); $builder->where('e_main.id', $envio_id); + $builder->where('p.estado', 'finalizado'); + $builder->where("pr.cliente_id = ($subCliente)", null, false); - $builder->groupBy('pl.id'); - $builder->having('unidades_enviadas < pl.cantidad', null, false); + $builder->having('unidades_pendientes >', 0); $builder->orderBy('name', 'ASC'); return $builder; } + public static function addLineaEnvio($envio_id = null, $pedido_id = null, $direccion = null) { $modelPedido = model('App\Models\Pedidos\PedidoModel'); @@ -183,10 +189,10 @@ class LogisticaService return [ 'status' => true, 'data' => [ - 'unidades_envio' => $result[0]->unidades_envio, - 'unidades_enviadas' => $result[0]->unidades_enviadas, - 'total_unidades' => $result[0]->total_unidades, - ] + 'unidades_envio' => $result[0]->unidades_envio, + 'unidades_enviadas' => $result[0]->unidades_enviadas, + 'total_unidades' => $result[0]->total_unidades, + ] ]; } @@ -211,7 +217,8 @@ class LogisticaService presupuesto_direcciones.email, presupuesto_direcciones.pais_id, presupuesto_direcciones.cantidad - IFNULL(SUM(envios_lineas.unidades_envio), 0) as cantidad, - presupuesto_direcciones.cantidad as cantidad_total + presupuesto_direcciones.cantidad as cantidad_total, + presupuestos.cliente_id as cliente_id ') ->join('pedidos_linea', 'pedidos_linea.presupuesto_id = presupuesto_direcciones.presupuesto_id') ->join('pedidos', 'pedidos.id = pedidos_linea.pedido_id') @@ -225,6 +232,7 @@ class LogisticaService // se genera un nuevo envio con estos datos $EnvioModel = model('App\Models\Logistica\EnvioModel'); + $EnvioModel->set('cliente_id', $datosEnvio->cliente_id); $EnvioModel->set('att', $datosEnvio->att); $EnvioModel->set('direccion', $datosEnvio->direccion); $EnvioModel->set('ciudad', $datosEnvio->ciudad); @@ -261,9 +269,9 @@ class LogisticaService return [ 'status' => true, 'data' => [ - 'id_envio' => $idEnvio, - 'multienvio' => false, - ], + 'id_envio' => $idEnvio, + 'multienvio' => false, + ], ]; } diff --git a/ci4/app/Views/themes/vuexy/form/logistica/viewEnvioEditForm.php b/ci4/app/Views/themes/vuexy/form/logistica/viewEnvioEditForm.php index 0684a072..a8f4d5ce 100644 --- a/ci4/app/Views/themes/vuexy/form/logistica/viewEnvioEditForm.php +++ b/ci4/app/Views/themes/vuexy/form/logistica/viewEnvioEditForm.php @@ -41,7 +41,8 @@ + class="form-control" + value="direccion) ?>">
@@ -95,7 +96,8 @@ + class="form-control" + value="comentarios) ?>">
@@ -119,13 +121,13 @@
-
+

-
+
@@ -159,6 +161,13 @@

+
+ +
@@ -197,12 +206,21 @@ + + + - - - + + + + + + + + + @@ -212,32 +230,54 @@ - +
-
+
+
+

+ +

+ +
+
+ + +
+ +
+
+
+ + +
endSection() ?> section('css') ?> - - - + + + endSection() ?> section('additionalExternalJs') ?> - - - + + + - - + + endSection() ?> \ No newline at end of file diff --git a/ci4/app/Views/themes/vuexy/form/pedidos/_albaranesItems.php b/ci4/app/Views/themes/vuexy/form/pedidos/_albaranesItems.php index 6a5ba19e..e69de29b 100644 --- a/ci4/app/Views/themes/vuexy/form/pedidos/_albaranesItems.php +++ b/ci4/app/Views/themes/vuexy/form/pedidos/_albaranesItems.php @@ -1,787 +0,0 @@ -
- -
-

- -

- -
-
- - -
-
- - -
- -
- - -
-
- -
-
-
-
- - -section('additionalInlineJs') ?> - - - -$('#generar_albaranes').on('click', function(){ - - var lineasPedido = $('#tableOfLineasPedido').DataTable(); - var presupuestos = lineasPedido.column(0).data().unique().toArray(); - - $.ajax({ - url: '', - type: 'POST', - data: { - pedido_id: id ?>, - presupuestos_id: presupuestos, - : v, - }, - success: function(response){ - - if(response.data.length > 0){ - Object.values(response.data).forEach(function(item){ - generarAlbaran(item); - }); - } - cambios_cantidad_albaranes(); - } - }); -}) - -const deleteLineaBtns = function(data) { - return ` - -
- -
- `; -}; - -function generarAlbaran(item){ - - // Crear los elementos necesarios - const accordion = $('
', { - class: 'accordion accordion-bordered mt-3 accordion-albaran', - id: 'accordioAlbaran' + item.albaran.id, - albaran: item.albaran.id - }); - - const card = $('
', { - class: 'card accordion-item active' - }); - - const header = $('

', { - class: 'accordion-header', - id: 'headingAlbaran' + item.albaran.id - }); - - const button = $('