diff --git a/ci4/app/Config/Routes.php b/ci4/app/Config/Routes.php index 8bf72145..a665e363 100644 --- a/ci4/app/Config/Routes.php +++ b/ci4/app/Config/Routes.php @@ -396,6 +396,7 @@ $routes->group('clienteprecios', ['namespace' => 'App\Controllers\Clientes'], fu $routes->post('datatable_editor', 'ClientePrecios::datatable_editor', ['as' => 'editorOfClienteprecios']); $routes->post('changeplantilla', 'ClientePrecios::updatePlantilla', ['as' => 'changePlantillaOfClienteprecios']); $routes->get('getplantilla', 'ClientePrecios::getCurrentPlantilla', ['as' => 'getPlantillaOfClienteprecios']); + $routes->post('update', 'ClientePrecios::updatePlantilla', ['as' => 'updateClienteprecios']); }); $routes->resource('clienteprecios', ['namespace' => 'App\Controllers\Clientes', 'controller' => 'ClientePrecios', 'except' => 'show,new,create,update']); diff --git a/ci4/app/Controllers/Clientes/Clienteplantillaprecios.php b/ci4/app/Controllers/Clientes/Clienteplantillaprecios.php index 0c65fc90..ae43ffee 100755 --- a/ci4/app/Controllers/Clientes/Clienteplantillaprecios.php +++ b/ci4/app/Controllers/Clientes/Clienteplantillaprecios.php @@ -247,6 +247,23 @@ class Clienteplantillaprecios extends \App\Controllers\BaseResourceController } // end function edit(...) + public function updatePlantillaEnCliente(){ + + if ($this->request->isAJAX()) { + + $reqData = $this->request->getPost(); + $plantilla_id = $reqData['plantilla_id'] ?? -1; + + $model = model('App\Models\Clientes\ClientePreciosModel'); + $model->update_plantilla_id($plantilla_id); + + + } else { + return $this->failUnauthorized('Invalid request', 403); + } + } + + public function datatable() { if ($this->request->isAJAX()) { diff --git a/ci4/app/Controllers/Clientes/Clienteplantillaprecioslineas.php b/ci4/app/Controllers/Clientes/Clienteplantillaprecioslineas.php index 83cfd625..4e933a3a 100755 --- a/ci4/app/Controllers/Clientes/Clienteplantillaprecioslineas.php +++ b/ci4/app/Controllers/Clientes/Clienteplantillaprecioslineas.php @@ -134,6 +134,8 @@ class Clienteplantillaprecioslineas extends \App\Controllers\BaseResourceControl Field::inst( 'tipo_maquina' ), Field::inst( 'tipo_impresion' ), Field::inst( 'user_updated_id' ), + Field::inst( 'deleted_at' ), + Field::inst( 'is_deleted' ), Field::inst( 'updated_at' ), Field::inst( 'tiempo_min' ) ->getFormatter( 'Format::toDecimalChar')->setFormatter( 'Format::fromDecimalChar') @@ -197,21 +199,20 @@ class Clienteplantillaprecioslineas extends \App\Controllers\BaseResourceControl } }) ->on('preCreate', function ($editor, &$values) { - $session = session(); $datetime = (new \CodeIgniter\I18n\Time("now")); $editor ->field('user_updated_id') - ->setValue($session->id_user); + ->setValue(auth()->user()->id); $editor ->field('updated_at') ->setValue($datetime->format('Y-m-d H:i:s')); }) ->on('preEdit', function ($editor, &$values) { - $session = session(); + $datetime = (new \CodeIgniter\I18n\Time("now")); $editor ->field('user_updated_id') - ->setValue($session->id_user); + ->setValue(auth()->user()->id); $editor ->field('updated_at') ->setValue($datetime->format('Y-m-d H:i:s')); diff --git a/ci4/app/Models/Clientes/ClientePlantillaPreciosLineasModel.php b/ci4/app/Models/Clientes/ClientePlantillaPreciosLineasModel.php index 9e1b6852..4a948f0e 100755 --- a/ci4/app/Models/Clientes/ClientePlantillaPreciosLineasModel.php +++ b/ci4/app/Models/Clientes/ClientePlantillaPreciosLineasModel.php @@ -160,7 +160,7 @@ class ClientePlantillaPreciosLineasModel extends \App\Models\BaseModel else { $builder->groupStart(); foreach ($search as $col_search) { - if ($col_search[0] > 0 && $col_search[0] < 4) + if ($col_search[1] > 0 && $col_search[0] < 4) $builder->where(self::SORTABLE[$col_search[0]], $col_search[2]); else $builder->like(self::SORTABLE[$col_search[0]], $col_search[2]); diff --git a/ci4/app/Models/Clientes/ClientePreciosModel.php b/ci4/app/Models/Clientes/ClientePreciosModel.php index 953eec5b..5a50ac6a 100755 --- a/ci4/app/Models/Clientes/ClientePreciosModel.php +++ b/ci4/app/Models/Clientes/ClientePreciosModel.php @@ -178,7 +178,6 @@ class ClientePreciosModel extends \App\Models\BaseModel function update_from_plantilla($plantilla_id = 0){ - $session = session(); $datetime = (new \CodeIgniter\I18n\Time("now")); $date_value = $datetime->format('Y-m-d H:i:s'); @@ -187,6 +186,7 @@ class ClientePreciosModel extends \App\Models\BaseModel ->table($this->table . " t1") ->select("t1.cliente_id AS id") ->where('t1.plantilla_id', $plantilla_id) + ->where('t1.is_deleted', 0) ->distinct() ->get()->getResultObject(); @@ -200,7 +200,7 @@ class ClientePreciosModel extends \App\Models\BaseModel // Se cargan los valores de la plantilla $plantillaModel = model('App\Models\Clientes\ClientePlantillaPreciosLineasModel'); - $values = $plantillaModel->getResource($plantilla_id)->get()->getResultObject(); + $values = $plantillaModel->getResource([], $plantilla_id)->get()->getResultObject(); foreach ($values as $value) { $this->db ->table($this->table . " t1") @@ -215,7 +215,7 @@ class ClientePreciosModel extends \App\Models\BaseModel ->set('margen', $value->margen) ->set('user_updated_id', $value->user_updated_id) ->set('updated_at', $value->updated_at) - ->set('user_created_id', $session->id_user) + ->set('user_created_id', auth()->user()->id) ->set('created_at', $date_value) ->insert(); } diff --git a/ci4/app/Views/themes/vuexy/form/clientes/plantillaprecios/viewClienteplantillapreciosForm.php b/ci4/app/Views/themes/vuexy/form/clientes/plantillaprecios/viewClienteplantillapreciosForm.php index 1c161027..5eefbee4 100644 --- a/ci4/app/Views/themes/vuexy/form/clientes/plantillaprecios/viewClienteplantillapreciosForm.php +++ b/ci4/app/Views/themes/vuexy/form/clientes/plantillaprecios/viewClienteplantillapreciosForm.php @@ -42,9 +42,13 @@
- + + diff --git a/httpdocs/assets/js/safekat/components/modalYesNo.js b/httpdocs/assets/js/safekat/components/modalYesNo.js new file mode 100644 index 00000000..2a88cc59 --- /dev/null +++ b/httpdocs/assets/js/safekat/components/modalYesNo.js @@ -0,0 +1,69 @@ +class ModalYesNo { + + constructor(text= "", alias = "") { + + this.modalId = alias !== "" ? `yesNoModal-${alias}`: 'yesNoModal'; + + this.btnCancelId = alias !== "" ? `btnCancelModal-${alias}` : 'btnCancelModal'; + this.btnConfirmId = alias !== "" ? `btnYesModal-${alias}` : 'btnYesModal'; + + this.modalHtml = ` + + `; + } + + init() { + + // Insertar el modal en el body del documento si no existe + if (!document.getElementById(this.modalId)) { + document.body.insertAdjacentHTML('beforeend', this.modalHtml); + } + document.getElementById(this.btnCancelId).addEventListener('click', () => { + const modal = new bootstrap.Modal(document.getElementById(this.modalId)); + modal.hide(); + }); + } + + getModalId() { + return '#' + this.modalId; + } + + // Método para mostrar el modal + show(callback) { + + // Mostrar el modal usando Bootstrap + const modal = new bootstrap.Modal(document.getElementById(this.modalId)); + modal.show(); + + // Configurar el evento de confirmación de eliminación + document.getElementById(this.btnConfirmId).addEventListener('click', () => { + callback(); // Llamar al callback que el usuario haya proporcionado + modal.hide(); // Cerrar el modal + }); + } + + // Método para ocultar el modal si es necesario + hide() { + const modal = new bootstrap.Modal(document.getElementById(this.modalId)); + modal.hide(); + } +} + + +export default ModalYesNo; \ No newline at end of file diff --git a/httpdocs/assets/js/safekat/components/table.js b/httpdocs/assets/js/safekat/components/table.js index af794fe0..4e662ad1 100644 --- a/httpdocs/assets/js/safekat/components/table.js +++ b/httpdocs/assets/js/safekat/components/table.js @@ -49,6 +49,7 @@ let Table = function ( columns.push( { 'data': self.actionBtns.bind(self), // Vincular correctamente el contexto + 'defaultContent': '', 'className': 'row-edit dt-center', } ); @@ -92,7 +93,7 @@ let Table = function ( autoWidth: true, responsive: true, scrollX: true, - stateSave: false, + stateSave: true, lengthMenu: [5, 10, 25, 50, 75, 100, 250, 500, 1000, 2500], order: order, orderCellsTop: true, diff --git a/httpdocs/assets/js/safekat/pages/plantillasTarifasCliente/edit.js b/httpdocs/assets/js/safekat/pages/plantillasTarifasCliente/edit.js index cbd17b78..5fa6071c 100644 --- a/httpdocs/assets/js/safekat/pages/plantillasTarifasCliente/edit.js +++ b/httpdocs/assets/js/safekat/pages/plantillasTarifasCliente/edit.js @@ -1,6 +1,6 @@ import Table from '../../components/table.js'; import TableEditor from '../../components/tableEditor.js'; -import ConfirmDeleteModal from '../../components/ConfirmDeleteModal.js'; +import ModalYesNo from '../../components/modalYesNo.js'; import Ajax from '../../components/ajax.js'; import { getToken } from '../../common/common.js'; @@ -16,15 +16,13 @@ class PlantillasTarifasClienteForm { this.csrf_hash = $('#mainContainer').find('input[name="' + this.csrf_token + '"]').val(); this.btnApply = $('#btnApply'); + this.btnUndo = $('#btnUndo'); this.tablePlantilla = null; - this.deleteModal = null; + this.modalYesNo = null; this.localEditor = null; this.ajaxEditor = null; - - this.changedRows = []; - this.deletedRows = []; } init() { @@ -33,12 +31,17 @@ class PlantillasTarifasClienteForm { this.headerSearcher(); - this.deleteModal = new ConfirmDeleteModal('plantillasTarifasCliente'); - this.deleteModal.init(); + + this.modalYesNo = new ModalYesNo( + "Aplicar los cambios afectarán a TODOS los clientes que tengan asociada esta plantilla de precios.
" + + "¿Esta seguro de que deseas aplicar los cambios?", + ); + this.modalYesNo.init(); + + this.#initEditor(); this.#initTable(); - this.#initEditor(); // Editar en linea la fila this.tablePlantilla.table.on('click', 'tbody span.edit', function (e) { @@ -58,6 +61,37 @@ class PlantillasTarifasClienteForm { } ); }); + + this.tablePlantilla.table.on('click', '.btn-delete-' + this.tablePlantilla.getAlias(), function (e) { + + self.tablePlantilla.table.settings()[0].oFeatures.bServerSide = false; + + const row = $(this).attr('data-id'); + self.btnApply.removeClass('d-none'); + self.btnUndo.removeClass('d-none'); + + $('#' + row).css('background-color', '#ffcccc'); + $('#' + row).addClass('row-deleted'); + + // find closest span.edit + $('#' + row).find('span.edit').addClass('d-none'); + $('#' + row).find('.btn-delete-' + self.tablePlantilla.getAlias()).addClass('d-none'); + }); + + this.btnApply.on('click', function (e) { + self.modalYesNo.show(self.#applyChanges.bind(self)); + }); + + this.btnUndo.on('click', function (e) { + + self.tablePlantilla.table.settings()[0].oFeatures.bServerSide = true; + + self.tablePlantilla.table.clearPipeline(); + self.tablePlantilla.table.draw(); + + self.btnApply.addClass('d-none'); + self.btnUndo.addClass('d-none'); + }); } @@ -86,7 +120,8 @@ class PlantillasTarifasClienteForm { const editorFields = [ { name: "id", - type: "readonly" + type: "readonly", + def: new Date().toISOString().slice(0, 19).replace('T', ' ') }, { name: "tipo", type: "select", @@ -107,7 +142,26 @@ class PlantillasTarifasClienteForm { name: "precio_hora" }, { name: "margen" - }, + }, { + name: "user_updated", + type: "hidden", + def: '' + }, { + name: "updated_at", + type: "hidden", + def: '' + }, { + name: "deleted_at", + type: "hidden", + }, { + name: "is_deleted", + type: "hidden", + }, { + name: "plantilla_id", + type: "hidden", + def: this.plantillaId + } + ]; this.localEditor = new TableEditor( $('#tableOfPlantillasPreciosLineas'), @@ -127,14 +181,42 @@ class PlantillasTarifasClienteForm { this.ajaxEditor.init(); + this.localEditor.editor.on('preCreate', function (e, d, type) { + + self.tablePlantilla.table.settings()[0].oFeatures.bServerSide = false; + + }); + + // add class and change background color of row in postCreate + this.localEditor.editor.on('postCreate', function (e, json, data) { + + const row = self.tablePlantilla.table.row('#' + json.data[0].id); + + let rowNode = row.node(); + + $(rowNode).addClass('row-created'); + $(rowNode).css('background-color', '#C9E2C7'); + + self.btnApply.removeClass('d-none'); + self.btnUndo.removeClass('d-none'); + }); + this.localEditor.editor.on('postEdit', function (e, json, data) { + self.tablePlantilla.table.settings()[0].oFeatures.bServerSide = false; + let row = self.tablePlantilla.table.row('#' + data.id); - + + let rowNode = row.node(); + + // Añadir una clase usando jQuery + if (!$(rowNode).hasClass('row-created')) { + $(rowNode).addClass('row-edited'); + $(rowNode).css('background-color', '#E9DEAC'); + } + if (row.length) { - - let rowData = row.data(); - + // Actualizar los datos de la fila self.tablePlantilla.table.row('#' + data.id).data({ id: data.id, @@ -144,56 +226,199 @@ class PlantillasTarifasClienteForm { tiempo_min: data.tiempo_min, tiempo_max: data.tiempo_max, precio_hora: data.precio_hora, - margen: "150", + margen: data.margen, user_updated_id: data.user_updated, user_updated: data.user_updated, updated_at: data.updated_at - }); + }); - // check if this id exists - if (!self.changedRows.includes(data.id)) - self.changedRows.push(data.id); + self.btnApply.removeClass('d-none'); + self.btnUndo.removeClass('d-none'); } }); - /* - this.editorTarifas.editor.on('preSubmit', function (e, d, type) { - if (type === 'create') { - d.data[0]['cliente_id'] = self.clienteId; - } + this.ajaxEditor.editor.on('preEdit', function (e, d, type) { + self.tablePlantilla.table.settings()[0].oFeatures.bServerSide = true; }); - - this.editorTarifas.editor.on('submitSuccess', function (e, json, data, action) { - - self.tablePlantilla.table.clearPipeline(); - self.tablePlantilla.table.draw(); + + this.ajaxEditor.editor.on('preCreate', function (e, d, type) { + self.tablePlantilla.table.settings()[0].oFeatures.bServerSide = true; }); - - - this.editorTarifas.editor.on('postEdit', function (e, json, data, action) { - self.#borrarPlantillaTarifa(self.clienteId); - self.selectorPlantilla.offChange(); - self.selectorPlantilla.setOption(0, 'Personalizado'); - self.selectorPlantilla.onChange(self.#changePlantilla.bind(this)); - }) - - this.editorTarifas.editor.on('postCreate', function (e, json, data, action) { - self.#borrarPlantillaTarifa(self.clienteId); - self.selectorPlantilla.offChange(); - self.selectorPlantilla.setOption(0, 'Personalizado'); - self.selectorPlantilla.onChange(self.#changePlantilla.bind(this)); - }) - - this.editorTarifas.editor.on('postCancel', function (e, json, data) { - // Restaurar botones de acción por fila - self.tablePlantilla.table.rows().nodes().each(function (node) { - $(node).find('span.edit').removeClass('d-none'); - $(node).find('span.cancel, span.submit').addClass('d-none'); - }); - });*/ } + #applyChanges() { + + const self = this; + + const deletedRows = self.tablePlantilla.table.rows('.row-deleted').data().toArray(); + const editedRows = self.tablePlantilla.table.rows('.row-edited').data().toArray(); + const createdRows = self.tablePlantilla.table.rows('.row-created').data().toArray(); + + if (editedRows.length != 0) { + let error = self.#checkInterval(editedRows); + if (error) { + if (error == 1) { + popErrorAlert('Hay filas EDITADAS con el tiempo mínimo mayor que el tiempo máximo'); + } + else if (error == 2) { + popErrorAlert('Hay filas EDITADAS con intervalos [Tiempo min., Tiempo max] solapados'); + } + return; + } + } + + if (createdRows.length != 0) { + let error = self.#checkInterval(editedRows); + if (error) { + if (error == 1) { + popErrorAlert('Hay filas CREADAS con el tiempo mínimo mayor que el tiempo máximo'); + } + else if (error == 2) { + popErrorAlert('Hay filas CREADAS con intervalos [Tiempo min., Tiempo max] solapados'); + } + return; + } + } + + if (deletedRows.length != 0) { + + let rowIds = deletedRows.map(row => '#' + row.id); + + // Iterar sobre cada fila y actualizar los campos necesarios + self.ajaxEditor.editor + .edit(rowIds, false) // Editar múltiples filas (acepta un array) + .multiSet({ + deleted_at: new Date().toISOString().slice(0, 19).replace('T', ' '), + is_deleted: 1 + }) // Establecer valores comunes para todas las filas + .submit(); + } + + + + if (editedRows.length != 0) { + + let rowIds = editedRows.map(row => '#' + row.id); + let updatedFields = {}; + + // Iterar sobre las filas editadas y construir el objeto actualizado + editedRows.forEach(row => { + + updatedFields['tipo'] = updatedFields['tipo'] || {}; + updatedFields['tipo'][row.id] = row.tipo; + + updatedFields['tipo_maquina'] = updatedFields['tipo_maquina'] || {}; + updatedFields['tipo_maquina'][row.id] = row.tipo_maquina; + + updatedFields['tipo_impresion'] = updatedFields['tipo_impresion'] || {}; + updatedFields['tipo_impresion'][row.id] = row.tipo_impresion; + + updatedFields['tiempo_min'] = updatedFields['tiempo_min'] || {}; + updatedFields['tiempo_min'][row.id] = row.tiempo_min; + + updatedFields['tiempo_max'] = updatedFields['tiempo_max'] || {}; + updatedFields['tiempo_max'][row.id] = row.tiempo_max; + + updatedFields['precio_hora'] = updatedFields['precio_hora'] || {}; + updatedFields['precio_hora'][row.id] = row.precio_hora; + + updatedFields['margen'] = updatedFields['margen'] || {}; + updatedFields['margen'][row.id] = row.margen; + }); + + self.ajaxEditor.editor.edit(rowIds, false).multiSet(updatedFields) + .submit() + } + + + if (createdRows.length != 0) { + + let updatedFields = {}; + + let count = 0; + // Iterar sobre las filas editadas y construir el objeto actualizado + createdRows.forEach(row => { + + updatedFields['id'] = updatedFields['id'] || {}; + updatedFields['id'][row.id] = count; + + updatedFields['tipo'] = updatedFields['tipo'] || {}; + updatedFields['tipo'][count] = row.tipo; + + updatedFields['tipo_maquina'] = updatedFields['tipo_maquina'] || {}; + updatedFields['tipo_maquina'][count] = row.tipo_maquina; + + updatedFields['tipo_impresion'] = updatedFields['tipo_impresion'] || {}; + updatedFields['tipo_impresion'][count] = row.tipo_impresion; + + updatedFields['tiempo_min'] = updatedFields['tiempo_min'] || {}; + updatedFields['tiempo_min'][count] = row.tiempo_min; + + updatedFields['tiempo_max'] = updatedFields['tiempo_max'] || {}; + updatedFields['tiempo_max'][count] = row.tiempo_max; + + updatedFields['precio_hora'] = updatedFields['precio_hora'] || {}; + updatedFields['precio_hora'][count] = row.precio_hora; + + updatedFields['margen'] = updatedFields['margen'] || {}; + updatedFields['margen'][count] = row.margen; + + updatedFields['plantilla_id'] = updatedFields['plantilla_id'] || {}; + updatedFields['plantilla_id'][count] = self.plantillaId; + + count++; + }); + + self.ajaxEditor.editor.create(createdRows.length, false).multiSet(updatedFields) + .submit() + } + + if (deletedRows.length != 0 || editedRows.length != 0 || createdRows.length != 0) { + + new Ajax( + '/clienteprecios/update', + { + [self.csrf_token]: self.csrf_hash, + plantilla_id: self.plantillaId + }, + {}, + () => { + window.location.reload(); + }, + (error) => { + console.log(error); + } + ).post(); + + } + + + } + + #checkInterval(rows) { + + // obtener todas las filas de la tabla que no tengan la clase row-deleted + let rowsNotDeletedDT = this.tablePlantilla.table.rows(':not(.row-deleted)').nodes().toArray(); + for (let row of rowsNotDeletedDT) { + let rowData = this.tablePlantilla.table.row(row).data(); + for (let rowEdited of rows) { + if (rowEdited.tiempo_min > rowEdited.tiempo_max) { + + return 1; + } + if (rowData.tipo == rowEdited.tipo && rowData.tipo_maquina == rowEdited.tipo_maquina && rowData.tipo_impresion == rowEdited.tipo_impresion) { + // check overlapping intervals + if (rowEdited.tiempo_min >= rowData.tiempo_min || rowEdited.tiempo_min <= rowData.tiempo_max) { + return 2; + } + } + } + } + return 0; + + } + #initTable() { const self = this; @@ -252,7 +477,7 @@ class PlantillasTarifasClienteForm { columns, [ { name: 'plantilla_id', value: this.plantillaId } - ],'id' + ], 'id' ); @@ -260,6 +485,8 @@ class PlantillasTarifasClienteForm { actions: actions, colVisibility: false, buttonsExport: true, + buttonNewWithEditor: true, + editor: self.localEditor.editor, });