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 + +
`; + 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