Merge branch 'main' into 'dev/pedidos_v1'

Main

See merge request jjimenez/safekat!264
This commit is contained in:
2024-06-05 14:13:23 +00:00
15 changed files with 446 additions and 774212 deletions

2
.gitignore vendored
View File

@ -1,4 +1,4 @@
ci4/.env
.vscode/
./xdebug.log
xdebug.log

View File

@ -66,6 +66,7 @@ $routes->group('users', ['namespace' => 'App\Controllers\Configuracion'], functi
$routes->get('delete/(:num)', 'Users::delete/$1', ['as' => 'deleteUser']);
$routes->post('allmenuitems', 'Users::allItemsSelect', ['as' => 'select2ItemsOfUsers']);
$routes->post('menuitems', 'Users::menuItems', ['as' => 'menuItemsOfUsers']);
$routes->post('getMenuComerciales', 'Users::getMenuComerciales', ['as' => 'menuItemsComerciales']);
});
$routes->group('group', ['namespace' => 'App\Controllers\Configuracion'], function ($routes) {
@ -354,10 +355,10 @@ $routes->group('clientes', ['namespace' => 'App\Controllers\Clientes'], function
$routes->resource('cliente', ['namespace' => 'App\Controllers\Clientes', 'controller' => 'Cliente', 'except' => 'show,new,create,update']);*/
$routes->group('clienteprecios', ['namespace' => 'App\Controllers\Clientes'], function ($routes) {
$routes->post('datatable', 'Clienteprecios::datatable', ['as' => 'dataTableOfClienteprecios']);
$routes->post('datatable_editor', 'Clienteprecios::datatable_editor', ['as' => 'editorOfClienteprecios']);
$routes->post('datatable', 'ClientePrecios::datatable', ['as' => 'dataTableOfClienteprecios']);
$routes->post('datatable_editor', 'ClientePrecios::datatable_editor', ['as' => 'editorOfClienteprecios']);
});
$routes->resource('clienteprecios', ['namespace' => 'App\Controllers\Clientes', 'controller' => 'Clienteprecios', 'except' => 'show,new,create,update']);
$routes->resource('clienteprecios', ['namespace' => 'App\Controllers\Clientes', 'controller' => 'ClientePrecios', 'except' => 'show,new,create,update']);
$routes->group('clienteplantillaprecios', ['namespace' => 'App\Controllers\Clientes'], function ($routes) {

View File

@ -67,7 +67,7 @@ class Users extends \App\Controllers\GoBaseController {
$currentGroups = $postData['group']??[];
unset($postData['group']);
$postData['username'] = strstr($postData['email'], '@', true);
$sanitizedData = $this->sanitized($postData, true);
$noException = true;
@ -75,20 +75,28 @@ class Users extends \App\Controllers\GoBaseController {
$users = auth()->getProvider();
if ($successfulResult = $this->canValidate()) : // if ($successfulResult = $this->validate($this->formValidationRules) ) :
if ($this->canValidate()) :
if ($this->canValidate()) :
try {
$user = new User([
'username' => strstr($sanitizedData['email'], '@', true),
'username' => $sanitizedData['username'],
'first_name' => $sanitizedData['first_name'],
'last_name' => $sanitizedData['last_name'],
'email' => $sanitizedData['email'],
'password' => 'Safekat2024',
'status' => $sanitizedData['status']??0,
'active' => $sanitizedData['active']??0,
]);
$users->save($user);
$successfulResult = true; // Hacked
$successfulResult = true; // Hacked
} catch (\Exception $e) {
$noException = false;
$this->dealWithException($e);
//$this->dealWithException($e);
if (strpos($e->getMessage(), 'correo duplicado') !== false) {
$this->viewData['errorMessage'] = "El correo electrónico ya está registrado en el sistema";
$this->session->setFlashdata('formErrors', $this->model->errors());
}
}
else:
$this->viewData['errorMessage'] = lang('Basic.global.formErr1', [mb_strtolower(lang('Users.user'))]);
@ -100,10 +108,10 @@ class Users extends \App\Controllers\GoBaseController {
if ($noException && $successfulResult) :
$id = $users->getInsertID();
$this->group_user_model->where('user_id', $user->id)->delete();
$this->group_user_model->where('user_id', $id)->delete();
foreach($currentGroups as $group){
$group_user_data = [
'user_id' => $user->id,
'user_id' => $id,
'group' => $group
];
$this->group_user_model->insert($group_user_data);
@ -296,6 +304,22 @@ class Users extends \App\Controllers\GoBaseController {
}
}
public function getMenuComerciales(){
if ($this->request->isAJAX()) {
$comerciales = $this->model->getComerciales();
$newTokenHash = csrf_hash();
$csrfTokenName = csrf_token();
$data = [
'menu' => $comerciales,
$csrfTokenName => $newTokenHash
];
return $this->respond($data);
} else {
return $this->failUnauthorized('Invalid request', 403);
}
}
protected function getPaisListItems() {
$data = [''=>lang('Basic.global.pleaseSelectA', [mb_strtolower(lang('Pais.pais'))])];

View File

@ -788,7 +788,7 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
return $this->respond([
'status' => $id,
'url' => site_url('presupuestocliente/list'),
'url' => site_url('presupuestos/presupuestocliente/edit'),
'message' => lang('Basic.global.saveSuccess', [lang('Basic.global.record')]),
$csrfTokenName => $newTokenHash
]);
@ -797,6 +797,89 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
}
}
public function get_files(){
// Check if the request is a POST request
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$presupuesto_id = $this->request->getPost()['presupuesto_id'] ?? 0;
$model = model('App\Models\Presupuestos\PresupuestoFicheroModel');
$files = $model->getFiles($presupuesto_id);
$result = [];
foreach ($files as $file) {
$size = filesize($file->file_path);
$splitPath = explode("presupuestos/", $file->file_path);
// se crea un objeto con el nombre del fichero y el tamaño
$obj = (object) array(
'name' => $file->nombre,
'size' => $size,
'hash' => $splitPath[1] ?? $file->file_path);
// se añade el objeto al array
array_push($result, $obj);
}
return json_encode($result);
}
}
public function upload_files(){
$model = model('App\Models\Presupuestos\PresupuestoFicheroModel');
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$presupuesto_id = $_POST['presupuesto_id'];
$old_files = json_decode($_POST['oldFiles']);
// Comprobar si se han subido archivos
if (!empty($_FILES['file']) || !empty($old_files)) {
// Borrar los archivos existentes del presupuesto
$model->deleteFiles($presupuesto_id, $old_files);
if (!empty($_FILES['file'])){
$files = $_FILES['file'];
// Iterar sobre los archivos
for ($i = 0; $i < count($files['name']); $i++) {
// Aquí puedes acceder a las propiedades del archivo
$name = $files['name'][$i];
$extension = explode('.', $files['name'][$i])[1];
$tmp_name = $files['tmp_name'][$i];
$new_name = $model->saveFileInBBDD($presupuesto_id, $name, $extension, auth()->id());
// Se sube el fichero
// Pero primero se comprueba que la carpeta presupuestos exista
if (!is_dir(WRITEPATH . 'uploads/presupuestos')) {
mkdir(WRITEPATH . 'uploads/presupuestos', 0777, true);
}
if(!is_null($new_name)){
move_uploaded_file($tmp_name, WRITEPATH . 'uploads/presupuestos/' . $new_name);
}
}
}
}
else{
// Borrar los archivos existentes del presupuesto
$model->deleteFiles($presupuesto_id);
}
}
return json_encode(['message' => 'Archivos subidos correctamente']);
}
/***********************
*
@ -1479,7 +1562,6 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
}
}
protected function calcular_coste_linea($linea, &$totalPapel, &$margenPapel, &$sumForFactor, &$totalImpresion, &$margenImpresion)
{
if (count($linea) == 0)
@ -1676,14 +1758,18 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
protected function obtenerPaginasColor($presupuestoEntity)
{
$comparador_data = json_decode($presupuestoEntity->comparador_json_data);
if (property_exists($comparador_data, 'color')) {
$presupuestoEntity->paginasColor = $comparador_data->color->paginas;
if(!is_null($comparador_data)){
if (property_exists($comparador_data, 'color')) {
$presupuestoEntity->paginasColor = $comparador_data->color->paginas;
}
if (property_exists($comparador_data, 'colorhq')) {
$presupuestoEntity->paginasColor = $comparador_data->colorhq->paginas;
} else {
$presupuestoEntity->paginasColor = 0;
}
}
if (property_exists($comparador_data, 'colorhq')) {
$presupuestoEntity->paginasColor = $comparador_data->colorhq->paginas;
} else {
else
$presupuestoEntity->paginasColor = 0;
}
}
protected function obtenerTiradas($presupuestoEntity)

View File

@ -0,0 +1,37 @@
<?php
namespace App\Controllers\Sistema;
use CodeIgniter\Controller;
class Intranet extends Controller
{
function presupuestos($resource_name)
{
helper('file');
$resource_path = WRITEPATH . 'uploads/presupuestos/' . $resource_name;
if (file_exists($resource_path)) {
// Get the mime type of the file
$mime_type = mime_content_type($resource_path);
// Get an instance of the Response class
$response = service('response');
// Set the content type
$response->setContentType($mime_type);
// Set the output
$response->setBody(file_get_contents($resource_path));
// Send the response to the browser
$response->send();
}
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace App\Entities\Presupuestos;
use CodeIgniter\Entity;
class PresupuestoFicheroEntity extends \CodeIgniter\Entity\Entity
{
protected $attributes = [
"id" => null,
"presupuesto_id" => null,
"nombre" => null,
"file_path" => null,
"upload_by" => null,
"upload_at" => null,
];
protected $casts = [
"presupuesto_id" => "int",
];
}

View File

@ -0,0 +1,89 @@
<?php
namespace App\Models\Presupuestos;
class PresupuestoFicheroModel extends \App\Models\BaseModel
{
protected $table = "presupuesto_ficheros";
/**
* Whether primary key uses auto increment.
*
* @var bool
*/
protected $useAutoIncrement = true;
protected $allowedFields = ["presupuesto_id", "nombre", "file_path", "upload_by", "upload_at"];
protected $returnType = "App\Entities\Presupuestos\PresupuestoFicheroEntity";
protected $useTimestamps = false;
protected $useSoftDeletes = false;
public static $labelField = "nombre";
public function saveFileInBBDD($presupuesto_id, $filename, $extension ,$user_id) {
try{
$new_filename = $this->generateFileHash($filename) . '.' . $extension;
$this->db->table($this->table . " t1")
->set('presupuesto_id', $presupuesto_id)
->set('nombre', $filename)
->set('file_path', WRITEPATH . 'uploads/presupuestos/' . $new_filename)
->set('upload_by', $user_id)
->set('upload_at', date('Y-m-d H:i:s'))
->insert();
return $new_filename;
} catch (\Exception $e) {
return null;
}
}
public function deleteFiles($presupuesto_id, $old_files = []){
$files = $this->db
->table($this->table . " t1")
->where('presupuesto_id', $presupuesto_id)->get()->getResult();
if($files){
foreach($files as $file){
// se comprueba que el $file->nombre no sea igual a ninguno de los elementos del array $old_files
if (!in_array($file->nombre, $old_files)) {
if (file_exists($file->file_path)) {
unlink($file->file_path);
}
$this->db
->table($this->table . " t1")
->where('presupuesto_id', $presupuesto_id)
->where('nombre', $file->nombre)
->delete();
}
}
}
}
public function getFiles($presupuesto_id){
return $this->db
->table($this->table . " t1")
->where('presupuesto_id', $presupuesto_id)->get()->getResult();
}
/**
* Función para convertir el nombre y extensión de un fichero en un hash único
* usando cifrado simétrico.
*
* @param string $filename Nombre del fichero con extensión
* @return string Hash encriptado del fichero
*/
private function generateFileHash($filename) {
return hash('sha256', $filename);
}
}

View File

@ -19,11 +19,27 @@ class UserModel extends ShieldUserModel
];
}
/*protected $validationRules = [
"email" => [
"label" => "RolesPermisos.email",
"rules" => "required|max_length[150]",
protected $validationRules = [
"username" => [
"label" => "correo duplicado",
"rules" => "is_unique[users.username]",
]
];*/
];
public function getComerciales(){
$builder = $this->db
->table("users" . " t1")
->select(
"t1.id AS id, CONCAT(t1.first_name, ' ', t1.last_name) AS text"
);
$builder->where('t1.deleted_at', null);
$builder->where("t2.group", "comercial");
$builder->join("auth_groups_users t2", "t1.id = t2.user_id", "left");
return $builder->get()->getResult();
}
}

