From 4cf4e3fcfdfcd347bd7014923a1264d345f6a948 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaime=20Jim=C3=A9nez?= Date: Fri, 29 Nov 2024 17:06:23 +0100 Subject: [PATCH 1/5] trabajando --- .../assets/js/safekat/pages/cliente/cliente.js | 5 +++++ .../js/safekat/pages/cliente/tarifasCliente.js | 14 ++++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 httpdocs/assets/js/safekat/pages/cliente/tarifasCliente.js diff --git a/httpdocs/assets/js/safekat/pages/cliente/cliente.js b/httpdocs/assets/js/safekat/pages/cliente/cliente.js index fabbe83f..286be4ec 100644 --- a/httpdocs/assets/js/safekat/pages/cliente/cliente.js +++ b/httpdocs/assets/js/safekat/pages/cliente/cliente.js @@ -1,4 +1,5 @@ import ClassSelect from '../../components/select2.js'; +import tarifasClienteView from './tarifasCliente.js'; class Cliente { @@ -7,6 +8,8 @@ class Cliente { this.csrf_token = this.getToken(); this.csrf_hash = $('#clienteForm').find('input[name="' + this.csrf_token + '"]').val(); + this.tarifas = new tarifasClienteView(); + this.pais = new ClassSelect($("#paisId"), '/paises/menuitems2', "Seleccione un país", {[this.csrf_token]: this.csrf_hash}); this.soporte = new ClassSelect($("#soporteId"), '/users/getMenuComerciales', "Seleccione un usuario", {[this.csrf_token]: this.csrf_hash}); this.comercial = new ClassSelect($("#comercialId"), '/users/getMenuComerciales', "Seleccione un usuario", {[this.csrf_token]: this.csrf_hash}); @@ -30,6 +33,8 @@ class Cliente { this.formaPago.init(); this.provincia.init(); this.comunidadAutonoma.init(); + + this.tarifas.init(); $(document).keypress(function (e) { var key = e.which; diff --git a/httpdocs/assets/js/safekat/pages/cliente/tarifasCliente.js b/httpdocs/assets/js/safekat/pages/cliente/tarifasCliente.js new file mode 100644 index 00000000..d6d7a423 --- /dev/null +++ b/httpdocs/assets/js/safekat/pages/cliente/tarifasCliente.js @@ -0,0 +1,14 @@ +import { getToken } from "../../utils/common"; + +class tarifasClienteView{ + + constructor(domItem) { + this.csrf_token = document.querySelector('meta[name="csrf-token"]').content; + this.csrf_hash = document.querySelector('meta[name="csrf-hash"]').content; + this.token = getToken(); + } + + init() { + + } +} \ No newline at end of file From d870fca64d7e9668531f58c79c1e319250d24ca0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaime=20Jim=C3=A9nez?= Date: Sat, 30 Nov 2024 13:59:05 +0100 Subject: [PATCH 2/5] trabajando en el datatable --- ci4/app/Controllers/Language.php | 21 ++++- .../clientes/cliente/_clienteFormItems.php | 8 +- .../js/safekat/pages/cliente/cliente.js | 32 +++---- .../safekat/pages/cliente/tarifasCliente.js | 91 +++++++++++++++++-- 4 files changed, 122 insertions(+), 30 deletions(-) diff --git a/ci4/app/Controllers/Language.php b/ci4/app/Controllers/Language.php index 437f18eb..f9c32e5d 100755 --- a/ci4/app/Controllers/Language.php +++ b/ci4/app/Controllers/Language.php @@ -21,9 +21,22 @@ class Language extends BaseController public function getTranslation() { $translationFile = $this->request->getPost('translationFile'); - $locale = $this->request->getPost('locale'); - $path = "Language/{$locale}/$translationFile.php"; - $lang = require APPPATH.$path; - return json_encode($lang); + $data = []; + if(is_array($translationFile)){ + foreach($translationFile as $file){ + $locale = $this->request->getPost('locale'); + $path = "Language/{$locale}/$file.php"; + $lang = require APPPATH.$path; + $data[$file] = $lang; + } + return json_encode($data); + } + else{ + $locale = $this->request->getPost('locale'); + $path = "Language/{$locale}/$translationFile.php"; + $lang = require APPPATH.$path; + return json_encode($lang); + } + } } diff --git a/ci4/app/Views/themes/vuexy/form/clientes/cliente/_clienteFormItems.php b/ci4/app/Views/themes/vuexy/form/clientes/cliente/_clienteFormItems.php index 3a741867..f66999c1 100644 --- a/ci4/app/Views/themes/vuexy/form/clientes/cliente/_clienteFormItems.php +++ b/ci4/app/Views/themes/vuexy/form/clientes/cliente/_clienteFormItems.php @@ -1046,6 +1046,8 @@ $(document).on('click', '.btn-remove', function(e) { }) }) +/* + var theTablePrecios = $('#tableOfPrecios').DataTable( { serverSide: true, processing: true, @@ -1143,7 +1145,7 @@ $(document).on('click', '.btn-remove', function(e) { } } ] } ); - +*/ const initPrecioTemplate = ; if(initPrecioTemplate != null){ @@ -1151,7 +1153,7 @@ $(document).on('click', '.btn-remove', function(e) { $('#plantillas').append(newOption); } - + /* // Activate an inline edit on click of a table cell $('#tableOfPrecios').on( 'click', 'tbody span.edit', function (e) { editorPrecios.inline( @@ -1165,7 +1167,7 @@ $(document).on('click', '.btn-remove', function(e) { } ); } ); - +*/ // Delete row $(document).on('click', '.btn-delete', function(e) { diff --git a/httpdocs/assets/js/safekat/pages/cliente/cliente.js b/httpdocs/assets/js/safekat/pages/cliente/cliente.js index 286be4ec..0bd83277 100644 --- a/httpdocs/assets/js/safekat/pages/cliente/cliente.js +++ b/httpdocs/assets/js/safekat/pages/cliente/cliente.js @@ -1,14 +1,12 @@ import ClassSelect from '../../components/select2.js'; import tarifasClienteView from './tarifasCliente.js'; +import Ajax from '../../components/ajax.js'; class Cliente { constructor() { - this.csrf_token = this.getToken(); - this.csrf_hash = $('#clienteForm').find('input[name="' + this.csrf_token + '"]').val(); - - this.tarifas = new tarifasClienteView(); + this.tarifas = new tarifasClienteView($('#tarifascliente')); this.pais = new ClassSelect($("#paisId"), '/paises/menuitems2', "Seleccione un país", {[this.csrf_token]: this.csrf_hash}); this.soporte = new ClassSelect($("#soporteId"), '/users/getMenuComerciales', "Seleccione un usuario", {[this.csrf_token]: this.csrf_hash}); @@ -17,7 +15,6 @@ class Cliente { this.provincia = new ClassSelect($("#provinciaId"), '/provincias/menuitems2', "Seleccione una provincia", {[this.csrf_token]: this.csrf_hash}); this.comunidadAutonoma = new ClassSelect($("#comunidadAutonomaId"), '/comunidades-autonomas/menuitems2', "Seleccione una comunidad autónoma", {[this.csrf_token]: this.csrf_hash}); - this.init(); } init() { @@ -54,18 +51,21 @@ class Cliente { }); } - - getToken(){ - - const scriptUrl = new URL(import.meta.url); - const params = new URLSearchParams(scriptUrl.search); - - const paramsObject = Object.fromEntries(params.entries()); - return paramsObject.token; - } } document.addEventListener('DOMContentLoaded', function () { - new Cliente().init(); -}); \ No newline at end of file + + const locale = document.querySelector('meta[name="locale"]').getAttribute('content'); + + new Ajax('/translate/getTranslation', { locale: locale, translationFile: ['ClienteContactos', 'ClientePrecios'] }, {}, + function(translations) { + window.language = JSON.parse(translations); + new Cliente().init(); + }, + function (error) { + console.log("Error getting translations:", error); + } + ).post(); +}); + diff --git a/httpdocs/assets/js/safekat/pages/cliente/tarifasCliente.js b/httpdocs/assets/js/safekat/pages/cliente/tarifasCliente.js index d6d7a423..55d61ad0 100644 --- a/httpdocs/assets/js/safekat/pages/cliente/tarifasCliente.js +++ b/httpdocs/assets/js/safekat/pages/cliente/tarifasCliente.js @@ -1,14 +1,91 @@ -import { getToken } from "../../utils/common"; +import Table from '../../components/table.js'; +import { getToken } from '../../common/common.js'; -class tarifasClienteView{ +class tarifasClienteView { constructor(domItem) { - this.csrf_token = document.querySelector('meta[name="csrf-token"]').content; - this.csrf_hash = document.querySelector('meta[name="csrf-hash"]').content; - this.token = getToken(); + + this.domItem = domItem; + + this.csrf_token = getToken(); + this.csrf_hash = $('#mainContainer').find('input[name="' + this.csrf_token + '"]').val(); + + this.clienteId = window.location.href.split("/").pop(); + this.actions = ['edit', 'delete']; } init() { - + + const self = this; + + const columns = [ + { + 'data': 'tipo', + 'render': function (data, type, row, meta) { + if (data == 'interior') + return window.language.ClientePrecios.interior; + else if (data == 'cubierta') + return window.language.ClientePrecios.cubierta; + else if (data == 'sobrecubierta') + return window.language.ClientePrecios.sobrecubierta; + } + }, + { + 'data': 'tipo_maquina', + 'render': function (data, type, row, meta) { + if (data == 'toner') + return window.language.ClientePrecios.toner; + else if (data == 'inkjet') + return window.language.ClientePrecios.inkjet; + } + }, + { + 'data': 'tipo_impresion', + 'render': function (data, type, row, meta) { + if (data == 'negro') + return window.language.ClientePrecios.negro; + else if (data == 'negrohq') + return window.language.ClientePrecios.negrohq; + else if (data == 'color') + return window.language.ClientePrecios.color; + else if (data == 'colorhq') + return window.language.ClientePrecios.colorhq; + } + }, + { 'data': 'tiempo_min' }, + { 'data': 'tiempo_max' }, + { 'data': 'precio_hora' }, + { 'data': 'margen' }, + { 'data': 'user_updated' }, + { 'data': 'updated_at' }, + { 'data': 'plantilla_id' }, + + ]; + this.tableTarifas = new Table( + $('#tableOfPrecios'), + 'tarifasCliente', + '/clienteprecios/datatable', + columns, + [ + { name: 'cliente_id', value: window.location.href.split("/").pop() }, + { name: this.csrf_token, value: this.csrf_hash }, + ] + ); + + this.tableTarifas.init({ + actions: ['edit', 'delete'], + buttonsNewEditor: true, + + }); + + $('button[data-bs-target="#tarifascliente"]').on('shown.bs.tab', function(event) { + setTimeout(() => { + self.tableTarifas.table.columns.adjust().draw(); + }, 100); // Usamos setTimeout para asegurar que se dibuje después del renderizado + }); } -} \ No newline at end of file + + +} + +export default tarifasClienteView; \ No newline at end of file From 510e33b5fa01b864fe1af9756f2f7859fc26c412 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaime=20Jim=C3=A9nez?= Date: Sun, 1 Dec 2024 20:44:15 +0100 Subject: [PATCH 3/5] trabajando en el editor --- .../Controllers/Clientes/ClientePrecios.php | 8 +- .../Models/Clientes/ClientePreciosModel.php | 17 +- .../clientes/cliente/_clienteFormItems.php | 12 +- .../form/clientes/cliente/viewClienteForm.php | 3 + .../assets/js/safekat/components/table.js | 175 ++++++++++++ .../js/safekat/components/tableEditor.js | 32 +++ .../js/safekat/pages/cliente/cliente.js | 2 + .../safekat/pages/cliente/tarifasCliente.js | 249 +++++++++++++++++- 8 files changed, 481 insertions(+), 17 deletions(-) create mode 100644 httpdocs/assets/js/safekat/components/table.js create mode 100644 httpdocs/assets/js/safekat/components/tableEditor.js diff --git a/ci4/app/Controllers/Clientes/ClientePrecios.php b/ci4/app/Controllers/Clientes/ClientePrecios.php index 2a73ba78..bc258921 100755 --- a/ci4/app/Controllers/Clientes/ClientePrecios.php +++ b/ci4/app/Controllers/Clientes/ClientePrecios.php @@ -108,16 +108,18 @@ class ClientePrecios extends \App\Controllers\BaseResourceController $dir3 = $reqData['order']['2']['dir'] ?? $dir; $dir4= $reqData['order']['3']['dir'] ?? $dir; $dir5= $reqData['order']['4']['dir'] ?? $dir; + + $searchValues = get_filter_datatables_columns($reqData); $cliente_id = $reqData['cliente_id'] ?? 0; - $resourceData = $this->model->getResource($cliente_id) + $resourceData = $this->model->getResource($searchValues, $cliente_id) ->orderBy($order, $dir)->orderBy($order2, $dir2)->orderBy($order3, $dir3)->orderBy($order4, $dir4)->orderBy($order5, $dir5) ->limit($length, $start)->get()->getResultObject(); return $this->respond(Collection::datatable( $resourceData, - $this->model->getResource($cliente_id)->countAllResults(), - $this->model->getResource($cliente_id)->countAllResults() + $this->model->getResource($searchValues, $cliente_id)->countAllResults(), + $this->model->getResource($searchValues, $cliente_id)->countAllResults() )); } else { return $this->failUnauthorized('Invalid request', 403); diff --git a/ci4/app/Models/Clientes/ClientePreciosModel.php b/ci4/app/Models/Clientes/ClientePreciosModel.php index a52893c8..3bfbdb1d 100755 --- a/ci4/app/Models/Clientes/ClientePreciosModel.php +++ b/ci4/app/Models/Clientes/ClientePreciosModel.php @@ -256,7 +256,7 @@ class ClientePreciosModel extends \App\Models\BaseModel * * @return \CodeIgniter\Database\BaseBuilder */ - public function getResource($cliente_id = -1) + public function getResource($search = [], $cliente_id = -1) { $builder = $this->db ->table($this->table . " t1") @@ -271,9 +271,20 @@ class ClientePreciosModel extends \App\Models\BaseModel $builder->where('t1.is_deleted', 0); $builder->where('t1.cliente_id', $cliente_id); - - return $builder; + if (empty($search)) + return $builder; + else { + $builder->groupStart(); + foreach ($search as $col_search) { + if ($col_search[0] > 2) + $builder->like(self::SORTABLE[$col_search[0]], $col_search[2]); + else + $builder->where(self::SORTABLE[$col_search[0]], $col_search[2]); + } + $builder->groupEnd(); + return $builder; + } } diff --git a/ci4/app/Views/themes/vuexy/form/clientes/cliente/_clienteFormItems.php b/ci4/app/Views/themes/vuexy/form/clientes/cliente/_clienteFormItems.php index f66999c1..dc3e7967 100644 --- a/ci4/app/Views/themes/vuexy/form/clientes/cliente/_clienteFormItems.php +++ b/ci4/app/Views/themes/vuexy/form/clientes/cliente/_clienteFormItems.php @@ -591,10 +591,10 @@ - - - plantilla_id - + + + plantilla_id + @@ -924,7 +924,7 @@ $(document).on('click', '.btn-remove', function(e) { `; }; - +/* const tipo_linea = [ {label:'', value:'interior'}, {label:'', value: 'cubierta'}, @@ -1045,7 +1045,7 @@ $(document).on('click', '.btn-remove', function(e) { } }) }) - +*/ /* var theTablePrecios = $('#tableOfPrecios').DataTable( { diff --git a/ci4/app/Views/themes/vuexy/form/clientes/cliente/viewClienteForm.php b/ci4/app/Views/themes/vuexy/form/clientes/cliente/viewClienteForm.php index 9c3eb039..a149252e 100644 --- a/ci4/app/Views/themes/vuexy/form/clientes/cliente/viewClienteForm.php +++ b/ci4/app/Views/themes/vuexy/form/clientes/cliente/viewClienteForm.php @@ -43,5 +43,8 @@ section("additionalExternalJs") ?> + + + endSection() ?> \ No newline at end of file diff --git a/httpdocs/assets/js/safekat/components/table.js b/httpdocs/assets/js/safekat/components/table.js new file mode 100644 index 00000000..83ea0bee --- /dev/null +++ b/httpdocs/assets/js/safekat/components/table.js @@ -0,0 +1,175 @@ +let Table = function ( + domItem, + alias, + url, + columns, + data, + language = "es-ES") { + + this.domItem = domItem; + this.alias = alias; + this.url = url; + this.columns = columns; + this.data = data; + this.language = language; + + this.table = null; + this.actions = []; // Declaración inicial de actions como propiedad + this.deleteModal = null; + + const self = this; + + this.init = function ({ + dom = '<"mt-4"><"float-end"B><"float-start"l><"mt-4 mb-3"p>', + actions = ['view', 'edit', 'delete', 'cancel'], + order = [[0, 'asc']], + deleteModal = null, + buttonsExport = true, + buttonNewWithEditor = false, + editor = null, + booleanColumns = [], + } = {}) { + + this.actions = actions; // Guardar actions como propiedad de la instancia + this.deleteModal = deleteModal; + + const lastColNr = this.domItem.find("tr:first th").length - 1; + + let columnDefs = []; + if (actions.length > 0) { + columnDefs = [ + { + orderable: false, + searchable: false, + targets: [lastColNr] + } + ]; + columns.push( + { + 'data': self.actionBtns.bind(self), // Vincular correctamente el contexto + 'className': 'row-edit dt-center', + } + ); + } + + let buttons = []; + if (buttonsExport) { + buttons = [ + { + extend: 'colvis', + columns: ':not(.noVis)', + + }, + 'copy', 'csv', 'excel', 'print', { + extend: 'pdfHtml5', + orientation: 'landscape', + pageSize: 'A4' + } + ]; + } + if (buttonNewWithEditor) { + buttons.push( + { + className: 'btn btn-primary me-sm-3 me-1', + extend: "createInline", + editor: editor, + formOptions: { + submitTrigger: -1, + submitHtml: '' + } + } + ); + } + + // Inicialización de DataTable + this.table = this.domItem.DataTable({ + processing: true, + serverSide: true, + autoWidth: true, + responsive: true, + scrollX: true, + stateSave: false, + lengthMenu: [5, 10, 25, 50, 75, 100, 250, 500, 1000, 2500], + order: order, + orderCellsTop: true, + fixedHeader: true, + dom: dom, + ajax: $.fn.dataTable.pipeline({ + url: this.url, + method: 'POST', + headers: { 'X-Requested-With': 'XMLHttpRequest' }, + data: function (d) { + $.each(self.data, function (key, val) { + d[val.name] = val.value; + }); + }, + async: true, + }), + buttons: buttons, + columns: this.columns, + language: { + url: "/themes/vuexy/vendor/libs/datatables-sk/plugins/i18n/" + this.language + ".json" + }, + columnDefs: columnDefs, + }); + + if (Array.isArray(booleanColumns) && booleanColumns.length > 0) { + this.table.on('draw.dt', function () { + for (let coln of booleanColumns) { + self.table.column(coln, { page: 'current' }).nodes().each(function (cell) { + cell.innerHTML = cell.innerHTML == '1' ? '' : ''; + }); + } + }); + } + }; + + this.setData = function (data) { + this.data = data; + } + + this.setPageLength = function (length) { + this.table.page.len(length).draw(); + } + + this.setEditCallback = function (callback) { + this.domItem.on('click', '.btn-edit-' + this.alias, function () { + let id = $(this).data('id'); + callback(id); + }); + } + + this.setDeleteCallback = function (callback) { + this.domItem.on('click', '.btn-delete-' + this.alias, function () { + let id = $(this).data('id'); + callback(id); + }); + } + + this.setViewCallback = function (callback) { + this.domItem.on('click', '.btn-view-' + this.alias, function () { + let id = $(this).data('id'); + callback(id); + }); + } + + this.actionBtns = function (data) { + let btns = ``; + if (this.actions.includes('view')) { + btns += ``; + } + if (this.actions.includes('edit')) { + btns += ``; + } + if (this.actions.includes('delete')) { + btns += ``; + } + if (this.actions.includes('cancel')) { + btns += ``; + } + return btns; + }; + +} + +export default Table; diff --git a/httpdocs/assets/js/safekat/components/tableEditor.js b/httpdocs/assets/js/safekat/components/tableEditor.js new file mode 100644 index 00000000..89b12369 --- /dev/null +++ b/httpdocs/assets/js/safekat/components/tableEditor.js @@ -0,0 +1,32 @@ +let TableEditor = function ( + table, + url, + headers, + idSrc, + fields) { + + + this.table = table; + this.url = url; + this.headers = headers; + this.idSrc = idSrc; + this.fields = fields; + + this.editor = null; + + this.init = function () { + + this.editor = new $.fn.dataTable.Editor( { + ajax: { + url: url, + headers: headers, + }, + table : table, + idSrc: idSrc, + fields: fields + }); + }; +} + +export default TableEditor; + diff --git a/httpdocs/assets/js/safekat/pages/cliente/cliente.js b/httpdocs/assets/js/safekat/pages/cliente/cliente.js index 0bd83277..0ef85e60 100644 --- a/httpdocs/assets/js/safekat/pages/cliente/cliente.js +++ b/httpdocs/assets/js/safekat/pages/cliente/cliente.js @@ -57,6 +57,8 @@ class Cliente { document.addEventListener('DOMContentLoaded', function () { const locale = document.querySelector('meta[name="locale"]').getAttribute('content'); + + new Ajax('/translate/getTranslation', { locale: locale, translationFile: ['ClienteContactos', 'ClientePrecios'] }, {}, function(translations) { diff --git a/httpdocs/assets/js/safekat/pages/cliente/tarifasCliente.js b/httpdocs/assets/js/safekat/pages/cliente/tarifasCliente.js index 55d61ad0..5e6ad756 100644 --- a/httpdocs/assets/js/safekat/pages/cliente/tarifasCliente.js +++ b/httpdocs/assets/js/safekat/pages/cliente/tarifasCliente.js @@ -1,6 +1,8 @@ import Table from '../../components/table.js'; +import TableEditor from '../../components/tableEditor.js'; import { getToken } from '../../common/common.js'; + class tarifasClienteView { constructor(domItem) { @@ -12,12 +14,148 @@ class tarifasClienteView { this.clienteId = window.location.href.split("/").pop(); this.actions = ['edit', 'delete']; + + this.headerSearcher(); + + this.tableTarifas = null; + this.editorTarifas = null; } init() { const self = this; + const tipo_linea = [ + { label: window.language.ClientePrecios.interior, value: 'interior' }, + { label: window.language.ClientePrecios.cubierta, value: 'cubierta' }, + { label: window.language.ClientePrecios.sobrecubierta, value: 'sobrecubierta' } + ]; + + const tipo_maquina = [ + { label: window.language.ClientePrecios.toner, value: 'toner' }, + { label: window.language.ClientePrecios.inkjet, value: 'inkjet' }, + ]; + + const tipo_impresion = [ + { label: window.language.ClientePrecios.negro, value: 'negro' }, + { label: window.language.ClientePrecios.negrohq, value: 'negrohq' }, + { label: window.language.ClientePrecios.color, value: 'color' }, + { label: window.language.ClientePrecios.colorhq, value: 'colorhq' }, + ]; + + const editorFields = [{ + name: "tipo", + type: "select", + options: tipo_linea + }, { + name: "tipo_maquina", + type: "select", + options: tipo_maquina + }, { + name: "tipo_impresion", + type: "select", + options: tipo_impresion + }, { + name: "tiempo_min" + }, { + name: "tiempo_max" + }, { + name: "precio_hora" + }, { + name: "margen" + }, { + name: "user_updated_id", + type: 'hidden', + + }, { + name: "updated_at", + type: 'hidden', + + }, { + "name": "plantilla_id", + "type": "hidden" + }, { + "name": "cliente_id", + "type": "hidden" + }, { + "name": "deleted_at", + "type": "hidden" + }, { + "name": "is_deleted", + "type": "hidden" + }, + ]; + this.editorTarifas = new TableEditor( + $('#tableOfPrecios'), + '/clienteprecios/datatable_editor', + { [this.csrf_token]: this.csrf_hash }, + editorFields); + + this.editorTarifas.init(); + + this.editorTarifas.editor.on('preSubmit', function (e, d, type) { + if (type === 'create') { + d.data[0]['cliente_id'] = this.clienteId; + } + else if (type === 'edit') { + for (v in d.data) { + d.data[v]['cliente_id'] = this.clienteId; + } + } + }); + + this.editorTarifas.editor.on('submitSuccess', function (e, json, data, action) { + + this.tableTarifas.table.clearPipeline(); + this.tableTarifas.table.draw(); + }); + + this.editorTarifas.editor.on('postEdit', function (e, json, data, action) { + /*const domain = window.location.origin + fetch(domain + "/clientes/clienteprecios/update/" + id, { + method: "POST", + body: JSON.stringify({ + : v + }), + headers: { + "Content-type": "application/json; charset=UTF-8" + } + })*/ + }) + + this.editorTarifas.editor.on('postCreate', function (e, json, data, action) { + const domain = window.location.origin + /*fetch(domain + "/clientes/clienteprecios/update/" + id, { + method: "POST", + body: JSON.stringify({ + : v + }), + headers: { + "Content-type": "application/json; charset=UTF-8" + } + })*/ + }) + this.#initTable(); + + this.tableTarifas.table.on( 'click', 'tbody span.edit', function (e) { + self.editorTarifas.editor.inline( + self.tableTarifas.table.cells(this.parentNode.parentNode, '*').nodes(), + { + cancelHtml: '', + cancelTrigger: 'span.cancel', + submitHtml: '', + submitTrigger: 'span.edit', + submit: 'allIfChanged' + } + ); + } ); + } + + + #initTable() { + + const self = this; + const columns = [ { 'data': 'tipo', @@ -58,9 +196,14 @@ class tarifasClienteView { { 'data': 'margen' }, { 'data': 'user_updated' }, { 'data': 'updated_at' }, - { 'data': 'plantilla_id' }, + { + 'data': 'plantilla_id', + 'searchable': false, + 'visible': false, + }, ]; + this.tableTarifas = new Table( $('#tableOfPrecios'), 'tarifasCliente', @@ -72,20 +215,116 @@ class tarifasClienteView { ] ); + this.tableTarifas.init({ actions: ['edit', 'delete'], - buttonsNewEditor: true, - + buttonNewWithEditor: true, + buttonsExport: true, + editor: this.editorTarifas.editor, }); - $('button[data-bs-target="#tarifascliente"]').on('shown.bs.tab', function(event) { + + this.tableTarifas.table.on('init.dt', function () { + self.tableTarifas.table.page.len(50).draw(); + }); + + $('button[data-bs-target="#tarifascliente"]').on('shown.bs.tab', function (event) { setTimeout(() => { self.tableTarifas.table.columns.adjust().draw(); - }, 100); // Usamos setTimeout para asegurar que se dibuje después del renderizado + }, 1000); // Usamos setTimeout para asegurar que se dibuje después del renderizado }); + } + headerSearcher() { + const self = this; + + $('#tableOfPrecios thead tr').clone(false).appendTo('#tableOfPrecios thead'); + $('#tableOfPrecios thead tr:eq(1) th').each(function (i) { + + if (!$(this).hasClass("noFilter")) { + + if (i == 0) { + + // Agregar un selector en la segunda columna + $(this).html(''); + + // Agregar opciones al selector + var selector = $('select', this); + selector.append(''); // Opción vacía + selector.append(''); + selector.append(''); + selector.append(''); + + selector.on('change', function () { + var val = $.fn.dataTable.util.escapeRegex( + $(this).val() + ); + self.tableTarifas.table.column(i).search(val).draw(); + }); + + } + + else if (i == 1) { + // Agregar un selector en la tercera columna + $(this).html(''); + + // Agregar opciones al selector + var selector = $('select', this); + selector.append(''); // Opción vacía + selector.append(''); + selector.append(''); + + selector.on('change', function () { + var val = $.fn.dataTable.util.escapeRegex( + $(this).val() + ); + self.tableTarifas.table.column(i).search(val).draw(); + }); + } + + else if (i == 2) { + // Agregar un selector en la cuarta columna + $(this).html(''); + + // Agregar opciones al selector + var selector = $('select', this); + selector.append(''); // Opción vacía + selector.append(''); + selector.append(''); + selector.append(''); + selector.append(''); + + selector.on('change', function () { + var val = $.fn.dataTable.util.escapeRegex( + $(this).val() + ); + self.tableTarifas.table.column(i).search(val).draw(); + }); + } + else { + $(this).html(''); + + $('input', this).on('change clear', function () { + if (self.tableTarifas.table.column(i).search() !== this.value) { + self.tableTarifas.table + .column(i) + .search(this.value) + .draw(); + } + }); + } + } + else { + $(this).html(''); + } + }); + + + } } + + export default tarifasClienteView; \ No newline at end of file From 9bec8f7adb3ae1ad2df53fc7600af8b5a6def32b Mon Sep 17 00:00:00 2001 From: Jaime Jimenez Date: Mon, 2 Dec 2024 15:10:26 +0100 Subject: [PATCH 4/5] haciendo el borrar! --- .../Models/Clientes/ClientePreciosModel.php | 22 +- .../clientes/cliente/_clienteFormItems.php | 1 + .../form/clientes/cliente/viewClienteForm.php | 1 + .../safekat/components/ConfirmDeleteModal.js | 51 +++++ .../assets/js/safekat/components/table.js | 10 +- .../js/safekat/components/tableEditor.js | 2 +- .../safekat/pages/cliente/tarifasCliente.js | 196 ++++++++++-------- 7 files changed, 182 insertions(+), 101 deletions(-) create mode 100644 httpdocs/assets/js/safekat/components/ConfirmDeleteModal.js diff --git a/ci4/app/Models/Clientes/ClientePreciosModel.php b/ci4/app/Models/Clientes/ClientePreciosModel.php index 3bfbdb1d..eb76141d 100755 --- a/ci4/app/Models/Clientes/ClientePreciosModel.php +++ b/ci4/app/Models/Clientes/ClientePreciosModel.php @@ -14,14 +14,14 @@ class ClientePreciosModel extends \App\Models\BaseModel protected $useAutoIncrement = true; const SORTABLE = [ - 0 => "t1.tipo", - 1 => "t1.tipo_maquina", - 2 => "t1.tipo_impresion", - 3 => "t1.tiempo_min", - 4 => "t1.tiempo_max", - 5 => "t1.precio_hora", - 6 => "t1.margen", - + 0 => "t1.id", + 1 => "t1.tipo", + 2 => "t1.tipo_maquina", + 3 => "t1.tipo_impresion", + 4 => "t1.tiempo_min", + 5 => "t1.tiempo_max", + 6 => "t1.precio_hora", + 7 => "t1.margen", ]; protected $allowedFields = [ @@ -277,10 +277,10 @@ class ClientePreciosModel extends \App\Models\BaseModel else { $builder->groupStart(); foreach ($search as $col_search) { - if ($col_search[0] > 2) - $builder->like(self::SORTABLE[$col_search[0]], $col_search[2]); - else + if ($col_search[0] > 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]); } $builder->groupEnd(); return $builder; diff --git a/ci4/app/Views/themes/vuexy/form/clientes/cliente/_clienteFormItems.php b/ci4/app/Views/themes/vuexy/form/clientes/cliente/_clienteFormItems.php index dc3e7967..92c184d8 100644 --- a/ci4/app/Views/themes/vuexy/form/clientes/cliente/_clienteFormItems.php +++ b/ci4/app/Views/themes/vuexy/form/clientes/cliente/_clienteFormItems.php @@ -584,6 +584,7 @@ + diff --git a/ci4/app/Views/themes/vuexy/form/clientes/cliente/viewClienteForm.php b/ci4/app/Views/themes/vuexy/form/clientes/cliente/viewClienteForm.php index a149252e..84a2ea39 100644 --- a/ci4/app/Views/themes/vuexy/form/clientes/cliente/viewClienteForm.php +++ b/ci4/app/Views/themes/vuexy/form/clientes/cliente/viewClienteForm.php @@ -1,6 +1,7 @@ include("themes/_commonPartialsBs/datatables") ?> include("themes/_commonPartialsBs/select2bs5") ?> include("themes/_commonPartialsBs/sweetalert") ?> +include('themes/_commonPartialsBs/_confirm2delete') ?> extend('themes/vuexy/main/defaultlayout') ?> section("content") ?> diff --git a/httpdocs/assets/js/safekat/components/ConfirmDeleteModal.js b/httpdocs/assets/js/safekat/components/ConfirmDeleteModal.js new file mode 100644 index 00000000..a874abf7 --- /dev/null +++ b/httpdocs/assets/js/safekat/components/ConfirmDeleteModal.js @@ -0,0 +1,51 @@ +class ConfirmDeleteModal { + constructor(alias = "") { + this.modalId = 'confirm2delete'; + + const removeClass = alias !== "" ? `btn-remove-${alias}` : 'btn-remove'; + + this.modalHtml = ` + + `; + } + + // Método para mostrar el modal + show(callback) { + // Insertar el modal en el body del documento si no existe + if (!document.getElementById(this.modalId)) { + document.body.insertAdjacentHTML('beforeend', this.modalHtml); + } + + // 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('confirmDelete').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(); + } +} diff --git a/httpdocs/assets/js/safekat/components/table.js b/httpdocs/assets/js/safekat/components/table.js index 83ea0bee..2f3c8eb3 100644 --- a/httpdocs/assets/js/safekat/components/table.js +++ b/httpdocs/assets/js/safekat/components/table.js @@ -156,19 +156,21 @@ let Table = function ( this.actionBtns = function (data) { let btns = ``; if (this.actions.includes('view')) { - btns += ``; + btns += ``; } if (this.actions.includes('edit')) { btns += ``; } - if (this.actions.includes('delete')) { - btns += ``; - } if (this.actions.includes('cancel')) { btns += ``; } + if (this.actions.includes('delete')) { + btns += ``; + } + return btns; }; + } diff --git a/httpdocs/assets/js/safekat/components/tableEditor.js b/httpdocs/assets/js/safekat/components/tableEditor.js index 89b12369..c0a5c370 100644 --- a/httpdocs/assets/js/safekat/components/tableEditor.js +++ b/httpdocs/assets/js/safekat/components/tableEditor.js @@ -23,7 +23,7 @@ let TableEditor = function ( }, table : table, idSrc: idSrc, - fields: fields + fields: fields, }); }; } diff --git a/httpdocs/assets/js/safekat/pages/cliente/tarifasCliente.js b/httpdocs/assets/js/safekat/pages/cliente/tarifasCliente.js index 5e6ad756..be539820 100644 --- a/httpdocs/assets/js/safekat/pages/cliente/tarifasCliente.js +++ b/httpdocs/assets/js/safekat/pages/cliente/tarifasCliente.js @@ -1,5 +1,6 @@ import Table from '../../components/table.js'; import TableEditor from '../../components/tableEditor.js'; +import Confirm2Delete from '../../components/confirm2delete.js'; import { getToken } from '../../common/common.js'; @@ -13,18 +14,51 @@ class tarifasClienteView { this.csrf_hash = $('#mainContainer').find('input[name="' + this.csrf_token + '"]').val(); this.clienteId = window.location.href.split("/").pop(); - this.actions = ['edit', 'delete']; + this.actions = ['edit', 'delete', 'cancel']; this.headerSearcher(); this.tableTarifas = null; this.editorTarifas = null; + this.confirmDeleteModal = null; } init() { const self = this; + this.#initEditor(); + + this.#initTable(); + + + // Editar en linea la fila + this.tableTarifas.table.on('click', 'tbody span.edit', function (e) { + + const row = $(this).closest('tr'); + + // Iniciar la edición en línea para todas las celdas de la fila + self.editorTarifas.editor.inline( + self.tableTarifas.table.cells(row, '*').nodes(), + { + cancelHtml: '', + submitHtml: '', + cancelTrigger: row.find('span.cancel')[0], + submitTrigger: row.find('span.edit')[0], + submit: 'allIfChanged' + } + ); + }); + + + + } + + + #initEditor() { + + const self = this; + const tipo_linea = [ { label: window.language.ClientePrecios.interior, value: 'interior' }, { label: window.language.ClientePrecios.cubierta, value: 'cubierta' }, @@ -43,120 +77,111 @@ class tarifasClienteView { { label: window.language.ClientePrecios.colorhq, value: 'colorhq' }, ]; - const editorFields = [{ - name: "tipo", - type: "select", - options: tipo_linea - }, { - name: "tipo_maquina", - type: "select", - options: tipo_maquina - }, { - name: "tipo_impresion", - type: "select", - options: tipo_impresion - }, { - name: "tiempo_min" - }, { - name: "tiempo_max" - }, { - name: "precio_hora" - }, { - name: "margen" - }, { - name: "user_updated_id", - type: 'hidden', + const editorFields = [ + { + name: "id", + type: "readonly" + }, { + name: "tipo", + type: "select", + options: tipo_linea + }, { + name: "tipo_maquina", + type: "select", + options: tipo_maquina + }, { + name: "tipo_impresion", + type: "select", + options: tipo_impresion + }, { + name: "tiempo_min" + }, { + name: "tiempo_max" + }, { + name: "precio_hora" + }, { + name: "margen" + }, { + name: "user_updated_id", + type: 'hidden', - }, { - name: "updated_at", - type: 'hidden', + }, { + name: "updated_at", + type: 'hidden', - }, { - "name": "plantilla_id", - "type": "hidden" - }, { - "name": "cliente_id", - "type": "hidden" - }, { - "name": "deleted_at", - "type": "hidden" - }, { - "name": "is_deleted", - "type": "hidden" - }, + }, { + name: "plantilla_id", + type: "hidden" + }, { + name: "cliente_id", + type: "hidden" + }, { + name: "deleted_at", + type: "hidden" + }, { + name: "is_deleted", + type: "hidden" + }, ]; this.editorTarifas = new TableEditor( $('#tableOfPrecios'), '/clienteprecios/datatable_editor', { [this.csrf_token]: this.csrf_hash }, + 'id', editorFields); this.editorTarifas.init(); this.editorTarifas.editor.on('preSubmit', function (e, d, type) { if (type === 'create') { - d.data[0]['cliente_id'] = this.clienteId; - } - else if (type === 'edit') { - for (v in d.data) { - d.data[v]['cliente_id'] = this.clienteId; - } + d.data[0]['cliente_id'] = self.clienteId; } }); this.editorTarifas.editor.on('submitSuccess', function (e, json, data, action) { - this.tableTarifas.table.clearPipeline(); - this.tableTarifas.table.draw(); + self.tableTarifas.table.clearPipeline(); + self.tableTarifas.table.draw(); }); + this.editorTarifas.editor.on('postEdit', function (e, json, data, action) { - /*const domain = window.location.origin - fetch(domain + "/clientes/clienteprecios/update/" + id, { - method: "POST", - body: JSON.stringify({ - : v - }), - headers: { - "Content-type": "application/json; charset=UTF-8" - } - })*/ + self.#borrarPlantillaTarifa(self.clienteId); }) this.editorTarifas.editor.on('postCreate', function (e, json, data, action) { - const domain = window.location.origin - /*fetch(domain + "/clientes/clienteprecios/update/" + id, { - method: "POST", - body: JSON.stringify({ - : v - }), - headers: { - "Content-type": "application/json; charset=UTF-8" - } - })*/ + self.#borrarPlantillaTarifa(self.clienteId); }) - this.#initTable(); - this.tableTarifas.table.on( 'click', 'tbody span.edit', function (e) { - self.editorTarifas.editor.inline( - self.tableTarifas.table.cells(this.parentNode.parentNode, '*').nodes(), - { - cancelHtml: '', - cancelTrigger: 'span.cancel', - submitHtml: '', - submitTrigger: 'span.edit', - submit: 'allIfChanged' - } - ); - } ); + this.editorTarifas.editor.on('postCancel', function (e, json, data) { + // Restaurar botones de acción por fila + self.tableTarifas.table.rows().nodes().each(function (node) { + $(node).find('span.edit').removeClass('d-none'); + $(node).find('span.cancel, span.submit').addClass('d-none'); + }); + }); } + #borrarPlantillaTarifa(id) { + + const domain = window.location.origin + fetch(domain + "/clientes/clienteprecios/update/" + id, { + method: "POST", + body: JSON.stringify({ + [self.csrf_token]: self.csrf_hash + }), + headers: { + "Content-type": "application/json; charset=UTF-8" + } + }) + } #initTable() { const self = this; const columns = [ + { 'data': 'id' }, { 'data': 'tipo', 'render': function (data, type, row, meta) { @@ -217,10 +242,11 @@ class tarifasClienteView { this.tableTarifas.init({ - actions: ['edit', 'delete'], + actions: self.actions, buttonNewWithEditor: true, buttonsExport: true, editor: this.editorTarifas.editor, + deleteModal: '#confirm2delete' }); @@ -245,7 +271,7 @@ class tarifasClienteView { if (!$(this).hasClass("noFilter")) { - if (i == 0) { + if (i == 1) { // Agregar un selector en la segunda columna $(this).html(''); @@ -266,7 +292,7 @@ class tarifasClienteView { } - else if (i == 1) { + else if (i == 2) { // Agregar un selector en la tercera columna $(this).html(''); @@ -284,7 +310,7 @@ class tarifasClienteView { }); } - else if (i == 2) { + else if (i == 3) { // Agregar un selector en la cuarta columna $(this).html(''); From aa22b81c965f337748b9ea784ed1b076337dbd1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaime=20Jim=C3=A9nez?= Date: Tue, 3 Dec 2024 17:51:03 +0100 Subject: [PATCH 5/5] =?UTF-8?q?terminada=20pesta=C3=B1a=20cliente=20tarifa?= =?UTF-8?q?s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/Clientes/ClientePrecios.php | 6 +-- .../safekat/components/ConfirmDeleteModal.js | 42 ++++++++++++++++--- .../assets/js/safekat/components/table.js | 10 +++-- .../safekat/pages/cliente/tarifasCliente.js | 24 ++++++++++- 4 files changed, 66 insertions(+), 16 deletions(-) diff --git a/ci4/app/Controllers/Clientes/ClientePrecios.php b/ci4/app/Controllers/Clientes/ClientePrecios.php index bc258921..105d085a 100755 --- a/ci4/app/Controllers/Clientes/ClientePrecios.php +++ b/ci4/app/Controllers/Clientes/ClientePrecios.php @@ -205,21 +205,19 @@ class ClientePrecios extends \App\Controllers\BaseResourceController } }) ->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/httpdocs/assets/js/safekat/components/ConfirmDeleteModal.js b/httpdocs/assets/js/safekat/components/ConfirmDeleteModal.js index a874abf7..161c593f 100644 --- a/httpdocs/assets/js/safekat/components/ConfirmDeleteModal.js +++ b/httpdocs/assets/js/safekat/components/ConfirmDeleteModal.js @@ -1,9 +1,16 @@ class ConfirmDeleteModal { + constructor(alias = "") { - this.modalId = 'confirm2delete'; + + this.modalId = alias !== "" ? `confirm2delete-${alias}`: 'confirm2delete'; const removeClass = alias !== "" ? `btn-remove-${alias}` : 'btn-remove'; + this.btnCancelId = alias !== "" ? `btnCancelDelete-${alias}` : 'btnCancelDelete'; + this.btnDeleteId = alias !== "" ? `btnConfirmDelete-${alias}` : 'btnConfirmDelete'; + + this.data = null; + this.modalHtml = ` @@ -25,19 +32,39 @@ class ConfirmDeleteModal { `; } - // Método para mostrar el modal - show(callback) { + 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; + } + + setData(data) { + this.data = data; + } + + getData() { + return this.data; + } + + // 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('confirmDelete').addEventListener('click', () => { + document.getElementById(this.btnDeleteId).addEventListener('click', () => { callback(); // Llamar al callback que el usuario haya proporcionado modal.hide(); // Cerrar el modal }); @@ -49,3 +76,6 @@ class ConfirmDeleteModal { modal.hide(); } } + + +export default ConfirmDeleteModal; \ 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 2f3c8eb3..84f94c7b 100644 --- a/httpdocs/assets/js/safekat/components/table.js +++ b/httpdocs/assets/js/safekat/components/table.js @@ -23,15 +23,13 @@ let Table = function ( dom = '<"mt-4"><"float-end"B><"float-start"l><"mt-4 mb-3"p>', actions = ['view', 'edit', 'delete', 'cancel'], order = [[0, 'asc']], - deleteModal = null, buttonsExport = true, buttonNewWithEditor = false, editor = null, booleanColumns = [], } = {}) { - this.actions = actions; // Guardar actions como propiedad de la instancia - this.deleteModal = deleteModal; + this.actions = actions; const lastColNr = this.domItem.find("tr:first th").length - 1; @@ -124,6 +122,10 @@ let Table = function ( } }; + this.getAlias = function () { + return this.alias; + } + this.setData = function (data) { this.data = data; } @@ -165,7 +167,7 @@ let Table = function ( btns += ``; } if (this.actions.includes('delete')) { - btns += ``; + btns += ``; } return btns; diff --git a/httpdocs/assets/js/safekat/pages/cliente/tarifasCliente.js b/httpdocs/assets/js/safekat/pages/cliente/tarifasCliente.js index be539820..0ed7c8ea 100644 --- a/httpdocs/assets/js/safekat/pages/cliente/tarifasCliente.js +++ b/httpdocs/assets/js/safekat/pages/cliente/tarifasCliente.js @@ -1,6 +1,6 @@ import Table from '../../components/table.js'; import TableEditor from '../../components/tableEditor.js'; -import Confirm2Delete from '../../components/confirm2delete.js'; +import ConfirmDeleteModal from '../../components/ConfirmDeleteModal.js'; import { getToken } from '../../common/common.js'; @@ -21,12 +21,16 @@ class tarifasClienteView { this.tableTarifas = null; this.editorTarifas = null; this.confirmDeleteModal = null; + this.deleteModal = null; } init() { const self = this; + this.deleteModal = new ConfirmDeleteModal('tarifascliente'); + this.deleteModal.init(); + this.#initEditor(); this.#initTable(); @@ -51,6 +55,21 @@ class tarifasClienteView { }); + this.tableTarifas.table.on('click', '.btn-delete-' + this.tableTarifas.getAlias(), function (e) { + const row = $(this).closest('tr')[0]._DT_RowIndex; + self.deleteModal.setData($(this).attr('data-id')); + self.deleteModal.show(() =>{ + if ($.isNumeric(self.deleteModal.getData())) { + self.editorTarifas.editor + .create( false ) + .edit( self.tableTarifas.table.rows(row), false) + .set( 'deleted_at', new Date().toISOString().slice(0, 19).replace('T', ' ') ) + .set( 'is_deleted', 1 ) + .submit(); + self.deleteModal.hide(); + } + }); + }); } @@ -246,7 +265,6 @@ class tarifasClienteView { buttonNewWithEditor: true, buttonsExport: true, editor: this.editorTarifas.editor, - deleteModal: '#confirm2delete' }); @@ -262,6 +280,8 @@ class tarifasClienteView { } + + headerSearcher() { const self = this;
ID