View File

@ -1513,7 +1513,7 @@ function delete_direccion_envio(dataId){
<?=$this->section('css') ?>
<link rel="stylesheet" href="<?= site_url('themes/vuexy/css/datatables-editor/editor.bootstrap5.min.css') ?>">
<link rel="stylesheet" href="<?= site_url("/themes/vuexy/vendor/libs/datatables-sk/plugins/buttons/buttons.bootstrap5.min.css") ?>">
<link rel="stylesheet" href="<?= site_url("/themes/vuexy/vendor/libs/datatables-bs5/dataTables.bootstrap5.min.css") ?>">
<link rel="stylesheet" href="<?= site_url("/themes/vuexy/vendor/libs/datatables-bs5/datatables.bootstrap5.css") ?>">
<?=$this->endSection() ?>
<?= $this->section('additionalExternalJs') ?>

View File

@ -55,7 +55,7 @@
$('#soporteId').select2({
allowClear: false,
ajax: {
url: '<?= route_to("menuItemsOfUsers") ?>',
url: '<?= route_to("menuItemsComerciales") ?>',
type: 'post',
dataType: 'json',
@ -200,14 +200,14 @@
$('#comercialId').select2({
allowClear: false,
ajax: {
url: '<?= route_to("menuItemsOfUsers") ?>',
url: '<?= route_to("menuItemsComerciales") ?>',
type: 'post',
dataType: 'json',
data: function (params) {
return {
id: 'id_user',
text: 'first_name',
id: 'id',
text: 'text',
searchTerm: params.term,
<?= csrf_token() ?? "token" ?> : <?= csrf_token() ?>v
};

View File

@ -145,10 +145,29 @@
echo '</div>';
endforeach;
endif;
echo '</div>';
echo '</div>';
endif; ?>
<?php if($presupuestoEntity->estado_id==2): ?>
<div class="row mb-3">
<h3>Ficheros</h3>
<div class="col-12">
<div class="dropzone needsclick" id="dropzone-multi" >
<div class="dz-message needsclick">
Arrastre aquí los ficheros o haga click
</div>
<div class="fallback">
<input name="file" type="file" />
</div>
</div>
</div>
<button id="submit-all" class="btn mt-3 btn-primary btn-submit waves-effect waves-light ml-2">
<span class="align-middle d-sm-inline-block d-none me-sm-1">Actualizar ficheros</span>
<i class="ti ti-upload ti-xs"></i>
</button>
</div>
<?php endif; ?>
</div>
<!-- Modal -->
@ -181,7 +200,117 @@ window.routes_resumen = {
duplicarPresupuesto: "<?= route_to('duplicarPresupuesto') ?>",
}
if(<?php echo $presupuestoEntity->estado_id?>==2)
if(<?php echo $presupuestoEntity->estado_id?>==2){
previewEsquemaCubierta(true);
const previewTemplate = `<div class="dz-preview dz-file-preview">
<div class="dz-details">
<div class="dz-thumbnail">
<!---<img data-dz-thumbnail>
<span class="dz-nopreview">No preview</span> --->
<div class="dz-success-mark"></div>
<div class="dz-error-mark"></div>
<div class="dz-error-message"><span data-dz-errormessage></span></div>
<div class="progress">
<div class="progress-bar progress-bar-primary" role="progressbar" aria-valuemin="0" aria-valuemax="100" data-dz-uploadprogress></div>
</div>
</div>
<div class="dz-filename" data-dz-name></div>
<div class="dz-size" data-dz-size></div>
</div>
</div>`;
Dropzone.autoDiscover = false;
var dropzoneMulti = new Dropzone('#dropzone-multi', {
url: "<?= site_url('presupuestos/presupuestocliente/upload_files') ?>",
addRemoveLinks: true,
previewTemplate: previewTemplate,
paramName: "file",
uploadMultiple: true,
parallelUploads: 4, // Ajusta este número al máximo número de archivos que esperas subir a la vez
maxFiles: 5, // Ajusta este número al máximo número de archivos que esperas subir a la vez
autoProcessQueue: true,
dictRemoveFile: "Eliminar",
acceptedFiles: 'image/*, application/pdf',
maxFilesize: 5e+7, // Bytes
init: function() {
thisDropzone = this;
$('#loader').show();
$.ajax({
url: "<?= site_url('presupuestos/presupuestocliente/get_files') ?>",
type: 'POST',
data: { presupuesto_id: <?= $presupuestoEntity->id ?> },
}).done(function(response) {
if(response == null || response == ""){
return;
}
values = JSON.parse(response);
for(var i = 0; i < values.length; i++){
var mockFile = { name: values[i].name, size: values[i].size, hash: values[i].hash};
thisDropzone.files.push(mockFile); // add to files array
thisDropzone.emit("addedfile", mockFile);
thisDropzone.emit("thumbnail", mockFile, window.location.host + "/sistema/intranet/presupuestos/"+values[i].hash);
thisDropzone.emit("complete", mockFile);
thisDropzone.options.success.call(thisDropzone, mockFile);
};
}).always(function() {
$('#loader').hide();
});
this.on("addedfile", function (file) {
if(file.hash){
var viewButton = Dropzone.createElement("<span class='dz-remove'>Ver</span>");
file.previewElement.appendChild(viewButton);
// Listen to the view button click event
viewButton.addEventListener("click", function (e) {
window.open(window.location.protocol + "//" + window.location.host + "/sistema/intranet/presupuestos/"+file.hash, '_blank');
});
}
});
}
});
$('#presupuesto-cliente-form').submit(function(e){
e.preventDefault();
var files = dropzoneMulti.files;
$('#loader').show();
var formData = new FormData();
var oldFiles = [];
var counter = 0;
for (var i = 0; i < files.length; i++) {
if(files[i].upload){
var file = files[i];
formData.append('file[' + counter + ']', file);
counter += 1;
}
else{
oldFiles.push(files[i].name);
}
}
formData.append('oldFiles', JSON.stringify(oldFiles));
formData.append('presupuesto_id', <?= $presupuestoEntity->id ?>);
$.ajax({
url: "<?= site_url('presupuestos/presupuestocliente/upload_files') ?>",
type: 'POST',
data: formData,
processData: false, // Indicar a jQuery que no procese los datos
contentType: false // Indicar a jQuery que no establezca el tipo de contenido
}).done(function(response) {
// Aquí puedes manejar la respuesta del servidor
}).always(function() {
$('#loader').hide();
})
return false;
});
}
<?= $this->endSection() ?>

View File

@ -735,7 +735,10 @@ async function calcularPresupuesto() {
}
catch(error){
}
console.log(response);
//For debug only
//console.log(response);
$('#loader').hide();
$('#divTiradasPrecio').empty();

View File

@ -279,11 +279,13 @@ function finalizarPresupuesto(confirmar){
data: datos,
success: function(response) {
if(Object.keys(response).length > 0) {
if(response.status > 0){
window.location.href = response.url;
if(confirmar){
if(Object.keys(response).length > 0) {
if(response.status > 0){
window.location.href = response.url + '/' + response.status;
}
}
}
$('#loader').hide();

View File

@ -78,7 +78,7 @@
</div>
<div class="bs-stepper-content">
<form id="presupuesto-cliente-form" onsubmit="return false">
<form id="presupuesto-cliente-form" >
<!-- Tipo Libro -->
@ -179,7 +179,6 @@
</div>
</div>
</div>
</form>
</div>
</div>
@ -239,10 +238,12 @@ if(<?= $presupuestoEntity->estado_id ?>==1){
<link rel="stylesheet" href="<?= site_url('themes/vuexy/vendor/libs/bs-stepper/bs-stepper.css') ?>" />
<link rel="stylesheet" href="<?= site_url('themes/vuexy/vendor/libs/formvalidation/dist/css/formValidation.min.css') ?>" />
<link rel="stylesheet" href="<?= site_url('themes/vuexy/vendor/libs/dropzone/dropzone.css') ?>" />
<?= $this->endSection() ?>
<?= $this->section('additionalExternalJs') ?>
<script src="<?= site_url("themes/vuexy/vendor/libs/dropzone/dropzone.js") ?>"></script>
<script src="<?= site_url("themes/vuexy/vendor/libs/bs-stepper/bs-stepper.js") ?>"></script>
<script src="<?= site_url("themes/vuexy/vendor/libs/formvalidation/dist/js/FormValidation.min.js") ?>"></script>
<script src="<?= site_url("themes/vuexy/vendor/libs/formvalidation/dist/js/plugins/Bootstrap5.min.js") ?>"></script>

774173
xdebug.log

File diff suppressed because one or more lines are too long