Merge branch 'main' into 'dev/chat'

Main

See merge request jjimenez/safekat!296
This commit is contained in:
Ignacio Martinez Navajas
2024-07-31 18:41:45 +00:00
64 changed files with 3508 additions and 2443 deletions

View File

@ -13,6 +13,7 @@ declare(strict_types=1);
namespace Config; namespace Config;
use App\Entities\Usuarios\UsersEntity;
use App\Models\UserModel; use App\Models\UserModel;
use CodeIgniter\Shield\Authentication\Passwords\ValidationRules; use CodeIgniter\Shield\Authentication\Passwords\ValidationRules;
use CodeIgniter\Shield\Config\Auth as ShieldAuth; use CodeIgniter\Shield\Config\Auth as ShieldAuth;

View File

@ -76,7 +76,7 @@ $routes->group('configuracion', ['namespace' => 'App\Controllers\Configuracion']
$routes->match(['get', 'post'], 'edit/(:num)', 'SeriesFacturas::edit/$1', ['as' => 'seriesFacturasEdit']); $routes->match(['get', 'post'], 'edit/(:num)', 'SeriesFacturas::edit/$1', ['as' => 'seriesFacturasEdit']);
$routes->get('delete/(:num)', 'SeriesFacturas::delete/$1', ['as' => 'seriesFacturasDelete']); $routes->get('delete/(:num)', 'SeriesFacturas::delete/$1', ['as' => 'seriesFacturasDelete']);
$routes->post('datatable', 'SeriesFacturas::datatable', ['as' => 'seriesFacturasDT']); $routes->post('datatable', 'SeriesFacturas::datatable', ['as' => 'seriesFacturasDT']);
$routes->post('menuitemsFacturas', 'SeriesFacturas::menuItemsFacturas', ['as' => 'menuItemsOfSeriesFacturas']);
}); });
}); });
@ -652,8 +652,28 @@ $routes->group('facturas', ['namespace' => 'App\Controllers\Facturacion'], funct
$routes->get('list', 'Facturas::list', ['as' => 'facturasList']); $routes->get('list', 'Facturas::list', ['as' => 'facturasList']);
$routes->post('datatable', 'Facturas::datatable', ['as' => 'dataTableOfFacturas']); $routes->post('datatable', 'Facturas::datatable', ['as' => 'dataTableOfFacturas']);
$routes->get('add', 'Facturas::add', ['as' => 'newFactura']);
$routes->post('add', 'Facturas::add', ['as' => 'createFactura']);
$routes->get('edit/(:any)', 'Facturas::edit/$1', ['as' => 'editarFactura']);
$routes->get('validar/(:any)', 'Facturas::validar/$1', ['as' => 'validarFactura']);
$routes->post('update/(:any)', 'Facturas::update/$1', ['as' => 'actualizarFactura']);
$routes->post('duplicate/(:any)', 'Facturas::duplicate/$1', ['as' => 'duplicarFactura']);
$routes->post('datatable/(:any)', 'FacturasLineas::datatable/$1', ['as' => 'dataTableOfLineasFacturas']);
$routes->post('menuPedidosPendientes/(:num)', 'Facturas::menuPedidosPendientes/$1', ['as' => 'menuPedidosPendientesImpresion']);
$routes->post('addLineaPedidoImpresion/(:num)', 'Facturas::addLineaPedidoImpresion/$1', ['as' => 'addLineaPedidoImpresion2Factura']);
$routes->post('addLineaPedidoImpresion/(:num)', 'Facturas::addLineaPedidoImpresion/$1', ['as' => 'addLineaPedidoImpresion2Factura']);
$routes->get('deleteLinea/(:any)', 'FacturasLineas::deleteLinea/$1', ['as' => 'deleteLineaFactura']);
$routes->get('delete/(:any)', 'Facturas::delete/$1', ['as' => 'borrarFactura']);
$routes->post('deleteFacturaLineaPedido', 'Facturas::deleteLineaPedidoImpresion', ['as' => 'deleteLineaPedidoImpresion']);
$routes->post('editorLineas', 'FacturasLineas::datatable_editor', ['as' => 'editorOfLineasFacturas']);
$routes->post('updateTotales/(:any)', 'Facturas::updateTotales/$1', ['as' => 'updateFacturaTotales']);
$routes->post('updateCabecera/(:any)', 'Facturas::updateCabecera/$1', ['as' => 'updateCabecera']);
$routes->post('datatablePagos/(:any)', 'FacturasPagos::datatable/$1', ['as' => 'dataTableOfPagosFacturas']);
$routes->post('editorPagos', 'FacturasPagos::datatable_editor', ['as' => 'editorOfPagosFacturas']);
$routes->post('datatablePedidos', 'Facturas::datatablePedidos', ['as' => 'dataTableOfFacturasPedido']);
}); });
$routes->group( $routes->group(
'printpresupuestos', 'printpresupuestos',
['namespace' => 'App\Controllers\Pdf'], ['namespace' => 'App\Controllers\Pdf'],

View File

@ -312,10 +312,6 @@ class Cliente extends \App\Controllers\BaseResourceController
$onlyActiveOnes = false; $onlyActiveOnes = false;
try{ try{
$menu = $this->model->getSelect2MenuItems($columns2select, $columns2select[1], $onlyActiveOnes, $searchStr); $menu = $this->model->getSelect2MenuItems($columns2select, $columns2select[1], $onlyActiveOnes, $searchStr);
$nonItem = new \stdClass;
$nonItem->id = '';
$nonItem->text = '- ' . lang('Basic.global.None') . ' -';
array_unshift($menu, $nonItem);
} }
catch(Exception $e){ catch(Exception $e){
$menu = []; $menu = [];

View File

@ -238,10 +238,24 @@ class SeriesFacturas extends BaseResourceController
$onlyActiveOnes = false; $onlyActiveOnes = false;
$menu = $this->model->getSelect2MenuItems($columns2select, $columns2select[1], $onlyActiveOnes, $searchStr); $menu = $this->model->getSelect2MenuItems($columns2select, $columns2select[1], $onlyActiveOnes, $searchStr);
$nonItem = new \stdClass; $nonItem = new \stdClass;
$nonItem->id = '';
$nonItem->text = '- ' . lang('Basic.global.None') . ' -'; $newTokenHash = csrf_hash();
array_unshift($menu, $nonItem); $csrfTokenName = csrf_token();
$data = [
'menu' => $menu,
$csrfTokenName => $newTokenHash
];
return $this->respond($data);
} else {
return $this->failUnauthorized('Invalid request', 403);
}
}
public function menuItemsFacturas()
{
if ($this->request->isAJAX()) {
$menu = $this->model->getMenuItemsFacturas();
$newTokenHash = csrf_hash(); $newTokenHash = csrf_hash();
$csrfTokenName = csrf_token(); $csrfTokenName = csrf_token();
$data = [ $data = [

View File

@ -1,4 +1,4 @@
<?php namespace App\Controllers\Configuracion; <?php namespace App\Controllers\Configuracion;
use App\Entities\Usuarios\UserEntity; use App\Entities\Usuarios\UserEntity;
@ -8,15 +8,17 @@ use App\Models\Usuarios\GroupModel;
use App\Models\UserModel; use App\Models\UserModel;
use App\Models\Usuarios\GroupsUsersModel; use App\Models\Usuarios\GroupsUsersModel;
use CodeIgniter\Shield\Entities\User; use CodeIgniter\Shield\Entities\User;
use function PHPUnit\Framework\isNull;
class Users extends \App\Controllers\GoBaseController { class Users extends \App\Controllers\GoBaseController
{
private $group_model; private $group_model;
private $group_user_model; private $group_user_model;
private $user_model; private $user_model;
use \CodeIgniter\API\ResponseTrait; use \CodeIgniter\API\ResponseTrait;
protected static $primaryModelName = 'App\Models\UserModel'; protected static $primaryModelName = 'App\Models\UserModel';
@ -29,9 +31,9 @@ class Users extends \App\Controllers\GoBaseController {
protected $indexRoute = 'userList'; protected $indexRoute = 'userList';
public function initController(\CodeIgniter\HTTP\RequestInterface $request, \CodeIgniter\HTTP\ResponseInterface $response, \Psr\Log\LoggerInterface $logger) { public function initController(\CodeIgniter\HTTP\RequestInterface $request, \CodeIgniter\HTTP\ResponseInterface $response, \Psr\Log\LoggerInterface $logger)
{
$this->group_model = new GroupModel(); $this->group_model = new GroupModel();
$this->group_user_model = new GroupsUsersModel(); $this->group_user_model = new GroupsUsersModel();
@ -46,72 +48,80 @@ class Users extends \App\Controllers\GoBaseController {
]; ];
parent::initController($request, $response, $logger); parent::initController($request, $response, $logger);
} }
public function index() { public function index()
{
$this->viewData['usingClientSideDataTable'] = true; $this->viewData['usingClientSideDataTable'] = true;
$this->viewData['pageSubTitle'] = lang('Basic.global.ManageAllRecords', [lang('Users.user')]); $this->viewData['pageSubTitle'] = lang('Basic.global.ManageAllRecords', [lang('Users.user')]);
$this->viewData['user_model'] = $this->user_model; $this->viewData['user_model'] = $this->user_model;
$this->viewData['userList2'] = auth()->getProvider()->findAll();
$this->viewData['userList2'] = $this->user_model->getUsersList();
parent::index(); parent::index();
} }
public function add() { public function add()
{
if ($this->request->getPost()) : if ($this->request->getPost()) :
$postData = $this->request->getPost(); $postData = $this->request->getPost();
$currentGroups = $postData['group']??[]; // Obtener contraseña nueva si se ha introducido en texto plano
if (empty($postData['new_pwd'])) {
$postData['password'] = 'Safekat2024'; // Contraseña por defecto
}else{
$postData['password'] = $postData['new_pwd'];
}
// Obtener los grupos a los que pertenece
$currentGroups = $postData['group'] ?? [];
unset($postData['group']); unset($postData['group']);
// Generar el nombre de usuario
$postData['username'] = strstr($postData['email'], '@', true); $postData['username'] = strstr($postData['email'], '@', true);
$sanitizedData = $this->sanitized($postData, true); $sanitizedData = $this->sanitized($postData, true);
$noException = true; $noException = true;
// Obtener proveedor de usuarios
$users = auth()->getProvider(); $users = auth()->getProvider();
if ($successfulResult = $this->canValidate()) : // if ($successfulResult = $this->validate($this->formValidationRules) ) : if ($successfulResult = $this->canValidate()) :
if ($this->canValidate()) : if ($this->canValidate()) :
try { try {
$user = new User([ $user = new User([
'username' => $sanitizedData['username'], 'username' => $sanitizedData['username'],
'first_name' => $sanitizedData['first_name'], 'first_name' => $sanitizedData['first_name'],
'last_name' => $sanitizedData['last_name'], 'last_name' => $sanitizedData['last_name'],
'email' => $sanitizedData['email'], 'email' => $sanitizedData['email'],
'password' => 'Safekat2024', 'password' => $sanitizedData['password'],
'status' => $sanitizedData['status']??0, 'status' => $sanitizedData['status'] ?? 0,
'active' => $sanitizedData['active']??0, 'active' => $sanitizedData['active'] ?? 0,
]); ]);
$users->save($user); $users->save($user);
$successfulResult = true; // Hacked $successfulResult = true; // Hacked
} catch (\Exception $e) { } catch (\Exception $e) {
$noException = false; $noException = false;
//$this->dealWithException($e); //$this->dealWithException($e);
if (strpos($e->getMessage(), 'correo duplicado') !== false) { if (strpos($e->getMessage(), 'correo duplicado') !== false) {
$this->viewData['errorMessage'] = "El correo electrónico ya está registrado en el sistema"; $this->viewData['errorMessage'] = "El correo electrónico ya está registrado en el sistema";
$this->session->setFlashdata('formErrors', $this->model->errors()); $this->session->setFlashdata('formErrors', $this->model->errors());
} }
} }
else: else:
$this->viewData['errorMessage'] = lang('Basic.global.formErr1', [mb_strtolower(lang('Users.user'))]); $this->viewData['errorMessage'] = lang('Basic.global.formErr1', [mb_strtolower(lang('Users.user'))]);
$this->session->setFlashdata('formErrors', $this->model->errors()); $this->session->setFlashdata('formErrors', $this->model->errors());
endif; endif;
$thenRedirect = true; // Change this to false if you want your user to stay on the form after submission $thenRedirect = true; // Change this to false if you want your user to stay on the form after submission
endif; endif;
if ($noException && $successfulResult) : if ($noException && $successfulResult) :
$id = $users->getInsertID(); $id = $users->getInsertID();
$this->group_user_model->where('user_id', $id)->delete(); $this->group_user_model->where('user_id', $id)->delete();
foreach($currentGroups as $group){ foreach ($currentGroups as $group) {
$group_user_data = [ $group_user_data = [
'user_id' => $id, 'user_id' => $id,
'group' => $group 'group' => $group
@ -119,8 +129,7 @@ class Users extends \App\Controllers\GoBaseController {
$this->group_user_model->insert($group_user_data); $this->group_user_model->insert($group_user_data);
} }
$message = lang('Basic.global.saveSuccess', [mb_strtolower(lang('Users.user'))]) . 'Downloads'; $message = lang('Basic.global.saveSuccess', [mb_strtolower(lang('Users.user'))]) . '.';
$message .= anchor(route_to('editUser', $id), lang('Basic.global.continueEditing').'?');
$message = ucfirst(str_replace("'", "\'", $message)); $message = ucfirst(str_replace("'", "\'", $message));
if ($thenRedirect) : if ($thenRedirect) :
@ -141,88 +150,92 @@ class Users extends \App\Controllers\GoBaseController {
$this->viewData['clienteList'] = $this->getClienteListItems(); $this->viewData['clienteList'] = $this->getClienteListItems();
$this->viewData['formAction'] = route_to('createUser'); $this->viewData['formAction'] = route_to('createUser');
$this->viewData['groups'] = $this->group_model->select('keyword, title')->findAll(); $this->viewData['groups'] = $this->group_model->select('keyword, title')->findAll();
$this->viewData['boxTitle'] = lang('Basic.global.addNew') .lang('Users.user').' '.lang('Basic.global.addNewSuffix'); $this->viewData['boxTitle'] = lang('Basic.global.addNew') . ' ' . lang('Users.user') . ' ' . lang('Basic.global.addNewSuffix');
return $this->displayForm(__METHOD__); return $this->displayForm(__METHOD__);
} // end function add() } // end function add()
public function edit($requestedId = null) { public function edit($requestedId = null)
{
if ($requestedId == null) : if ($requestedId == null) {
return $this->redirect2listView(); return $this->redirect2listView();
endif; }
$id = filter_var($requestedId, FILTER_SANITIZE_URL); $id = filter_var($requestedId, FILTER_SANITIZE_URL);
$user = $this->model->find($id); $users = auth()->getProvider();
$user = $users->findById($id);
if ($user == false) : if ($user == false) :
$message = lang('Basic.global.notFoundWithIdErr', [mb_strtolower(lang('Users.user')), $id]); $message = lang('Basic.global.notFoundWithIdErr', [mb_strtolower(lang('Users.user')), $id]);
return $this->redirect2listView('errorMessage', $message); return $this->redirect2listView('errorMessage', $message);
endif; endif;
if ($this->request->getPost()) : if ($this->request->getPost()) :
$postData = $this->request->getPost(); $postData = $this->request->getPost();
$currentGroups = $postData['group']; $currentGroups = $postData['group'] ?? [];
unset($postData['group']); unset($postData['group']);
// Obtener contraseña nueva si se ha introducido en texto plano
// Obtener contraseña nueva si se ha introducido en texto plano
if (!empty($postData['new_pwd'])) {
$postData['password'] = $postData['new_pwd'];
}
$sanitizedData = $this->sanitized($postData, true); $sanitizedData = $this->sanitized($postData, true);
if ($this->request->getPost('status') == 0 ) { if ($this->request->getPost('status') == 0) {
$sanitizedData['status'] = null; $sanitizedData['status'] = null;
} }
$noException = true; $noException = true;
if ($successfulResult = $this->canValidate()) : // if ($successfulResult = $this->validate($this->formValidationRules) ) : if ($successfulResult = $this->canValidate()) :
if ($this->canValidate()) :
try {
if ($this->canValidate()) :
try {
if (in_array('cliente-editor', $currentGroups) || in_array('cliente-administrador', $currentGroups)) { if (in_array('cliente-editor', $currentGroups) || in_array('cliente-administrador', $currentGroups)) {
if(!array_key_exists('cliente_id', $sanitizedData) || is_null($sanitizedData['cliente_id'])) { if (!array_key_exists('cliente_id', $sanitizedData) || is_null($sanitizedData['cliente_id'])) {
$this->viewData['errorMessage'] = lang('Users.errors.cliente_sin_clienteID'); $this->viewData['errorMessage'] = lang('Users.errors.cliente_sin_clienteID');
$this->session->setFlashdata('formErrors', $this->model->errors()); $this->session->setFlashdata('formErrors', $this->model->errors());
$successfulResult = false; $successfulResult = false;
} else {
$successfulResult = $this->model->skipValidation(true)->update($id, $sanitizedData);
} }
else{ } else {
$successfulResult = $this->model->skipValidation(true)->update($id, $sanitizedData);
}
}
else {
$successfulResult = $this->model->skipValidation(true)->update($id, $sanitizedData); $successfulResult = $this->model->skipValidation(true)->update($id, $sanitizedData);
} }
} catch (\Exception $e) {
} catch (\Exception $e) { $noException = false;
$noException = false; $this->dealWithException($e);
$this->dealWithException($e); }
} else:
else: $this->viewData['warningMessage'] = lang('Basic.global.formErr1', [mb_strtolower(lang('Users.user'))]);
$this->viewData['warningMessage'] = lang('Basic.global.formErr1', [mb_strtolower(lang('Users.user'))]); $this->session->setFlashdata('formErrors', $this->model->errors());
$this->session->setFlashdata('formErrors', $this->model->errors());
endif;
$user->fill($sanitizedData); endif;
$thenRedirect = false;
$user->fill($sanitizedData);
$users->save($user);
$thenRedirect = false;
endif; endif;
if ($noException && $successfulResult) : if ($noException && $successfulResult) :
$this->group_user_model->where('user_id', $user->id)->delete(); $this->group_user_model->where('user_id', $user->id)->delete();
foreach($currentGroups as $group){ foreach ($currentGroups as $group) {
$group_user_data = [ $group_user_data = [
'user_id' => $user->id, 'user_id' => $user->id,
'group' => $group 'group' => $group
]; ];
$this->group_user_model->insert($group_user_data); $this->group_user_model->insert($group_user_data);
} }
$id = $user->id ?? $id; $id = $user->id ?? $id;
$message = lang('Basic.global.updateSuccess', [mb_strtolower(lang('Users.user'))]) . 'Downloads'; $message = lang('Basic.global.updateSuccess', [mb_strtolower(lang('Users.user'))]) . '.';
$message .= anchor(route_to('editUser', $id), lang('Basic.global.continueEditing').'?');
$message = ucfirst(str_replace("'", "\'", $message)); $message = ucfirst(str_replace("'", "\'", $message));
if ($thenRedirect) : if ($thenRedirect) :
@ -234,7 +247,7 @@ class Users extends \App\Controllers\GoBaseController {
else: else:
$this->session->setFlashData('sweet-success', $message); $this->session->setFlashData('sweet-success', $message);
endif; endif;
endif; // $noException && $successfulResult endif; // $noException && $successfulResult
endif; // ($requestMethod === 'post') endif; // ($requestMethod === 'post')
@ -243,13 +256,14 @@ class Users extends \App\Controllers\GoBaseController {
$this->viewData['formAction'] = route_to('updateUser', $id); $this->viewData['formAction'] = route_to('updateUser', $id);
$this->viewData['selectedGroups'] = $this->group_model->getUsersRoles($requestedId); $this->viewData['selectedGroups'] = $this->group_model->getUsersRoles($requestedId);
$this->viewData['groups'] = $this->group_model->select('keyword, title')->findAll(); $this->viewData['groups'] = $this->group_model->select('keyword, title')->findAll();
$this->viewData['boxTitle'] = lang('Basic.global.edit2') .lang('Users.user').' '.lang('Basic.global.edit3'); $this->viewData['boxTitle'] = lang('Basic.global.edit2') . ' ' . lang('Users.user') . ' ' . lang('Basic.global.edit3');
return $this->displayForm(__METHOD__, $id); return $this->displayForm(__METHOD__, $id);
} // end function edit(...) } // end function edit(...)
public function delete($requestedId = null, bool $deletePermanently = true) { public function delete($requestedId = null, bool $deletePermanently = true)
{
if ($requestedId == null) : if ($requestedId == null) :
return $this->redirect2listView(); return $this->redirect2listView();
@ -264,26 +278,25 @@ class Users extends \App\Controllers\GoBaseController {
endif; endif;
$users = auth()->getProvider(); $users = auth()->getProvider();
$users->delete($user->id, $deletePermanently); $users->delete($user->id);
$message = "Usuario eliminado correctamente"; $message = "Usuario eliminado correctamente";
return $this->redirect2listView('successMessage', $message); return $this->redirect2listView('successMessage', $message);
} // end function delete(...) } // end function delete(...)
public function allItemsSelect() {
public function allItemsSelect()
{
if ($this->request->isAJAX()) { if ($this->request->isAJAX()) {
$onlyActiveOnes = true; $onlyActiveOnes = true;
$reqVal = $this->request->getPost('val') ?? 'id_user'; $reqVal = $this->request->getPost('val') ?? 'id_user';
$menu = $this->model->getAllForMenu($reqVal.', first_name', 'first_name', $onlyActiveOnes, false); $menu = $this->model->getAllForMenu($reqVal . ', first_name', 'first_name', $onlyActiveOnes, false);
$nonItem = new \stdClass; $nonItem = new \stdClass;
$nonItem->id_user = ''; $nonItem->id_user = '';
$nonItem->first_name = '- '.lang('Basic.global.None').' -'; $nonItem->first_name = '- ' . lang('Basic.global.None') . ' -';
array_unshift($menu , $nonItem); array_unshift($menu, $nonItem);
$newTokenHash = csrf_hash(); $newTokenHash = csrf_hash();
$csrfTokenName = csrf_token(); $csrfTokenName = csrf_token();
@ -296,8 +309,9 @@ class Users extends \App\Controllers\GoBaseController {
return $this->failUnauthorized('Invalid request', 403); return $this->failUnauthorized('Invalid request', 403);
} }
} }
public function menuItems() { public function menuItems()
{
if ($this->request->isAJAX()) { if ($this->request->isAJAX()) {
$searchStr = goSanitize($this->request->getPost('searchTerm'))[0]; $searchStr = goSanitize($this->request->getPost('searchTerm'))[0];
$reqId = goSanitize($this->request->getPost('id'))[0]; $reqId = goSanitize($this->request->getPost('id'))[0];
@ -308,8 +322,8 @@ class Users extends \App\Controllers\GoBaseController {
$menu = $this->model->getSelect2MenuItems($columns2select, $columns2select[1], $onlyActiveOnes, $searchStr); $menu = $this->model->getSelect2MenuItems($columns2select, $columns2select[1], $onlyActiveOnes, $searchStr);
$nonItem = new \stdClass; $nonItem = new \stdClass;
$nonItem->id = ''; $nonItem->id = '';
$nonItem->text = '- '.lang('Basic.global.None').' -'; $nonItem->text = '- ' . lang('Basic.global.None') . ' -';
array_unshift($menu , $nonItem); array_unshift($menu, $nonItem);
$newTokenHash = csrf_hash(); $newTokenHash = csrf_hash();
$csrfTokenName = csrf_token(); $csrfTokenName = csrf_token();
@ -323,10 +337,11 @@ class Users extends \App\Controllers\GoBaseController {
} }
} }
public function getMenuComerciales(){ public function getMenuComerciales()
{
if ($this->request->isAJAX()) { if ($this->request->isAJAX()) {
$comerciales = $this->model->getComerciales(); $comerciales = $this->model->getComerciales();
$newTokenHash = csrf_hash(); $newTokenHash = csrf_hash();
$csrfTokenName = csrf_token(); $csrfTokenName = csrf_token();
$data = [ $data = [
@ -339,15 +354,16 @@ class Users extends \App\Controllers\GoBaseController {
} }
} }
protected function getPaisListItems() { protected function getPaisListItems()
$data = [''=>lang('Basic.global.pleaseSelectA', [mb_strtolower(lang('Pais.pais'))])]; {
$data = ['' => lang('Basic.global.pleaseSelectA', [mb_strtolower(lang('Pais.pais'))])];
$paisModel = model('App\Models\Configuracion\PaisModel'); $paisModel = model('App\Models\Configuracion\PaisModel');
$registers = $paisModel->findAll(); $registers = $paisModel->findAll();
return $registers; return $registers;
} }
protected function getClienteListItems($selId = null) protected function getClienteListItems($selId = null)
{ {
@ -362,5 +378,5 @@ class Users extends \App\Controllers\GoBaseController {
endif; endif;
return $data; return $data;
} }
} }

View File

@ -3,6 +3,8 @@
namespace App\Controllers\Facturacion; namespace App\Controllers\Facturacion;
use App\Models\Facturas\FacturaModel; use App\Models\Facturas\FacturaModel;
use App\Entities\Facturas\FacturaEntity;
use App\Models\Clientes\ClienteModel;
use App\Models\Collection; use App\Models\Collection;
@ -22,14 +24,14 @@ class Facturas extends \App\Controllers\BaseResourceController
public function initController(\CodeIgniter\HTTP\RequestInterface $request, \CodeIgniter\HTTP\ResponseInterface $response, \Psr\Log\LoggerInterface $logger) public function initController(\CodeIgniter\HTTP\RequestInterface $request, \CodeIgniter\HTTP\ResponseInterface $response, \Psr\Log\LoggerInterface $logger)
{ {
$this->viewData['pageTitle'] = lang('Pedidos.moduleTitle'); $this->viewData['pageTitle'] = lang('Facturas.facturas');
// Se indica que este controlador trabaja con soft_delete // Se indica que este controlador trabaja con soft_delete
$this->viewData = ['usingServerSideDataTable' => true]; $this->viewData = ['usingServerSideDataTable' => true];
// Breadcrumbs // Breadcrumbs
$this->viewData['breadcrumb'] = [ $this->viewData['breadcrumb'] = [
['title' => lang("App.menu_pedidos"), 'route' => "javascript:void(0);", 'active' => false], ['title' => lang("App.menu_facturas"), 'route' => "javascript:void(0);", 'active' => false],
]; ];
parent::initController($request, $response, $logger); parent::initController($request, $response, $logger);
@ -51,10 +53,9 @@ class Facturas extends \App\Controllers\BaseResourceController
$viewData = [ $viewData = [
'currentModule' => static::$controllerSlug, 'currentModule' => static::$controllerSlug,
'pageSubTitle' => lang('Basic.global.ManageAllRecords', [lang('Pedidos.pedido')]), 'pageSubTitle' => lang('Basic.global.ManageAllRecords', [lang('Facturas.facturas')]),
'usingServerSideDataTable' => true, 'usingServerSideDataTable' => true,
'pageTitle' => lang('Facturas.facturas'), 'pageTitle' => lang('Facturas.facturas'),
'estadoPedidos' => 'todos',
['title' => lang("App.menu_facturas"), 'route' => site_url('facturas/list'), 'active' => true] ['title' => lang("App.menu_facturas"), 'route' => site_url('facturas/list'), 'active' => true]
]; ];
@ -66,6 +67,128 @@ class Facturas extends \App\Controllers\BaseResourceController
return view(static::$viewPath . 'viewFacturasList', $viewData); return view(static::$viewPath . 'viewFacturasList', $viewData);
} }
public function add()
{
if ($this->request->getPost()) :
$nullIfEmpty = true; // !(phpversion() >= '8.1');
$postData = $this->request->getPost();
$noException = true;
$allData = true;
if( !isset($postData['cliente_id']) || !isset($postData['serie_id']) ) {
$this->viewData['errorMessage'] = lang('Facturas.errors.requiredFields');
$this->session->setFlashdata('formErrors', $this->model->errors());
$allData = false;
$noException = false;
}
try {
$clienteModel = model('App\Models\Clientes\ClienteModel');
$datosCliente = $clienteModel->getClienteDataFacturas($postData['cliente_id']);
if(count($datosCliente)>0){
// add array data datosCliente to postData
$postData = array_merge($postData, $datosCliente[0]);
}
} catch (\Exception $e) {
$noException = false;
$this->dealWithException($e);
}
$sanitizedData = $this->sanitized($postData, $nullIfEmpty);
$sanitizedData['user_updated_id'] = auth()->user()->id;
$sanitizedData['user_created_id'] = auth()->user()->id;
if ($allData && $successfulResult = $this->canValidate()) : // if ($successfulResult = $this->validate($this->formValidationRules) ) :
if ($this->canValidate()) :
try {
$successfulResult = $this->model->skipValidation(true)->save($sanitizedData);
} catch (\Exception $e) {
$noException = false;
$this->dealWithException($e);
}
else:
$this->viewData['errorMessage'] = lang('Basic.global.formErr1', [lang('Basic.global.record')]);
$this->session->setFlashdata('formErrors', $this->model->errors());
endif;
endif;
if ($noException && $successfulResult) :
$id = $this->model->db->insertID();
$message = lang('Basic.global.saveSuccess', [lang('Basic.global.record')]) . '.';
return redirect()->to(route_to('editarFactura', $id))->with('sweet-success', $message);
endif; // $noException && $successfulResult
endif; // ($requestMethod === 'post')
$this->viewData['factura'] = isset($sanitizedData) ? new FacturaEntity($sanitizedData) : new FacturaEntity();
$this->viewData['formAction'] = route_to('createFactura');
$this->viewData['boxTitle'] = lang('Basic.global.addNew') . ' ' . lang('Facturas.facturas') . ' ' . lang('Basic.global.addNewSuffix');
helper('form');
$this->viewData['breadcrumb'] = [
['title' => lang("App.menu_facturas"), 'route' => "javascript:void(0);", 'active' => false],
['title' => lang("Facturas.facturaList"), 'route' => route_to('facturasList'), 'active' => true]
];
$this->viewData['usingSelect2'] = true;
$validation = \Config\Services::validation();
$this->viewData['validation'] = $validation;
$viewFilePath = static::$viewPath . 'viewAddFactura';
return view($viewFilePath, $this->viewData);
} // end function add()
public function edit($id=null){
if ($id == null) :
return $this->redirect2listView();
endif;
$id = filter_var($id, FILTER_SANITIZE_URL);
$factura = $this->model->find($id);
if ($factura == false) :
$message = lang('Basic.global.notFoundWithIdErr', [mb_strtolower(lang('Facturas.factura')), $id]);
return $this->redirect2listView('sweet-error', $message);
endif;
$this->obtenerDatosFormulario($factura);
$this->viewData['breadcrumb'] = [
['title' => lang("App.menu_facturas"), 'route' => "javascript:void(0);", 'active' => false],
['title' => lang("Facturas.facturaList"), 'route' => route_to('facturasList'), 'active' => true]
];
$this->viewData['facturaEntity'] = $factura;
$this->viewData['boxTitle'] = lang('Basic.global.edit2') . ' ' . lang('Facturas.factura') . ' ' . lang('Basic.global.edit3');
return $this->displayForm(__METHOD__, $id);
}
public function datatable(){ public function datatable(){
if ($this->request->isAJAX()) { if ($this->request->isAJAX()) {
@ -87,13 +210,425 @@ class Facturas extends \App\Controllers\BaseResourceController
return $this->respond(Collection::datatable( return $this->respond(Collection::datatable(
$resourceData, $resourceData,
$model_linea->getResource("")->countAllResults(), $this->model->getResource("")->countAllResults(),
$model_linea->getResource($search)->countAllResults() $this->model->getResource($search)->countAllResults()
)); ));
} else { } else {
return $this->failUnauthorized('Invalid request', 403); return $this->failUnauthorized('Invalid request', 403);
} }
} }
public function datatablePedidos(){
if ($this->request->isAJAX()) {
$reqData = $this->request->getPost();
if (!isset($reqData['draw']) || !isset($reqData['columns']) ) {
$errstr = 'No data available in response to this specific request.';
$response = $this->respond(Collection::datatable( [], 0, 0, $errstr ), 400, $errstr);
return $response;
}
$start = $reqData['start'] ?? 0;
$length = $reqData['length'] ?? 5;
$search = $reqData['search']['value'];
$requestedOrder = $reqData['order']['0']['column'] ?? 0;
$order = FacturaModel::SORTABLE_PEDIDOS[$requestedOrder >= 0 ? $requestedOrder : 0];
$dir = $reqData['order']['0']['dir'] ?? 'asc';
$pedido_id = $reqData['pedido_id'] ?? 0;
$resourceData = $this->model->getResourcePedidos($pedido_id)->orderBy($order, $dir)->limit($length, $start)->get()->getResultObject();
return $this->respond(Collection::datatable(
$resourceData,
$this->model->getResourcePedidos($pedido_id)->countAllResults(),
$this->model->getResourcePedidos($pedido_id)->countAllResults()
));
} else {
return $this->failUnauthorized('Invalid request', 403);
}
}
public function update($id = null){
if ($this->request->isAJAX()) {
$newTokenHash = csrf_hash();
$csrfTokenName = csrf_token();
if ($id == null) :
$data = [
'error' => 2,
$csrfTokenName => $newTokenHash
];
return $this->respond($data);
endif;
$id = filter_var($id, FILTER_SANITIZE_URL);
$facturaEntity = $this->model->find($id);
if ($facturaEntity == false) :
$message = lang('Basic.global.notFoundWithIdErr', [mb_strtolower(lang('Factura.factura')), $id]);
$data = [
'error' => $message,
$csrfTokenName => $newTokenHash
];
return $this->respond($data);
endif;
if ($this->request->getPost()) :
$nullIfEmpty = true; // !(phpversion() >= '8.1');
$postData = $this->request->getPost();
$sanitizedData = $this->sanitized($postData, $nullIfEmpty);
// JJO
$sanitizedData['user_updated_id'] = auth()->user()->id;
$noException = true;
if ($successfulResult = $this->canValidate()) : // if ($successfulResult = $this->validate($this->formValidationRules) ) :
if ($this->canValidate()) :
try {
$successfulResult = $this->model->skipValidation(true)->update($id, $sanitizedData);
} catch (\Exception $e) {
$noException = false;
$this->dealWithException($e);
}
else:
$this->viewData['warningMessage'] = lang('Basic.global.formErr1', [mb_strtolower(lang('Facturas.factura'))]);
$this->session->setFlashdata('formErrors', $this->model->errors());
endif;
$facturaEntity->fill($sanitizedData);
endif;
if ($noException && $successfulResult) :
$id = $facturaEntity->id ?? $id;
$message = lang('Basic.global.updateSuccess', [lang('Basic.global.record')]) . '.';
$data = [
'error' => 0,
$csrfTokenName => $newTokenHash
];
return $this->respond($data);
endif; // $noException && $successfulResult
endif; // ($requestMethod === 'post')
$data = [
'error' => 1,
$csrfTokenName => $newTokenHash
];
return $this->respond($data);
}
else {
return $this->failUnauthorized('Invalid request', 403);
}
}
public function menuPedidosPendientes($cliente_id){
if ($this->request->isAJAX()) {
$model = model('\App\Models\Pedidos\PedidoLineaModel');
$pedidos = [];
try{
$pedidos = $model->obtenerLineasPedidoSinFacturar($cliente_id);
}
catch(Exception $e){
}
$newTokenHash = csrf_hash();
$csrfTokenName = csrf_token();
$data = [
'menu' => $pedidos,
$csrfTokenName => $newTokenHash
];
return $this->respond($data);
}
else {
return $this->failUnauthorized('Invalid request', 403);
}
}
public function duplicate($factura_id = 0){
if($this->request->isAJAX()){
$factura_origen = $this->model->find($factura_id);
// se quita la key "id" del objeto
unset($factura_origen->id);
$factura_origen->estado = 'borrador';
$factura_origen->estado_pago = 'pendiente';
$factura_origen->base = 0;
$factura_origen->total = 0;
$factura_origen->pendiente = 0;
$factura_origen->total_pagos = 0;
$factura_origen->user_created_id = auth()->user()->id;
$factura_origen->user_updated_id = null;
$this->model->insert($factura_origen);
$id = $this->model->getInsertID();
$newTokenHash = csrf_hash();
$csrfTokenName = csrf_token();
$data = [
'id' => $id,
$csrfTokenName => $newTokenHash
];
return $this->respond($data);
}else{
return $this->failUnauthorized('Invalid request', 403);
}
}
public function updateTotales($factura_id = 0){
if($this->request->isAJAX()){
$postData = $this->request->getPost();
$data = [
'base' => $postData['base'] ?? 0,
'total' => $postData['total'] ?? 0,
'pendiente' => $postData['pendiente'] ?? 0,
'total_pagos' => $postData['total_pagos'] ?? 0,
'user_updated_id' => auth()->user()->id,
'estado_pago' => (intval($postData['pendiente'] ?? 0)==0) ? 'pagada' : 'pendiente',
];
$newTokenHash = csrf_hash();
$csrfTokenName = csrf_token();
$data_ret = [
$csrfTokenName => $newTokenHash
];
if($factura_id == 0){
return $this->respond($data_ret);
}
$data_ret['estado_pago'] = $data['estado_pago'];
$model = model('\App\Models\Facturas\FacturaModel');
$model->update($factura_id, $data);
return $this->respond($data_ret);
}
else {
return $this->failUnauthorized('Invalid request', 403);
}
}
public function addLineaPedidoImpresion($factura_id){
if ($this->request->isAJAX()) {
$model_pedido_linea = model('\App\Models\Pedidos\PedidoLineaModel');
$model_presupuesto = model('\App\Models\Presupuestos\PresupuestoModel');
$model_factura_linea = model('\App\Models\Facturas\FacturaLineaModel');
try{
$pedido_linea_id = $this->request->getPost('lineaPedido') ?? 0;
$linea = $model_pedido_linea->find($pedido_linea_id);
if($linea){
$presupuesto = $model_presupuesto->find($linea->presupuesto_id);
if($presupuesto){
// Se añade la linea de factura
$descripcion = $model_presupuesto->generarLineaPedido($presupuesto->id, true, $linea->pedido_id);
$cantidad = intval($presupuesto->tirada) - intval($this->model->getCantidadLineaPedidoFacturada($linea->id));
$base = $cantidad * floatval($presupuesto->total_precio_unidad);
$total_iva = $base * ($presupuesto->iva_reducido==1 ? 0.04 : 0.21);
// se redondea a dos decimales
$total_iva = round($total_iva, 2);
$total = $base + $total_iva;
$data = (object)[
'factura_id'=>$factura_id,
'pedido_linea_impresion_id'=>$linea->pedido_id,
'descripcion'=>$descripcion[0]->concepto,
'cantidad'=>$cantidad,
'precio_unidad'=>$presupuesto->total_precio_unidad,
'iva' => $presupuesto->iva_reducido==1 ? 4 : 21,
'base' => $base,
'total_iva' => $total_iva,
'total' => $total,
'user_updated_id' => auth()->user()->id,
];
$model_factura_linea->insert($data);
$id = $model_factura_linea->getInsertID();
if($id){
$model_factura_linea->addFacturaPedidoLinea($factura_id, $linea->id, $cantidad);
$newTokenHash = csrf_hash();
$csrfTokenName = csrf_token();
$data = [
'error' => 0,
'id' => $id,
$csrfTokenName => $newTokenHash
];
return $this->respond($data);
}
}
}
}
catch(Exception $e){
}
$newTokenHash = csrf_hash();
$csrfTokenName = csrf_token();
$data = [
$csrfTokenName => $newTokenHash
];
return $this->respond($data);
}
else {
return $this->failUnauthorized('Invalid request', 403);
}
}
public function deleteLineaPedidoImpresion(){
if ($this->request->isAJAX()) {
$postData = $this->request->getPost();
$factura_id = $postData['factura_id'] ?? 0;
$linea_id = $postData['linea_id'] ?? 0;
$cantidad = $postData['cantidad'] ?? 0;
$model_factura_linea = model('\App\Models\Facturas\FacturaLineaModel');
$model_factura_linea->deleteFacturasLineasPedido($factura_id, $linea_id, $cantidad);
$newTokenHash = csrf_hash();
$csrfTokenName = csrf_token();
$data = [
$csrfTokenName => $newTokenHash
];
return $this->respond($data);
}
else {
return $this->failUnauthorized('Invalid request', 403);
}
}
public function validar($factura_id){
if($this->request->isAJAX()){
$factura = $this->model->find($factura_id);
if($factura){
$model_series = model('\App\Models\Configuracion\SeriesFacturasModel');
$numero = $model_series->getSerieNumerada($factura->serie_id);
$data = [
'estado' => 'validada',
'numero' => $numero,
'user_updated_id' => auth()->user()->id,
];
if((strpos($numero, "REC ") === 0)){
$data['estado_pago'] = 'pagada';
}
$this->model->update($factura_id, $data);
}
$newTokenHash = csrf_hash();
$csrfTokenName = csrf_token();
$data = [
$csrfTokenName => $newTokenHash
];
return $this->respond($data);
}
else {
return $this->failUnauthorized('Invalid request', 403);
}
}
public function updateCabecera($factura_id){
if($this->request->isAJAX()){
if($factura_id == 0){
return;
}
$factura = $this->model->find($factura_id);
if($factura){
$postData = $this->request->getPost();
$dataName = $postData['name'] ?? '';
$dataValue = $postData['value'] ?? '';
if($dataName == 'factura_rectificativa_id'){
// se actualiza la factura donde el campo 'numero' sea igual al valor de $dataValue. El campo a actualizar es 'factura_rectificada_id'
$factura_rectificada = $this->model->where('numero', $dataValue)->first();
if($factura_rectificada){
$data2 = [
'factura_rectificada_id' => $factura->numero,
'user_updated_id' => auth()->user()->id,
];
$this->model->update($factura_rectificada->id, $data2);
}
}
$data = [
$dataName => $dataValue,
'user_updated_id' => auth()->user()->id,
];
$this->model->update($factura_id, $data);
$newTokenHash = csrf_hash();
$csrfTokenName = csrf_token();
$data = [
$csrfTokenName => $newTokenHash
];
return $this->respond($data);
}
}
else {
return $this->failUnauthorized('Invalid request', 403);
}
}
/*************************************
* FUNCIONES AUXILIARES
************************************/
private function obtenerDatosFormulario(&$factura){
if($factura->estado == 'borrador'){
$serieModel = model('App\Models\Configuracion\SeriesFacturasModel');
$serie = $serieModel->find($factura->serie_id);
if($serie){
$factura->numero = str_replace("{numero}", $serie->next, $serie->formato);
}
}
$clienteModel = model('App\Models\Clientes\ClienteModel');
$cliente = $clienteModel->find($factura->cliente_id);
$factura->cliente_alias = $cliente->alias;
$serieModel = model('App\Models\Configuracion\SeriesFacturasModel');
$serie = $serieModel->find($factura->serie_id);
$factura->serie_nombre = $serie->nombre;
$formaPagoModel = model('App\Models\Configuracion\FormaPagoModel');
$factura->formas_pago = $formaPagoModel->getMenuItems();
$factura->fecha_factura_at_text = $factura->fecha_factura_at ? date('d/m/Y', strtotime($factura->fecha_factura_at)) : '';
}
} }

View File

@ -0,0 +1,228 @@
<?php
namespace App\Controllers\Facturacion;
use App\Models\Facturas\FacturaLineaModel;
use App\Models\Collection;
use DataTables\Editor;
use DataTables\Editor\Field;
use DataTables\Editor\Validate;
class FacturasLineas extends \App\Controllers\BaseResourceController
{
protected $modelName = FacturaLineaModel::class;
protected $format = 'json';
protected static $controllerSlug = 'factura-lineas';
public function datatable($factura_id = null){
if ($this->request->isAJAX() && $factura_id != null) {
$reqData = $this->request->getPost();
if (!isset($reqData['draw']) || !isset($reqData['columns']) ) {
$errstr = 'No data available in response to this specific request.';
$response = $this->respond(Collection::datatable( [], 0, 0, $errstr ), 400, $errstr);
return $response;
}
$start = $reqData['start'] ?? 0;
$length = $reqData['length'] ?? 5;
$search = $reqData['search']['value'];
$requestedOrder = $reqData['order']['0']['column'] ?? 0;
//$order = FacturaModel::SORTABLE[$requestedOrder >= 0 ? $requestedOrder : 0];
$dir = $reqData['order']['0']['dir'] ?? 'asc';
$resourceData = $this->model->getResource($factura_id)->orderBy(1, $dir)->limit($length, $start)->get()->getResultObject();
return $this->respond(Collection::datatable(
$resourceData,
$this->model->getResource($factura_id)->countAllResults(),
$this->model->getResource($factura_id)->countAllResults()
));
} else {
return $this->failUnauthorized('Invalid request', 403);
}
}
public function deleteLinea($factura_linea_id = 0){
if (!empty(static::$pluralObjectNameCc) && !empty(static::$singularObjectNameCc)) {
$objName = mb_strtolower(lang(ucfirst(static::$pluralObjectNameCc).'.'.static::$singularObjectNameCc));
} else {
$objName = lang('Basic.global.record');
}
if($factura_linea_id == 0){
return $this->failNotFound(lang('Basic.global.deleteError', [$objName]));
}
$facturaLinea = $this->model->find($factura_linea_id);
if($facturaLinea == null){
return $this->failNotFound(lang('Basic.global.deleteError', [$objName]));
}
if($facturaLinea->pedido_linea_impresion_id != null){
$this->model->deleteFacturasLineasPedido($facturaLinea->factura_id, $facturaLinea->pedido_linea_impresion_id, $facturaLinea->cantidad);
}
if($facturaLinea->pedido_maquetacion_id != null){
//$this->model->deleteFacturasLineasPedido($facturaLinea->factura_id, $facturaLinea->pedido_maquetacion_id, $facturaLinea->cantidad);
}
$facturaLinea = $this->model->delete($factura_linea_id);
$message = lang('Basic.global.deleteSuccess', [lang('Basic.global.record')]);
$response = $this->respondDeleted(['id' => $factura_linea_id, 'msg' => $message]);
return $response;
}
public function datatable_editor() {
if ($this->request->isAJAX()) {
include(APPPATH . "ThirdParty/DatatablesEditor/DataTables.php");
// Build our Editor instance and process the data coming from _POST
$response = Editor::inst( $db, 'facturas_lineas' )
->fields(
Field::inst( 'id' ),
Field::inst( 'base' ),
Field::inst( 'total_iva' ),
Field::inst( 'total' ),
Field::inst( 'cantidad' )
->validator('Validate::numeric', array(
'message' => lang('Facturas.validation.numerico'))
)
->validator('Validate::notEmpty', array(
'message' => lang('Facturas.validation.requerido'))
),
Field::inst( 'descripcion' )
->validator('Validate::notEmpty', array(
'message' => lang('Facturas.validation.requerido'))
),
Field::inst( 'precio_unidad' )
->getFormatter( 'Format::toDecimalChar')->setFormatter( 'Format::fromDecimalChar')
->validator('Validate::numeric', array(
"decimal" => ',',
'message' => lang('Facturas.validation.decimal'))
)
->validator('Validate::notEmpty', array(
'message' => lang('Facturas.validation.requerido'))
),
Field::inst( 'iva' )
->validator('Validate::numeric', array(
'message' => lang('Facturas.validation.numerico'))
)
->validator('Validate::notEmpty', array(
'message' => lang('Facturas.validation.requerido'))
),
Field::inst( 'pedido_linea_impresion_id' )
->setFormatter(function($val, $data, $opts) {
return $val === '' ? null : $val;
}),
Field::inst( 'factura_id' ),
Field::inst( 'user_updated_id' ),
)
->on('preCreate', function ($editor, &$values) {
$totales = $this->generate_totales(
$values['factura_id'],
$values['pedido_linea_impresion_id'],
$values['precio_unidad'],
$values['iva'],
$values['cantidad'],
$values['old_cantidad']);
$editor
->field('user_updated_id')
->setValue(auth()->user()->id);
$editor
->field('base')
->setValue($totales['base']);
$editor
->field('total_iva')
->setValue($totales['total_iva']);
$editor
->field('total')
->setValue($totales['total']);
$editor
->field('user_updated_id')
->setValue(auth()->user()->id);
})
->on('preEdit', function ($editor, $id, &$values) {
$totales = $this->generate_totales(
$values['factura_id'],
$values['pedido_linea_impresion_id'],
$values['precio_unidad'],
$values['iva'],
$values['cantidad'],
$values['old_cantidad']);
$editor
->field('factura_id')
->setValue($values['factura_id']);
$editor
->field('pedido_linea_impresion_id')
->setValue(null);
$editor
->field('pedido_maquetacion_id')
->setValue(null);
$editor
->field('user_updated_id')
->setValue(auth()->user()->id);
$editor
->field('base')
->setValue($totales['base']);
$editor
->field('total_iva')
->setValue($totales['total_iva']);
$editor
->field('total')
->setValue($totales['total']);
})
->debug(true)
->process($_POST)
->data();
$newTokenHash = csrf_hash();
$csrfTokenName = csrf_token();
$response[$csrfTokenName] = $newTokenHash;
echo json_encode($response);
} else {
return $this->failUnauthorized('Invalid request', 403);
}
}
public function updateTotalesFactura($factura_id = 0){
if($factura_id == 0){
return;
}
$model = model('\App\Models\Facturas\FacturaModel');
$model->updateTotales($factura_id);
}
private function generate_totales($factura_id, $pedido_linea_id, $precio_unidad, $iva, $cantidad, $old_cantidad)
{
// si es una linea que se refiere a pedido
if ($pedido_linea_id != null && $factura_id != null) {
// se actualiza la cantidad de la linea de pedido en la tabla pivote facturas_pedidos_lineas
$this->model->updateFacturaPedidoLinea($factura_id, $pedido_linea_id, $old_cantidad, $cantidad);
}
// se calcula y se actualiza el subtotal, total_iva y total
// redondeando a 4 decimales el precio_unidad y a dos el resto
$base = round($precio_unidad * $cantidad, 2);
$total_iva = round($base * $iva / 100, 2);
$total = round($base + $total_iva, 2);
$values = [];
$values['base'] = $base;
$values['total_iva'] = $total_iva;
$values['total'] = $total;
return $values;
}
}

View File

@ -0,0 +1,142 @@
<?php
namespace App\Controllers\Facturacion;
use App\Models\Facturas\FacturaPagoModel;
use App\Models\Collection;
use DataTables\Editor;
use DataTables\Editor\Field;
use DataTables\Editor\Validate;
use DataTables\Editor\Format;
class FacturasPagos extends \App\Controllers\BaseResourceController
{
protected $modelName = FacturaPagoModel::class;
protected $format = 'json';
protected static $controllerSlug = 'factura-pagos';
public function datatable($factura_id = null){
if ($this->request->isAJAX() && $factura_id != null) {
$reqData = $this->request->getPost();
if (!isset($reqData['draw']) || !isset($reqData['columns']) ) {
$errstr = 'No data available in response to this specific request.';
$response = $this->respond(Collection::datatable( [], 0, 0, $errstr ), 400, $errstr);
return $response;
}
$start = $reqData['start'] ?? 0;
$length = $reqData['length'] ?? 5;
$search = $reqData['search']['value'];
$requestedOrder = $reqData['order']['0']['column'] ?? 0;
//$order = FacturaModel::SORTABLE[$requestedOrder >= 0 ? $requestedOrder : 0];
$dir = $reqData['order']['0']['dir'] ?? 'asc';
$resourceData = $this->model->getResource($factura_id)->orderBy(1, $dir)->limit($length, $start)->get()->getResultObject();
return $this->respond(Collection::datatable(
$resourceData,
$this->model->getResource($factura_id)->countAllResults(),
$this->model->getResource($factura_id)->countAllResults()
));
} else {
return $this->failUnauthorized('Invalid request', 403);
}
}
public function datatable_editor() {
if ($this->request->isAJAX()) {
include(APPPATH . "ThirdParty/DatatablesEditor/DataTables.php");
// Build our Editor instance and process the data coming from _POST
$response = Editor::inst( $db, 'facturas_pagos' )
->fields(
Field::inst( 'id' ),
Field::inst( 'forma_pago_id' ),
Field::inst( 'notes' )
->validator('Validate::notEmpty', array(
'message' => lang('Facturas.validation.requerido'))
),
Field::inst( 'fecha_pago_at' )
->validator( Validate::dateFormat( 'Y-m-d H:i:s' ) )
->getFormatter( Format::dateSqlToFormat( 'Y-m-d H:i:s' ) )
->setFormatter( Format::dateFormatToSql( 'Y-m-d H:i:s' ) ),
Field::inst( 'fecha_vencimiento_at' )
->validator( Validate::dateFormat( 'Y-m-d H:i:s' ) )
->getFormatter( Format::dateSqlToFormat( 'Y-m-d H:i:s' ) )
->setFormatter( Format::dateFormatToSql( 'Y-m-d H:i:s' ) ),
Field::inst( 'total' )
->validator('Validate::numeric', array(
'message' => lang('Facturas.validation.numerico'))
)
->validator('Validate::notEmpty', array(
'message' => lang('Facturas.validation.requerido'))
),
Field::inst( 'factura_id' ),
Field::inst( 'user_updated_id' ),
)
->on('preCreate', function ($editor, &$values) {
/*
$editor
->field('user_updated_id')
->setValue(auth()->user()->id);
$editor
->field('base')
->setValue($totales['base']);
$editor
->field('total_iva')
->setValue($totales['total_iva']);
$editor
->field('total')
->setValue($totales['total']);
$editor
->field('user_updated_id')
->setValue(auth()->user()->id);
*/
})
->on('preEdit', function ($editor, $id, &$values) {
/*
$editor
->field('factura_id')
->setValue($values['factura_id']);
$editor
->field('pedido_linea_impresion_id')
->setValue(null);
$editor
->field('pedido_maquetacion_id')
->setValue(null);
$editor
->field('user_updated_id')
->setValue(auth()->user()->id);
$editor
->field('base')
->setValue($totales['base']);
$editor
->field('total_iva')
->setValue($totales['total_iva']);
$editor
->field('total')
->setValue($totales['total']);
*/
})
->debug(true)
->process($_POST)
->data();
$newTokenHash = csrf_hash();
$csrfTokenName = csrf_token();
$response[$csrfTokenName] = $newTokenHash;
echo json_encode($response);
} else {
return $this->failUnauthorized('Invalid request', 403);
}
}
}

View File

@ -258,6 +258,17 @@ class Pedido extends \App\Controllers\BaseResourceController
} }
} }
public function obtenerPedidosForFacturas(){
if ($this->request->isAJAX()) {
$reqData = $this->request->getPost();
$start = $reqData['start'] ?? 0;
}
else {
return $this->failUnauthorized('Invalid request', 403);
}
}
public function getlineas(){ public function getlineas(){
if ($this->request->isAJAX()) { if ($this->request->isAJAX()) {

View File

@ -192,7 +192,7 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
$this->viewData['presupuestoEntity'] = $presupuestoEntity; $this->viewData['presupuestoEntity'] = $presupuestoEntity;
$this->viewData['datosPresupuesto'] = $datosPresupuesto; $this->viewData['datosPresupuesto'] = $datosPresupuesto;
$this->viewData['clienteId'] = $clienteId; $this->viewData['clienteId'] = $presupuestoEntity->cliente_id; // En el caso del edit, se mantiene el clienteId del presupuesto
// Si se ha llamado a esta funcion porque se ha duplicado el presupuesto // Si se ha llamado a esta funcion porque se ha duplicado el presupuesto
// se actualiza la bbdd para que sólo ejecute algunas funciones una vez // se actualiza la bbdd para que sólo ejecute algunas funciones una vez
@ -398,7 +398,7 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
'servicios' => $servicios, 'servicios' => $servicios,
); );
$return_data = $this->calcular_presupuesto($datos_presupuesto, 0, true); //TRUE FOR DEBUG $return_data = $this->calcular_presupuesto($datos_presupuesto, 0, false); //TRUE FOR DEBUG
array_merge($return_data, [$csrfTokenName => $newTokenHash]); array_merge($return_data, [$csrfTokenName => $newTokenHash]);
return $this->respond($return_data); return $this->respond($return_data);
@ -1449,9 +1449,18 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
} }
// Servicios // Servicios
if ($datos_guardas > 0) { // se comprueba si $datos guardas es un array
array_push($servicios, 62); // Plegado de guardas if(is_array($datos_guardas)){
if(count($datos_guardas) > 0){
array_push($servicios, 62); // Plegado de guardas
}
} }
else{
if ($datos_guardas > 0) {
array_push($servicios, 62); // Plegado de guardas
}
}
/* /*
'retractilado' => 3, 'retractilado' => 3,
'retractilado5' => 5, 'retractilado5' => 5,

View File

@ -7,91 +7,81 @@ use App\Models\UserModel;
class Profile extends BaseController class Profile extends BaseController
{ {
private $user_model;
private $id_user;
function __construct() function __construct()
{ {
$this->user_model = new UserModel();
$this->id_user = auth()->user()->id;
} }
public function index() public function index()
{ {
helper('file');
helper('form');
helper('text');
$data['title'] = [
'module' => lang("App.profile_title"),
'page' => lang("App.profile_subtitle"),
'icon' => 'fas fa-user'
];
$data['breadcrumb'] = [ $data['breadcrumb'] = [
['title' => lang("App.menu_dashboard"), 'route' => "/home", 'active' => false], ['title' => lang("App.menu_dashboard"), 'route' => "/home", 'active' => false],
['title' => lang("App.profile_title"), 'route' => "", 'active' => true] ['title' => lang("App.profile_title"), 'route' => "", 'active' => true]
]; ];
$data['btn_return'] = [ // Get the User Provider (UserModel by default)
'title' => lang("App.global_come_back"), $users = auth()->getProvider();
'route' => '/',
'class' => 'btn btn-dark mr-1',
'icon' => 'fas fa-angle-left'
];
$data['btn_submit'] = [ // Find by the user_id
'title' => lang("App.global_save"), $data['obj'] = $users->findById(auth()->id());
'route' => '',
'class' => 'btn btn-primary mr-1',
'icon' => 'fas fa-save'
];
$session = session(); echo view(getenv('theme.path') . 'form/profile/profileDetails', $data);
$data['obj'] = $this->user_model->where('id', $this->id_user)->first();
echo view(getenv('theme.path') . 'form/profile/index', $data);
} }
public function store() public function store()
{ {
$session = session(); $session = session();
helper('form'); helper('form');
$rules = [ $rules = [
'first_name' => 'required', 'first_name' => 'required',
'last_name' => 'required', 'last_name' => 'required',
'new_pwd' => 'permit_empty|min_length[8]',
'new_pwd_confirm' => 'required_with[new_pwd]|matches[new_pwd]'
]; ];
// Definir los mensajes de error personalizados
$rules_error = [ $rules_error = [
'first_name' => ['required' => lang("App.profile_rules_first_name_r")], 'first_name' => ['required' => lang("App.profile_rules_first_name_r")],
'last_name' => ['required' => lang("App.profile_rules_last_name_r")], 'last_name' => ['required' => lang("App.profile_rules_last_name_r")],
'new_pwd' => ['min_length' => lang("App.profile_rules_password_m")],
'new_pwd_confirm' => [
'matches' => lang("App.profile_rules_password_confirm_m")
]
]; ];
// Validar la entrada
if ($this->validate($rules ?? [], $rules_error ?? [])) { if (!$this->validate($rules, $rules_error)) {
if (!empty($this->id_user)) { // Si la validación falla, redirigir de vuelta con errores
$this->user_model->save([ return redirect()->back()->withInput()->with('errors', $this->validator->getErrors());
'id' => $this->id_user,
'first_name' => $this->request->getPost('first_name'),
'last_name' => $this->request->getPost('last_name')
]);
$session->setFlashdata('sweet', ['success', lang("App.global_alert_save_success")]);
} else {
$session->setFlashdata('sweet', ['error', lang("App.global_alert_save_error")]);
}
} else {
$session->setFlashdata('error', 'error');
return $this->index();
} }
return redirect()->to('/profile'); // Obtener los valores de los campos
$firstName = $this->request->getPost('first_name');
$lastName = $this->request->getPost('last_name');
$newPwd = $this->request->getPost('new_pwd');
$update_data = [
'first_name' => $firstName,
'last_name' => $lastName,
'password' => $newPwd,
];
if(empty($newPwd)){
unset($update_data['password']);
}
// Aquí debes obtener el usuario actual, por ejemplo, desde la sesión
$users = auth()->getProvider();
$user = $users->findById(auth()->id());
$user->fill($update_data);
$users->save($user);
// Redirigir con un mensaje de éxito
return redirect()->back()->with('success', lang('App.profile_updated_successfully'));
} }
} }

View File

@ -8,8 +8,8 @@ class FacturaEntity extends \CodeIgniter\Entity\Entity
protected $attributes = [ protected $attributes = [
'id' => null, 'id' => null,
'pedido_id' => null, 'pedido_id' => null,
'factura_retificada_id' => null, 'factura_rectificada_id' => null,
'factura_retificativa_id' => null, 'factura_rectificativa_id' => null,
'cliente_id' => null, 'cliente_id' => null,
'serie_id' => null, 'serie_id' => null,
'numero' => null, 'numero' => null,
@ -33,18 +33,14 @@ class FacturaEntity extends \CodeIgniter\Entity\Entity
'updated_at' => null, 'updated_at' => null,
'deleted_at' => null, 'deleted_at' => null,
'user_created_id' => null, 'user_created_id' => null,
'user_update_id' => null, 'user_updated_id' => null,
]; ];
protected $casts = [ protected $casts = [
'id' => 'int', 'id' => 'int',
'pedido_id' => 'int', 'pedido_id' => 'int',
'factura_retificada_id' => 'int',
'factura_retificativa_id' => 'int',
'cliente_id' => 'int', 'cliente_id' => 'int',
'serie_id' => 'int', 'serie_id' => 'int',
'estado' => 'int',
'estado_pago' => 'int',
'base' => 'float', 'base' => 'float',
'total' => 'float', 'total' => 'float',
'pendiente' => 'float', 'pendiente' => 'float',

View File

@ -8,7 +8,7 @@ class FacturaLineaEntity extends \CodeIgniter\Entity\Entity
protected $attributes = [ protected $attributes = [
'id' => null, 'id' => null,
'factura_id' => null, 'factura_id' => null,
'pedido_impresion_id' => null, 'pedido_linea_impresion_id' => null,
'pedido_maquetacion_id' => null, 'pedido_maquetacion_id' => null,
'descripcion' => null, 'descripcion' => null,
'cantidad' => null, 'cantidad' => null,
@ -19,14 +19,14 @@ class FacturaLineaEntity extends \CodeIgniter\Entity\Entity
'total' => null, 'total' => null,
'data' => null, 'data' => null,
'deleted_at' => null, 'deleted_at' => null,
'user_update_id' => null, 'user_updated_id' => null,
]; ];
protected $casts = [ protected $casts = [
'id' => 'int', 'id' => 'int',
'factura_id' => 'int', 'factura_id' => 'int',
'pedido_impresion_id' => 'int', 'pedido_linea_impresion_id' => 'int',
'pedido_maquetacion_id' => 'int', 'pedido_maquetacion_id' => 'int',
'cantidad' => 'float', 'cantidad' => 'float',
'precio_unidad' => 'float', 'precio_unidad' => 'float',

View File

@ -14,7 +14,7 @@ class FacturaPagoEntity extends \CodeIgniter\Entity\Entity
'forma_pago_id' => null, 'forma_pago_id' => null,
'total' => null, 'total' => null,
'deleted_at' => null, 'deleted_at' => null,
'user_update_id' => null, 'user_updated_id' => null,
]; ];

View File

@ -24,18 +24,25 @@ class UserEntity extends \CodeIgniter\Entity\Entity
"cliente_id" => "int", "cliente_id" => "int",
"active" => "boolean", "active" => "boolean",
]; ];
/** /**
* Returns a full name: "first last" * Get the full name of the user
* *
* @return string * If the first name and last name are available, the full name is generated as "{first name} {last name}".
* If the first name or last name is missing, only the available name is used.
* If both the first name and last name are missing, the username is used as the full name.
*
* @return string The full name of the user
*/ */
public function getFullName() public function getFullName()
{ {
$fullName = $firstName = trim($this->attributes["first_name"] ?? "");
(!empty($this->attributes["first_name"]) ? trim($this->attributes["first_name"]) . " " : "") . $lastName = trim($this->attributes["last_name"] ?? "");
(!empty($this->attributes["last_name"]) ? trim($this->attributes["last_name"]) : ""); $fullName = $firstName . ' ' . $lastName;
$name = empty($fullName) ? $this->attributes["username"] : $fullName; $fullName = trim($fullName); // In case first name is empty, this will remove the leading space
return $name;
// Use the username attribute if the full name is still empty after trimming
return $fullName ?: $this->attributes["username"];
} }
/** /**

View File

@ -1,16 +1,30 @@
<?php <?php
namespace App\Entities\Usuarios; namespace App\Entities\Usuarios;
use CodeIgniter\Entity;
use CodeIgniter\Shield\Entities\User; use CodeIgniter\Shield\Entities\User;
class UsersEntity extends User class UsersEntity extends User
{ {
protected $attributes = [ protected $attributes = [
"first_name" => null, 'first_name' => null,
"last_name" => null 'last_name'=> null,
'cliente_id' => null,
'comments' => null,
]; ];
protected $casts = [ protected $casts = [
"cliente_id" => "int",
]; ];
public function getFullName()
{
$firstName = trim($this->attributes["first_name"] ?? "");
$lastName = trim($this->attributes["last_name"] ?? "");
$fullName = $firstName . ' ' . $lastName;
$fullName = trim($fullName); // In case first name is empty, this will remove the leading space
// Use the username attribute if the full name is still empty after trimming
return $fullName ?: $this->attributes["username"];
}
} }

View File

@ -89,6 +89,7 @@ return [
'ok' => 'Ok', 'ok' => 'Ok',
'wait' => 'Wait', 'wait' => 'Wait',
'yes' => 'Yes', 'yes' => 'Yes',
'back' => 'Back',
], ],

View File

@ -1,6 +1,7 @@
<?php <?php
return [ return [
'id' => 'ID',
'factura' => 'Invoice', 'factura' => 'Invoice',
'facturaList' => 'Invoice List', 'facturaList' => 'Invoice List',
'facturas' => 'Invoices', 'facturas' => 'Invoices',
@ -21,6 +22,7 @@ return [
'serieFacturacion' => 'Billing Series', 'serieFacturacion' => 'Billing Series',
'creditoAsegurado' => 'Secured Credit', 'creditoAsegurado' => 'Secured Credit',
'facturaRectificada' => 'Rectified Invoice', 'facturaRectificada' => 'Rectified Invoice',
'facturaRectificativa' => 'Rectifying Invoice',
'razonSocial' => 'Business Name', 'razonSocial' => 'Business Name',
'cif' => 'Tax ID', 'cif' => 'Tax ID',
'direccion' => 'Address', 'direccion' => 'Address',
@ -54,4 +56,29 @@ return [
'giroDocimiliado' => 'Direct Debit', 'giroDocimiliado' => 'Direct Debit',
'pagare' => 'Promissory Note', 'pagare' => 'Promissory Note',
'transferencia' => 'Transfer', 'transferencia' => 'Transfer',
'datosFactura' => 'Invoice Data',
'addPedidosImpresion' => 'Add Print Orders',
'addPedidosMaquetacion' => 'Add Layout Orders',
'peiddoImpresion' => 'Print Order',
'peiddoMaquetacion' => 'Layout Order',
'nuevaLinea' => 'New Line',
'validarFactura' => 'Validate Invoice',
'borrarFactura' => 'Delete Invoice',
'imprimirFactura' => 'Print',
'pagos' => 'Payments',
'notas' => 'Notes',
'fechaVencimiento' => 'Due Date',
"fechaCobro" => "Collection Date",
"cantidad" => "Quantity",
"addPago" => "Add Payment",
"facturaPagada" => "Rectifying Invoice already paid",
'errors' => [
'requiredFields' => 'Fields marked with * are required',
],
'validation' => [
'numerico' => 'Must be numeric',
'requerido' => 'Required',
'decimal' => 'Must be decimal',
],
]; ];

View File

@ -52,7 +52,9 @@ return [
'dosCaras' => '2 sides', 'dosCaras' => '2 sides',
'lineasTemplates' =>[ 'lineasTemplates' =>[
'libro' => "[BUDGET %s] Printing of %s copies of %s pages.\nTitle: %s. Author: %s. ISBN: %s.Size: %smm.\n", 'presupuesto' => '[BUDGET %s] ',
'pedido' => '[ORDER %s] ',
'libro' => "Printing of %s copies of %s pages.\nTitle: %s. Author: %s. ISBN: %s.Size: %smm.\n",
'libro_linea_interior' => "%s black pages on %s paper of %s grams", 'libro_linea_interior' => "%s black pages on %s paper of %s grams",
'libro_linea_cubierta' => "\nCover printed on %s on %s paper of %s grams", 'libro_linea_cubierta' => "\nCover printed on %s on %s paper of %s grams",
'libro_linea_sobrecubierta' => "\nDust jacket on %s paper of %s grams", 'libro_linea_sobrecubierta' => "\nDust jacket on %s paper of %s grams",

View File

@ -137,9 +137,9 @@ return [
"profile_mobile" => "Teléfono Móvil", "profile_mobile" => "Teléfono Móvil",
"profile_mobile_ph" => "Escriba su número de celular", "profile_mobile_ph" => "Escriba su número de celular",
"profile_password" => "Cambiar Contraseña", "profile_password" => "Cambiar Contraseña",
"profile_password_ph" => "Escribe tu contraseña", "profile_password_ph" => "Escribe nueva contraseña para cambiarla",
"profile_confirm_password" => "Confirmar seña", "profile_confirm_password" => "Confirmar contraseña",
"profile_confirm_password_ph" => "Confirma tu contraseña anterior", "profile_confirm_password_ph" => "Confirma tu contraseña anterior para cambiarla",
"profile_date_birth" => "Fecha de Nacimiento", "profile_date_birth" => "Fecha de Nacimiento",
"profile_date_birth_ph" => "Seleccionar fecha de nacimiento", "profile_date_birth_ph" => "Seleccionar fecha de nacimiento",
"profile_address" => "Dirección", "profile_address" => "Dirección",

View File

@ -89,6 +89,8 @@ return [
'ok' => 'Ok', 'ok' => 'Ok',
'wait' => 'Espere', 'wait' => 'Espere',
'yes' => 'Si', 'yes' => 'Si',
'no' => 'No',
'back' => 'Volver',
], ],

View File

@ -1,6 +1,7 @@
<?php <?php
return [ return [
'id' => 'ID',
'factura' => 'Factura', 'factura' => 'Factura',
'facturaList' => 'Listado de Facturas', 'facturaList' => 'Listado de Facturas',
'facturas' => 'Facturas', 'facturas' => 'Facturas',
@ -21,6 +22,7 @@ return [
'serieFacturacion' => 'Serie facturación', 'serieFacturacion' => 'Serie facturación',
'creditoAsegurado' => 'Crédito asegurado', 'creditoAsegurado' => 'Crédito asegurado',
'facturaRectificada' => 'Factura rectificada', 'facturaRectificada' => 'Factura rectificada',
'facturaRectificativa' => 'Factura rectificativa',
'razonSocial' => 'Razón Social', 'razonSocial' => 'Razón Social',
'cif' => 'CIF', 'cif' => 'CIF',
'direccion' => 'Dirección', 'direccion' => 'Dirección',
@ -54,4 +56,30 @@ return [
'giroDomiciliado' => 'Giro domiciliado', 'giroDomiciliado' => 'Giro domiciliado',
'pagare' => 'Pagaré', 'pagare' => 'Pagaré',
'transferencia' => 'Transferencia', 'transferencia' => 'Transferencia',
'datosFactura' => 'Datos Factura',
'addPedidosImpresion' => 'Añadir Pedidos Impresión',
'addPedidosMaquetacion' => 'Añadir Pedidos Maquetación',
'pedidoImpresion' => 'Pedido Impresión',
'pedidoMaquetacion' => 'Pedido Maquetación',
'nuevaLinea' => 'Nueva Línea',
'validarFactura' => 'Validar Factura',
'borrarFactura' => 'Borrar Factura',
'imprimirFactura' => 'Imprimir',
'pagos' => 'Pagos',
'notas' => 'Notas',
"fechaVencimiento" => "Fecha Vencimiento",
"fechaCobro" => "Fecha Cobro",
"cantidad" => "Cantidad",
"addPago" => "Añadir Pago",
"facturaPagada" => "Factura rectificativa ya abonada",
'errors' => [
'requiredFields' => 'Los campos marcados con * son obligatorios',
],
'validation' => [
"requerido" => "El campo es obligatorio.",
"numerico" => "El campo debe ser numérico.",
"decimal" => "El campo debe ser decimal.",
]
]; ];

View File

@ -51,7 +51,9 @@ return [
'dosCaras' => '2 caras', 'dosCaras' => '2 caras',
'lineasTemplates' =>[ 'lineasTemplates' =>[
'libro' => "[PRESUPUESTO %s] Impresión de %s ejemplares de %s páginas.\nTítulo: %s. Autor: %s. ISBN: %s.Tamaño: %smm.\n", 'presupuesto' => '[PRESUPUESTO %s] ',
'pedido' => '[PEDIDO %s] ',
'libro' => "Impresión de %s ejemplares de %s páginas.\nTítulo: %s. Autor: %s. ISBN: %s.Tamaño: %smm.\n",
'libro_linea_interior' => "%s páginas en negro sobre papel %s de %s gramos", 'libro_linea_interior' => "%s páginas en negro sobre papel %s de %s gramos",
'libro_linea_cubierta' => "\nCubierta impresa a %s sobre papel %s de %s gramos", 'libro_linea_cubierta' => "\nCubierta impresa a %s sobre papel %s de %s gramos",
'libro_linea_sobrecubierta' => "\nSobrecubierta sobre papel %s de %s gramos", 'libro_linea_sobrecubierta' => "\nSobrecubierta sobre papel %s de %s gramos",

View File

@ -210,6 +210,8 @@ return [
'confirmar' => 'Confirmar presupuesto', 'confirmar' => 'Confirmar presupuesto',
'confirmado' => 'Presupuesto confirmado', 'confirmado' => 'Presupuesto confirmado',
'totalAceptado' => 'Total aceptado',
// Preview // Preview
'preview' => 'Previsualización de configuraciones', 'preview' => 'Previsualización de configuraciones',
'preview-conf-bn' => 'Configuración Blanco y Negro', 'preview-conf-bn' => 'Configuración Blanco y Negro',

View File

@ -153,18 +153,6 @@ return [
], ],
'tfa_code' => [
'max_length' => 'El campo {field} no puede exceder {param} caracteres en longitud.',
'required' => 'El campo {field} es obligatorio.',
],
'tfa_secret' => [
'max_length' => 'El campo {field} no puede exceder {param} caracteres en longitud.',
'required' => 'El campo {field} es obligatorio.',
],
'email' => [ 'email' => [
'max_length' => 'El campo {field} no puede exceder {param} caracteres en longitud.', 'max_length' => 'El campo {field} no puede exceder {param} caracteres en longitud.',
'required' => 'El campo {field} es obligatorio.', 'required' => 'El campo {field} es obligatorio.',

View File

@ -315,4 +315,21 @@ class ClienteModel extends \App\Models\BaseModel
public function creditoDisponible($cliente_id){ public function creditoDisponible($cliente_id){
return true; return true;
} }
public function getClienteDataFacturas($cliente_id){
$builder = $this->db
->table($this->table . " t1")
->select(
"
t1.nombre AS cliente_nombre, t1.direccion AS cliente_address, t1.cif AS cliente_cif,
t2.nombre AS cliente_pais, t1.cp AS cliente_cp, t1.ciudad AS cliente_ciudad,
t3.nombre AS cliente_provincia, t1.credito_asegurado AS creditoAsegurado"
)
->where("t1.is_deleted", 0)
->where("t1.id", $cliente_id);
$builder->join("lg_paises t2", "t1.pais_id = t2.id", "left");
$builder->join("lg_provincias t3", "t1.provincia_id = t3.id", "left");
return $builder->get()->getResultArray();
}
} }

View File

@ -3,7 +3,7 @@ namespace App\Models\Configuracion;
class FormaPagoModel extends \App\Models\BaseModel class FormaPagoModel extends \App\Models\BaseModel
{ {
protected $table = "lg_formas_pago"; protected $table = "formas_pago";
/** /**
* Whether primary key uses auto increment. * Whether primary key uses auto increment.
@ -38,6 +38,18 @@ class FormaPagoModel extends \App\Models\BaseModel
], ],
]; ];
public function getMenuItems(){
$items = $this->findAll();
$menuItems = [];
foreach ($items as $item) {
$menuItems[] = [
"value" => $item->id,
"label" => $item->nombre,
];
}
return $menuItems;
}
/** /**
* Get resource data. * Get resource data.
* *

View File

@ -91,4 +91,36 @@ class SeriesFacturasModel extends \App\Models\BaseModel
->orLike("t1.grupo", $search) ->orLike("t1.grupo", $search)
->groupEnd(); ->groupEnd();
} }
public function getMenuItemsFacturas(){
$resultSorting = $this->getPrimaryKeyName();
$id = 'id AS id';
$text = 'nombre AS text';
$queryBuilder = $this->db->table($this->table);
$queryBuilder->select([$id, $text]);
$queryBuilder->where('tipo', 'facturacion');
$queryBuilder->where('grupo', '1');
$queryBuilder->orderBy($resultSorting);
$result = $queryBuilder->get()->getResult();
return $result;
}
public function getSerieNumerada($id)
{
$number = $this->db->table($this->table)
->select("next, formato")
->where("id", $id)
->get()->getFirstRow();
$this->db->table($this->table)
->where("id", $id)
->set("next", $number->next + 1, false)
->update();
return str_replace("{number}", $number->next, $number->formato);
}
} }

View File

@ -10,7 +10,7 @@ class FacturaLineaModel extends \App\Models\BaseModel {
// Lista de columnas basada en los campos de la tabla, para asignación masiva // Lista de columnas basada en los campos de la tabla, para asignación masiva
protected $allowedFields = [ protected $allowedFields = [
'factura_id', 'factura_id',
'pedido_impresion_id', 'pedido_linea_impresion_id',
'pedido_maquetacion_id', 'pedido_maquetacion_id',
'descripcion', 'descripcion',
'cantidad', 'cantidad',
@ -21,7 +21,7 @@ class FacturaLineaModel extends \App\Models\BaseModel {
'total', 'total',
'data', 'data',
'deleted_at', 'deleted_at',
'user_update_id' 'user_updated_id'
]; ];
protected $returnType = "App\Entities\Facturas\FacturaLineaEntity"; protected $returnType = "App\Entities\Facturas\FacturaLineaEntity";
@ -30,4 +30,68 @@ class FacturaLineaModel extends \App\Models\BaseModel {
protected $useSoftDeletes = true; protected $useSoftDeletes = true;
public static $labelField = "id"; public static $labelField = "id";
public function getResource($factura_id)
{
$builder = $this->db
->table($this->table . " t1")
->select(
"t1.id AS id, t1.factura_id AS factura_id,
t1.pedido_linea_impresion_id AS pedido_linea_impresion_id, t1.pedido_maquetacion_id AS pedido_maquetacion_id,
t1.descripcion AS descripcion, t1.cantidad as cantidad, t1.precio_unidad AS precio_unidad, t1.iva AS iva,
t1.base AS base, t1.total_iva AS total_iva, t1.total AS total, t1.data AS data, t2.pedido_id AS pedido_id,
t3.total_aceptado AS total_aceptado"
)
->join("pedidos_linea t2", "t2.id = t1.pedido_linea_impresion_id", "left")
->join("presupuestos t3", "t3.id = t2.presupuesto_id", "left")
->where("t1.factura_id", $factura_id)
->where("t1.deleted_at", null);
return $builder;
}
public function addFacturaPedidoLinea($factura_id, $pedido_linea_id, $cantidad)
{
$data = [
"factura_id" => $factura_id,
"pedido_linea_id" => $pedido_linea_id,
"cantidad" => $cantidad
];
return $this->db->table("facturas_pedidos_lineas")->insert($data);
}
public function deleteFacturasLineasPedido($factura_id, $pedido_linea_id, $cantidad){
$this->db->table("facturas_pedidos_lineas")
->where("factura_id", $factura_id)
->where("pedido_linea_id", $pedido_linea_id)
->where("cantidad", $cantidad)
->delete();
}
public function updateFacturaPedidoLinea($factura_id, $pedido_linea_id, $cantidad, $cantidad_new)
{
// Obtener la ID del registro que queremos actualizar
$record = $this->db->table("facturas_pedidos_lineas")
->select('id')
->where("factura_id", $factura_id)
->where("pedido_linea_id", $pedido_linea_id)
->where("cantidad", $cantidad)
->limit(1)
->get()
->getRow();
// Si existe el registro
if ($record) {
$data = [
"cantidad" => $cantidad_new
];
// Actualizar el registro especificado por su ID
$this->db->table("facturas_pedidos_lineas")
->where("id", $record->id)
->update($data);
}
}
} }

View File

@ -23,12 +23,20 @@ class FacturaModel extends \App\Models\BaseModel {
11 => "DAFEDIFF(days, NOW(), t3.fecha_vencimiento_at)", 11 => "DAFEDIFF(days, NOW(), t3.fecha_vencimiento_at)",
]; ];
const SORTABLE_PEDIDOS = [
1 => "t1.numero",
2 => "t2.nombre",
3 => "t1.estado",
4 => "t1.fecha_factura_at",
5 => "t1.total",
];
// Lista de columnas basada en los campos de la tabla, para asignación masiva // Lista de columnas basada en los campos de la tabla, para asignación masiva
protected $allowedFields = [ protected $allowedFields = [
'pedido_id', 'pedido_id',
'factura_retificada_id', 'factura_rectificada_id',
'factura_retificativa_id', 'factura_rectificativa_id',
'customer_id', 'cliente_id',
'serie_id', 'serie_id',
'numero', 'numero',
'estado', 'estado',
@ -40,18 +48,18 @@ class FacturaModel extends \App\Models\BaseModel {
'pendiente', 'pendiente',
'total_pagos', 'total_pagos',
'creditoAsegurado', 'creditoAsegurado',
'customer_nombre', 'cliente_nombre',
'customer_address', 'cliente_address',
'customer_cif', 'cliente_cif',
'customer_pais', 'cliente_pais',
'customer_cp', 'cliente_cp',
'customer_ciudad', 'cliente_ciudad',
'customer_provincia', 'cliente_provincia',
'created_at', 'created_at',
'updated_at', 'updated_at',
'deleted_at', 'deleted_at',
'user_created_id', 'user_created_id',
'user_update_id' 'user_updated_id'
]; ];
protected $returnType = "App\Entities\Facturas\FacturaEntity"; protected $returnType = "App\Entities\Facturas\FacturaEntity";
@ -69,16 +77,20 @@ class FacturaModel extends \App\Models\BaseModel {
$builder = $this->db $builder = $this->db
->table($this->table . " t1") ->table($this->table . " t1")
->select( ->select(
"t1.id AS id, t1.numero AS numero, t1.fecha_factura_at AS fecha_factura_at, "t1.id AS id, t1.numero AS numero, DATE_FORMAT(t1.fecha_factura_at, '%d/%m/%Y') AS fecha_factura_at,
t2.nombre AS cliente, t1.base AS base, t1.total AS total, t1.pendiente AS pendiente, t2.nombre AS cliente, t1.base AS base, t1.total AS total, t1.pendiente AS pendiente,
t1.creditoAsegurado AS creditoAsegurado, t1.estado AS estado, t1.estado_pago AS estado_pago, t1.creditoAsegurado AS creditoAsegurado, t1.estado AS estado, t1.estado_pago AS estado_pago,
t4.nombre AS forma_pago, t3.fecha_vencimiento_at AS venciemento" GROUP_CONCAT(DISTINCT t4.nombre ORDER BY t4.nombre ASC SEPARATOR ', ') AS forma_pago,
DATE_FORMAT(MIN(CASE WHEN t3.fecha_vencimiento_at != '0000-00-00 00:00:00' THEN t3.fecha_vencimiento_at ELSE NULL END), '%d/%m/%Y') AS vencimiento,
t2.vencimiento AS dias_vencimiento"
); );
$builder->join("clientes t2", "t2.id = t1.cliente_id", "left"); $builder->join("clientes t2", "t2.id = t1.cliente_id", "left");
$builder->join("facturas_pagos t3", "t3.factura_id = t1.id", "left"); $builder->join("facturas_pagos t3", "t3.factura_id = t1.id", "left");
$builder->join("formas_pago t4", "t3.forma_pago_id = t4.id", "left"); $builder->join("formas_pago t4", "t3.forma_pago_id = t4.id", "left");
$builder->where("t1.deleted_at IS NULL");
$builder->groupBy("t1.id"); // Agrupa por id de la factura
return empty($search) return empty($search)
? $builder ? $builder
@ -88,4 +100,48 @@ class FacturaModel extends \App\Models\BaseModel {
->orLike("t1.id", $search) ->orLike("t1.id", $search)
->groupEnd(); ->groupEnd();
} }
public function getResourcePedidos($pedido_id)
{
$builder = $this->db
->table($this->table . " t1")
->select(
"t1.id AS id, t1.numero AS numero, t2.nombre AS serie, t1.estado AS estado,
DATE_FORMAT(t1.fecha_factura_at, '%d/%m/%Y') AS fecha_factura_at, t1.total AS total"
);
$builder->join("series t2", "t2.id = t1.serie_id", "left");
$builder->join("facturas_lineas t3", "t1.id = t3.factura_id", "left");
$builder->join("facturas_pedidos_lineas t4", "t1.id = t4.factura_id", "left");
$builder->join("pedidos_linea t5", "t4.pedido_linea_id = t5.id", "left");
$builder->join("pedidos t6", "t5.pedido_id = t6.id", "left");
$builder->where("t1.deleted_at IS NULL");
$builder->where("t6.id", $pedido_id);
$builder->groupBy("t1.id"); // Agrupa por id de la factura
return $builder;
}
public function getCantidadLineaPedidoFacturada($linea_pedido_id)
{
$builder = $this->db
->table("facturas_pedidos_lineas t1")
->select("SUM(t1.cantidad) AS cantidad")
->where("t1.pedido_linea_id", $linea_pedido_id);
return $builder->get()->getRow()->cantidad;
}
public function deleteFacturasLineasPedido($factura_id, $pedido_linea_id, $cantidad)
{
$this->db->table("facturas_pedidos_lineas")
->where("factura_id", $factura_id)
->where("pedido_linea_id", $pedido_linea_id)
->where("cantidad", $cantidad)
->delete();
}
} }

View File

@ -14,7 +14,7 @@ class FacturaPagoModel extends \App\Models\BaseModel {
'forma_pago_id', 'forma_pago_id',
'total', 'total',
'deleted_at', 'deleted_at',
'user_update_id' 'user_updated_id'
]; ];
protected $returnType = "App\Entities\Facturas\FacturaPagoEntity"; protected $returnType = "App\Entities\Facturas\FacturaPagoEntity";
@ -23,4 +23,20 @@ class FacturaPagoModel extends \App\Models\BaseModel {
protected $useSoftDeletes = true; protected $useSoftDeletes = true;
public static $labelField = "id"; public static $labelField = "id";
public function getResource($factura_id)
{
$builder = $this->db
->table($this->table . " t1")
->select(
"t1.id AS id, t1.factura_id AS factura_id,
t1.notes AS notes, t1.fecha_pago_at AS fecha_pago_at, t1.fecha_vencimiento_at AS fecha_vencimiento_at,
t1.forma_pago_id AS forma_pago_id, t2.nombre as forma_pago, t1.total AS total"
)
->join("formas_pago t2", "t2.id = t1.forma_pago_id", "left")
->where("t1.factura_id", $factura_id)
->where("t1.deleted_at", null);
return $builder;
}
} }

View File

@ -76,4 +76,41 @@ class PedidoLineaModel extends \App\Models\BaseModel
->orLike("t1.id", $search) ->orLike("t1.id", $search)
->groupEnd(); ->groupEnd();
} }
public function obtenerLineasPedidoSinFacturar($cliente_id) {
$resultaArray = [];
$subquery = $this->db
->table('facturas_pedidos_lineas')
->select('pedido_linea_id, SUM(cantidad) AS total_cantidad')
->groupBy('pedido_linea_id')
->getCompiledSelect();
$builder = $this->db
->table($this->table . " t1")
->select("t1.id AS id, t1.pedido_id AS pedido_id, t3.titulo AS titulo, t4.codigo AS tipo_impresion")
->join("pedidos t2", "t2.id = t1.pedido_id", "left")
->join("presupuestos t3", "t3.id = t1.presupuesto_id", "left")
->join("tipos_presupuestos t4", "t4.id = t3.tipo_impresion_id", "left")
->join("($subquery) fpl", "fpl.pedido_linea_id = t1.id", "left")
->where("t3.cliente_id", $cliente_id)
->where("t2.estado", "finalizado")
->where("(t3.tirada > IFNULL(fpl.total_cantidad, 0))");
// Ejecutar la consulta y devolver resultados
$query = $builder->get();
$data = $query->getResult();
foreach($data as $register) {
$item = (object)[
'id' => $register->id,
'text' => '['. lang('Pedidos.pedido') . ' ' . $register->pedido_id . '] ' . $register->titulo . ' - ' . lang('Presupuestos.' . $register->tipo_impresion),
];
array_push($resultaArray, $item);
}
return $resultaArray;
}
} }

View File

@ -142,7 +142,7 @@ class PresupuestoModel extends \App\Models\BaseModel
], ],
"titulo" => [ "titulo" => [
"label" => "Presupuestos.titulo", "label" => "Presupuestos.titulo",
"rules" => "trim|required|max_length[30]", "rules" => "trim|required|max_length[300]",
], ],
"inc_rei" => [ "inc_rei" => [
"label" => "Presupuestos.incRei", "label" => "Presupuestos.incRei",
@ -538,7 +538,7 @@ class PresupuestoModel extends \App\Models\BaseModel
return $json; return $json;
} }
public function generarLineaPedido($presupuesto_id) public function generarLineaPedido($presupuesto_id, $forFactura = false, $pedido_id = 0)
{ {
$builder = $this->db $builder = $this->db
->table($this->table . " t1") ->table($this->table . " t1")
@ -565,13 +565,18 @@ class PresupuestoModel extends \App\Models\BaseModel
$presupuesto = $presupuesto[0]; $presupuesto = $presupuesto[0];
// Libro // Libro
if($presupuesto->tipo < 10){ if($presupuesto->tipo < 10 || $presupuesto->tipo==20 || $presupuesto->tipo==21){
if($presupuesto->papel_formato_personalizado == 1){ if($presupuesto->papel_formato_personalizado == 1){
$presupuesto->tamanio= $presupuesto->papel_formato_ancho . "x" . $presupuesto->papel_formato_alto; $presupuesto->tamanio= $presupuesto->papel_formato_ancho . "x" . $presupuesto->papel_formato_alto;
} }
$presupuesto->concepto = sprintf(lang('Pedidos.lineasTemplates.libro'), if($forFactura){
$presupuesto->numero, $presupuesto->concepto = sprintf(lang('Pedidos.lineasTemplates.pedido'), $pedido_id);
}
else{
$presupuesto->concepto = sprintf(lang('Pedidos.lineasTemplates.presupuesto'), $presupuesto->numero);
}
$presupuesto->concepto .= sprintf(lang('Pedidos.lineasTemplates.libro'),
$presupuesto->unidades, $presupuesto->unidades,
$presupuesto->paginas, $presupuesto->paginas,
$presupuesto->titulo, $presupuesto->titulo,

View File

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace App\Models; namespace App\Models;
use App\Entities\Usuarios\UsersEntity;
use CodeIgniter\Shield\Models\UserModel as ShieldUserModel; use CodeIgniter\Shield\Models\UserModel as ShieldUserModel;
class UserModel extends ShieldUserModel class UserModel extends ShieldUserModel
@ -17,26 +18,51 @@ class UserModel extends ShieldUserModel
'first_name', // Añadido 'first_name', // Añadido
'last_name', // Añadido 'last_name', // Añadido
'cliente_id', // Añadido 'cliente_id', // Añadido
'comments', // Añadido
]; ];
} }
protected $returnType = UsersEntity::class;
protected $useSoftDeletes = true; protected $useSoftDeletes = true;
protected $useTimestamps = true; protected $useTimestamps = true;
protected $createdField = 'created_at'; protected $createdField = 'created_at';
protected $updatedField = 'updated_at'; protected $updatedField = 'updated_at';
protected $deletedField = 'deleted_at'; protected $deletedField = 'deleted_at';
protected $validationRules = [ protected $validationRules = [
"username" => [ "first_name" => "required|trim|max_length[150]",
"label" => "correo duplicado", "last_name" => "required|trim|max_length[150]",
"rules" => "is_unique[users.username]", 'new_pwd' => 'permit_empty|min_length[8]',
] 'new_pwd_confirm' => 'permit_empty|required_with[new_pwd]|matches[new_pwd]',
"comments" => "permit_empty|trim|max_length[512]"
];
protected $validationMessages = [
'first_name' => [
"max_length" => "Users.validation.first_name.max_length",
"required" => "Users.validation.first_name.required"
],
'last_name' => [
"max_length" => "Users.validation.last_name.max_length",
"required" => "Users.validation.last_name.required"
],
'new_pwd' => [
'min_length' => "App.profile_rules_password_m"
],
'new_pwd_confirm' => [
'matches' => "App.profile_rules_password_confirm_m"
],
'comments' => [
"max_length" => "Users.validation.last_name.max_length",
],
]; ];
public function getComerciales(){ public function getComerciales()
{
$builder = $this->db $builder = $this->db
->table("users" . " t1") ->table("users" . " t1")
->select( ->select(
@ -51,17 +77,5 @@ class UserModel extends ShieldUserModel
} }
public function getUsersList(){
$builder = $this->db
->table("users" . " t1")
->select(
"t1.id AS id, t1.first_name AS first_name, t1.last_name AS last_name, t1.last_active AS last_active, t2.group AS group"
);
$builder->where('t1.deleted_at', null);
$builder->join("auth_groups_users t2", "t1.id = t2.user_id", "left");
return $builder->get()->getResult();
}
} }

View File

@ -26,20 +26,34 @@
function asyncConfirmDialog(title, msg, yesCallbackFn, noCallbackFn) { function asyncConfirmDialog(title, msg, yesCallbackFn, noCallbackFn) {
var $confirmDialog = $("#modalConfirmYesNo"); var $confirmDialog = $("#modalConfirmYesNo");
$confirmDialog.modal('show'); $confirmDialog.modal('show');
$("#labelTitleConfirmDialog").html(title); $("#labelTitleConfirmDialog").html(title);
$("#labelMsgConfirmDialog").html(msg); $("#labelMsgConfirmDialog").html(msg);
$("#btnYesConfirmDialog").off('click').click(function () { $("#btnYesConfirmDialog").off('click').click(function () {
yesCallbackFn(); yesCallbackFn();
$confirmDialog.modal("hide"); $confirmDialog.modal("hide");
}); });
$("#btnNoConfirmDialog").off('click').click(function () { $("#btnNoConfirmDialog").off('click').click(function () {
noCallbackFn(); noCallbackFn();
$confirmDialog.modal("hide"); $confirmDialog.modal("hide");
}); });
} }
function asyncConfirmDialogWithParams(title, msg, yesCallbackFn, noCallbackFn, params) {
var $confirmDialog = $("#modalConfirmYesNo");
$confirmDialog.modal('show');
$("#labelTitleConfirmDialog").html(title);
$("#labelMsgConfirmDialog").html(msg);
$("#btnYesConfirmDialog").off('click').click(function () {
yesCallbackFn(params);
$confirmDialog.modal("hide");
});
$("#btnNoConfirmDialog").off('click').click(function () {
noCallbackFn(params);
$confirmDialog.modal("hide");
});
}
<?= $this->endSection() ?> <?= $this->endSection() ?>

View File

@ -0,0 +1,138 @@
<div class="row px-0">
<div style="padding-left: 0px;" class="col-md-12 col-lg-6 accordion accordion accordion-bordered mt-3 accordion-without-arrow" id="addPedidosImpresion">
<div class="card accordion-item active mt-3 mx-2">
<h3 class="accordion-header" id="headingAddPedidosImpresion">
<button type="button" class="accordion-button collapsed" data-bs-toggle="collapse" data-bs-target="#accordionIcon-1" aria-controls="accordionIcon-1">
<h4><?= lang('Facturas.addPedidosImpresion') ?> </h4>
</button>
</h3>
<div id="accordionAddPedidosImpresionTip" class="accordion show" data-bs-parent="#accordioAddPedidosImpresion">
<div class="accordion-body">
<div class="row">
<div class="col-md-12 col-lg-10">
<select name="pedidoImpresion" id="pedidoImpresion" class="form-select">
</select>
</div>
<div class="col-md-12 col-lg-2">
<button
type="button"
class="btn btn-label-primary float-start me-sm-3 me-1"
name="addNewPedidoImpresion"
id="addNewPedidoImpresion" >
<?= lang("Basic.global.addNew") ?>
</button>
</div>
</div> <!--//row -->
</div> <!--//accordion-body -->
</div> <!--//accordionFechasTip-->
</div> <!--//card-->
</div>
<div style="padding-right: 0px;" class="col-md-12 col-lg-6 accordion accordion accordion-bordered mt-3 accordion-without-arrow" id="addPedidosMaquetacion">
<div class="card accordion-item active mt-3 mx-2">
<h3 class="accordion-header" id="headingAddPedidosMaquetacion">
<button type="button" class="accordion-button collapsed" data-bs-toggle="collapse" data-bs-target="#accordionIcon-1" aria-controls="accordionIcon-1">
<h4><?= lang('Facturas.addPedidosMaquetacion') ?> </h4>
</button>
</h3>
<div id="accordionAddPedidosMaquetacionTip" class="accordion show" data-bs-parent="#accordioAddPedidosMaquetacion">
<div class="accordion-body">
<div class="row">
<div class="col-md-12 col-lg-10">
<select name="pedidoMaquetacion" id="pedidoMaquetacion" class="form-select">
</select>
</div>
<div class="col-md-12 col-lg-2">
<button
type="button"
class="btn btn-label-primary float-start me-sm-3 me-1"
name="addNewPedidoMaquetacion"
id="addNewPedidoMaquetacion" >
<?= lang("Basic.global.addNew") ?>
</button>
</div>
</div> <!--//row -->
</div> <!--//accordion-body -->
</div> <!--//accordionFechasTip-->
</div> <!--//card-->
</div>
</div> <!--//row -->
<?=$this->section('additionalInlineJs') ?>
$('#pedidoImpresion').select2({
placeholder: "<?= lang('Facturas.pedidoImpresion') ?>",
allowClear: true,
ajax: {
url: '<?= route_to("menuPedidosPendientesImpresion", $facturaEntity->cliente_id) ?>',
type: 'post',
dataType: 'json',
data: function (params) {
return {
id: 'id',
text: 'nombre',
searchTerm: params.term,
<?= csrf_token() ?? "token" ?> : <?= csrf_token() ?>v
};
},
delay: 60,
processResults: function (response) {
yeniden(response.<?= csrf_token() ?>);
return {
results: response.menu
};
},
cache: true
}
});
$('#addNewPedidoImpresion').on('click', function(){
var lineaPedido = $('#pedidoImpresion').val();
if(lineaPedido == null) {
return;
}
$.ajax({
url: '<?= route_to("addLineaPedidoImpresion2Factura", $facturaEntity->id) ?>',
type: 'post',
data: {
lineaPedido: lineaPedido,
<?= csrf_token() ?? "token" ?> : <?= csrf_token() ?>v
},
success: function(response) {
yeniden(response.<?= csrf_token() ?>);
// se ajustan el ancho de las columnas
$('#tableOfLineasFactura').DataTable().columns.adjust().draw();
$('#pedidoImpresion').val(null).trigger('change');
// Se actualiza la tabla de lineas de factura
tableLineas.clearPipeline();
tableLineas.draw();
}
});
});
$('#pedidoMaquetacion').select2({
placeholder: "<?= lang('Facturas.pedidoMaquetacion') ?>",
allowClear: true,
width: '100%'
});
<?=$this->endSection() ?>

View File

@ -0,0 +1,390 @@
<div class="accordion accordion-bordered mt-3" id="cabeceraFactura">
<div class="card accordion-item active">
<h2 class="accordion-header" id="headingFacturas">
<button type="button" class="accordion-button" data-bs-toggle="collapse" data-bs-target="#accordionFacturaTip" aria-expanded="false" aria-controls="accordionFacturaTip">
<h3><?= lang("Facturas.datosFactura") ?></h3>
</button>
</h2>
<div id="accordionFacturaTip" class="accordion-collapse collapse show" data-bs-parent="#accordioFactura">
<div class="accordion-body">
<div class="row">
<h4><?= lang('Facturas.factura') . ': '?>
<span style="color:<?=($facturaEntity->estado === 'borrador')?"red":"green"?>;"> <?= lang('Facturas.' . $facturaEntity->estado)?></span>
<span class="factura-validada"> <?= ($facturaEntity->estado != 'borrador')? " / ":""?></span>
<span id="estado_pago_text" class="factura-validada" style="color:<?=($facturaEntity->estado_pago === 'pendiente')?"red":"green"?>;<?= ($facturaEntity->estado == 'borrador')? "display:none;":""?>"> <?= lang('Facturas.' . $facturaEntity->estado_pago)?></span>
</h4>
</div>
<div class="row mb-2">
<div class="col-md-12 col-lg-2 px-4">
<?php if ($facturaEntity->estado === 'borrador') : ?>
<div class="mb-1">
<label for="id" class="form-label">
<?= lang('Facturas.id') ?>
</label>
<input disabled id="id" name="id" tabindex="1" maxLength="11" class="form-control" value="<?= old('id', $facturaEntity->id) ?>" >
</div>
<?php else : ?>
<div class="mb-1">
<label for="id" class="form-label">
<?= lang('Facturas.numeroFactura') ?>
</label>
<input disabled id="numero" name="numero" tabindex="1" maxLength="11" class="form-control" value="<?= old('numero', $facturaEntity->numero) ?>" >
</div>
<?php endif; ?>
</div>
<div class="col-md-12 col-lg-2 px-4">
<div class="mb-1">
<label for="serie_id" class="form-label">
<?= lang('Facturas.serieFacturacion') ?>
</label>
<select <?= ($facturaEntity->estado != 'borrador')?'disabled ':''?> id="serie_id" tabindex="2" name="serie_id" class="form-control select2bs2 update-cabecera" style="width: 100%;">
<option value="<?= old('serie_id', $facturaEntity->serie_id) ?>" selected><?= old('serie_nombre', $facturaEntity->serie_nombre) ?></option>
</select>
</div>
</div><!--//.mb-3 -->
<div class="col-md-12 col-lg-2 px-4">
<div class="mb-1">
<label for="creditoAsegurado" class="form-label">
<?= lang('Facturas.creditoAsegurado') ?>
</label>
<select <?= ($facturaEntity->estado != 'borrador')?'disabled ':''?> id="creditoAsegurado" tabindex="3" name="creditoAsegurado" class="form-control select2bs2 update-cabecera" style="width: 100%;">
<option value="0" <?= ($facturaEntity->creditoAsegurado == 0)?'selected':'' ?>> <?= lang('Basic.global.no') ?> </option>
<option value="1" <?= ($facturaEntity->creditoAsegurado == 1)?'selected':'' ?>> <?= lang('Basic.global.yes') ?> </option>
</select>
</div>
</div><!--//.mb-3 -->
<div class="col-md-12 col-lg-2 px-4">
<div class="mb-1">
<label for="fecha_factura_at" class="form-label">
<?= lang('Facturas.fechaFactura') ?>
</label>
<input <?= ($facturaEntity->estado != 'borrador')?'disabled ':''?> type="text" value="" tabindex="4" id="fecha_factura_at" name="fecha_factura_at" tabindex="1" maxLength="11" class="form-control update-cabecera" value="<?= old('fecha_factura_at', $facturaEntity->fecha_factura_at) ?>" >
</div>
</div>
<div class="col-md-12 col-lg-4 px-4">
<div class="mb-1">
<label for="cliente_id" class="form-label">
<?= lang('Facturas.cliente') ?>
<div class="btn-group btn-group-sm">
<a href="<?= route_to('editarCliente', $facturaEntity->cliente_id); ?>" target="_blank" ><i class="ti ti-file-search ti-sm btn-edit mx-2" data-id="${data.id}"></i></a>
</div>
</label>
<select <?= ($facturaEntity->estado != 'borrador')?'disabled ':''?> id="cliente_id" tabindex="5" name="cliente_id" class="form-control select2bs2 update-cabecera" style="width: 100%;">
<option value="<?= old('cliente_id', $facturaEntity->cliente_id) ?>" selected><?= old('cliente_alias', $facturaEntity->cliente_alias) ?></option>
</select>
</div>
</div><!--//.mb-3 -->
</div><!--//.row -->
<div class="row mb-2">
<div <?= ($facturaEntity->serie_id == 7 || $facturaEntity->serie_id == 9 || $facturaEntity->factura_rectificada_id != null) ? "":"style='display:none;'" ?> class="col-md-12 col-lg-2 px-4 factura-R">
<div class="mb-1">
<label for="facturaR" class="form-label factura-R">
<?= ($facturaEntity->factura_rectificada_id != null) ? lang('Facturas.facturaRectificada') : lang('Facturas.facturaRectificativa') ?>:
</label>
<input <?= ($facturaEntity->estado!='borrador')? "disabled":"" ?> id="facturaR" name="<?= ($facturaEntity->factura_rectificada_id != null) ? 'factura_rectificada_id' : 'factura_rectificativa_id' ?>" tabindex="" maxLength="25" class="form-control update-cabecera factura-R"
<?php if($facturaEntity->factura_rectificada_id == null && $facturaEntity->factura_rectificativa_id == null): ?>
value=""
<?php else: ?>
value="<?= ($facturaEntity->factura_rectificada_id != null) ? old('factura_rectificada_id', $facturaEntity->factura_rectificada_id): old('factura_rectificativa_id', $facturaEntity->factura_rectificativa_id)?>"
<?php endif; ?>
>
</div>
</div>
<div id="div_cliente" class="col-md-12 col-lg-<?= ($facturaEntity->factura_rectificada_id != null || $facturaEntity->factura_rectificativa_id != null)?"4":"6" ?> px-4">
<div class="mb-1">
<label for="cliente_nombre" class="form-label">
<?= lang('Facturas.razonSocial') ?>
</label>
<input <?= ($facturaEntity->estado != 'borrador')?'disabled ':''?> id="cliente_nombre" name="cliente_nombre" tabindex="6" class="form-control update-cabecera" value="<?= old('cliente_nombre', $facturaEntity->cliente_nombre) ?>"></input>
</div>
</div>
<div class="col-md-12 col-lg-3 px-4">
<div class="mb-1">
<label for="cliente_cif" class="form-label">
<?= lang('Facturas.cif') ?>
</label>
<input <?= ($facturaEntity->estado != 'borrador')?'disabled ':''?> id="cliente_cif" name="cliente_cif" tabindex="7" class="form-control update-cabecera" value="<?= old('cliente_cif', $facturaEntity->cliente_cif) ?>"></input>
</div>
</div>
<div class="col-md-12 col-lg-3 px-4">
<div class="mb-1">
<label for="cliente_pais" class="form-label">
<?= lang('Facturas.pais') ?>
</label>
<input <?= ($facturaEntity->estado != 'borrador')?'disabled ':''?> id="cliente_pais" name="cliente_pais" tabindex="8" class="form-control update-cabecera" value="<?= old('cliente_pais', $facturaEntity->cliente_pais) ?>"></input>
</div>
</div>
</div><!--//.row -->
<div class="row mb-3">
<div class="col-md-12 col-lg-4 px-4">
<div class="mb-1">
<label for="cliente_direccion" class="form-label">
<?= lang('Facturas.direccion') ?>
</label>
<input <?= ($facturaEntity->estado != 'borrador')?'disabled ':''?> id="cliente_direccion" name="cliente_address" tabindex="6" class="form-control update-cabecera" value="<?= old('cliente_address', $facturaEntity->cliente_address) ?>"></input>
</div>
</div>
<div class="col-md-12 col-lg-2 px-4">
<div class="mb-1">
<label for="cliente_cp" class="form-label">
<?= lang('Facturas.cp') ?>
</label>
<input <?= ($facturaEntity->estado != 'borrador')?'disabled ':''?> id="cliente_cp" name="cliente_cp" tabindex="7" class="form-control update-cabecera" value="<?= old('cliente_cp', $facturaEntity->cliente_cp) ?>"></input>
</div>
</div>
<div class="col-md-12 col-lg-3 px-4">
<div class="mb-1">
<label for="cliente_ciudad" class="form-label">
<?= lang('Facturas.localidad') ?>
</label>
<input <?= ($facturaEntity->estado != 'borrador')?'disabled ':''?> id="cliente_ciudad" name="cliente_ciudad" tabindex="8" class="form-control update-cabecera" value="<?= old('cliente_ciudad', $facturaEntity->cliente_ciudad) ?>"></input>
</div>
</div>
<div class="col-md-12 col-lg-3 px-4">
<div class="mb-1">
<label for="cliente_provincia" class="form-label">
<?= lang('Facturas.provincia') ?>
</label>
<input <?= ($facturaEntity->estado != 'borrador')?'disabled ':''?> id="cliente_provincia" name="cliente_provincia" tabindex="8" class="form-control update-cabecera" value="<?= old('cliente_provincia', $facturaEntity->cliente_provincia) ?>"></input>
</div>
</div>
</div><!--//.row -->
<div class="row">
<div class="col-md-12 col-lg-12 px-4">
<div class="pt-4">
<?php if ($facturaEntity->estado === 'validada' && (auth()->user()->inGroup('beta') || auth()->user()->inGroup('admin'))) : ?>
<button
type="button"
class="btn btn-label-danger float-start me-sm-3 me-1"
name="editarValidada"
id="editarValidada" >
<span class="ti-xs ti ti-save me-1"></span>
<?= lang("Basic.global.edit") ?>
</button>
<?php endif; ?>
<button
type="button"
class="btn btn-label-primary float-start me-sm-3 me-1"
name="exportar_lineas"
id="exportar_lineas" >
<span class="ti-xs ti ti-file-spreadsheet me-1"></span>
<?= lang("Facturas.exportarLineas") ?>
</button>
<button
type="button"
class="btn btn-label-primary float-start me-sm-3 me-1"
name="duplicar"
id="duplicar" >
<span class="ti-xs ti ti-copy me-1"></span>
<?= lang("Facturas.duplicar") ?>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<?=$this->section('additionalInlineJs') ?>
$("#fecha_factura_at").flatpickr({
defaultDate: <?= $facturaEntity->fecha_factura_at_text ? "'".$facturaEntity->fecha_factura_at_text."'" : 'null' ?>,
dateFormat: "d/m/Y",
locale: {
firstDayOfWeek: 1,
weekdays: {
shorthand: ['Do', 'Lu', 'Ma', 'Mi', 'Ju', 'Vi', 'Sa'],
longhand: ['Domingo', 'Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado'],
},
months: {
shorthand: ['Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Оct', 'Nov', 'Dic'],
longhand: ['Enero', 'Febreo', 'Мarzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'],
},
},
onChange: function(selectedDates, dateStr, instance) {
<?php if ($facturaEntity->estado == 'borrador'): ?>
updateDate('fecha_entrega_at', dateStr);
<?php endif; ?>
}
});
function updateDate(elementId, dateStr) {
var id = <?=$facturaEntity->id ?>;
data = {
<?= csrf_token() ?? "token" ?>: <?= csrf_token() ?>v,
};
var parts = dateStr.split('/');
var newFormat = parts[2] + '-' + parts[1] + '-' + parts[0]; // Asume dateStr en formato d/m/Y.
data[elementId] = newFormat;
var url = '<?= route_to('actualizarFactura', ':id') ?>';
url = url.replace(':id', id );
$.ajax({
url: url,
type: 'POST',
data: data,
success: function(response){
if('error' in response){
}
}
});
}
$('#serie_id').select2({
allowClear: false,
minimumResultsForSearch: -1,
ajax: {
url: '<?= route_to("menuItemsOfSeriesFacturas") ?>',
type: 'post',
dataType: 'json',
data: function(params) {
return {
id: 'id',
text: 'nombre',
searchTerm: params.term,
<?= csrf_token() ?? "token" ?> : <?= csrf_token() ?>v
};
},
delay: 60,
processResults: function(response) {
yeniden(response.<?= csrf_token() ?>);
return {
results: response.menu
};
},
cache: true
}
});
$('#cliente_id').select2({
allowClear: false,
ajax: {
url: '<?= route_to("menuItemsOfClientes") ?>',
type: 'post',
dataType: 'json',
data: function(params) {
return {
id: 'id',
text: 'alias',
searchTerm: params.term,
<?= csrf_token() ?? "token" ?> : <?= csrf_token() ?>v
};
},
delay: 60,
processResults: function(response) {
yeniden(response.<?= csrf_token() ?>);
return {
results: response.menu
};
},
cache: true
}
});
$('#editarValidada').on('click', function(){
$('.update-cabecera').prop('disabled', false);
});
$('#duplicar').on('click', function() {
var id = <?=$facturaEntity->id ?>;
var url = '<?= route_to('duplicarFactura', ':id') ?>';
url = url.replace(':id', id );
$.ajax({
url: url,
type: 'POST',
data: {
<?= csrf_token() ?? "token" ?>: <?= csrf_token() ?>v,
},
success: function(response){
if('error' in response){
} else {
var url = '<?= route_to('editarFactura', ':id') ?>';
url = url.replace(':id', response.id);
window.location.href = url;
}
}
});
});
$(".update-cabecera").on("change", function(){
if($(this).attr('id') == 'serie_id'){
var id = $(this).val();
if(id == 7 || id == 9){
// se muestra el campo de factura rectificada que tiene como clase factura-R
$('.factura-R').show();
$('#div_cliente').removeClass('col-lg-6').addClass('col-lg-4');
} else {
// se oculta el campo de factura rectificada
$('.factura-R').hide();
$('#div_cliente').removeClass('col-lg-4').addClass('col-lg-6');
}
}
$.ajax({
url: '<?= route_to('updateCabecera', $facturaEntity->id) ?>',
type: 'POST',
data: {
<?= csrf_token() ?? "token" ?>: <?= csrf_token() ?>v,
name: this.name,
value: $(this).val()
},
success: function(response){
if('error' in response){
}
}
});
});
<?=$this->endSection() ?>

View File

@ -0,0 +1,460 @@
<div class="accordion accordion-bordered mt-3" id="lineasFactura">
<div class="card accordion-item active">
<h2 class="accordion-header" id="headingLineasFacturas">
<button type="button" class="accordion-button" data-bs-toggle="collapse" data-bs-target="#accordionLineasFacturaTip" aria-expanded="false" aria-controls="accordionLineasFacturaTip">
<h3><?= lang("Facturas.lineas") ?></h3>
</button>
</h2>
<div id="accordionLineasFacturaTip" class="accordion-collapse collapse show" data-bs-parent="#accordioLineasFactura">
<div class="accordion-body">
<table id="tableOfLineasFactura" class="table table-striped table-hover" style="width: 100%;grid-template-columns: 1fr 1fr 6fr 1fr 1fr 1fr;">
<thead>
<tr>
<th style="max-width:60px;"></th>
<th>id</th>
<th></th>
<th></th>
<th></th>
<th><?= lang('Facturas.unidades') ?></th>
<th><?= lang('Facturas.concepto') ?></th>
<th><?= lang('Facturas.precioUnidad') ?></th>
<th><?= lang('Facturas.iva') ?></th>
<th><?= lang('Facturas.subtotal') ?></th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
</tbody>
<tfoot>
<tr>
<td colspan="9" style="text-align:right">Subtotal:</td>
<td id="subtotal-sum"></td>
<td></td>
<td></td>
</tr>
<tr>
<td colspan="9" style="text-align:right">I.V.A.:</td>
<td id="total-iva-sum"></td>
<td></td>
<td></td>
</tr>
<tr>
<td colspan="9" style="text-align:right">Total:</td>
<td id="total-sum"></td>
<td></td>
<td></td>
</tr>
<tr>
<td <?= ($facturaEntity->serie_id == 7 || $facturaEntity->serie_id == 9)? "style='display:none;'":"" ?> colspan="9" style="text-align:right">Pendiente de pago:</td>
<td <?= ($facturaEntity->serie_id == 7 || $facturaEntity->serie_id == 9)? "style='display:none;'":"" ?> id="pendiente-pago"></td>
<td></td>
<td></td>
</tr>
</tfoot>
</table>
<?php if($facturaEntity->estado =='borrador') : ?>
<div class="row">
<div class="col-md-12 col-lg-2">
<button
type="button"
class="btn btn-label-primary float-start me-sm-3 me-1"
name="addLineaFactura"
id="addLineaFactura" >
<?= lang("Facturas.nuevaLinea") ?>
</button>
</div>
</div>
<?php endif; ?>
</div>
</div>
</div>
</div>
<?=$this->section('additionalInlineJs') ?>
const actionBtns = function(data) {
// se comprueba si data es null
<?php if($facturaEntity->estado != 'borrador') :?>
if (data.pedido_id != null) {
return `
<div class="text-right py-0 align-middle">
<div class="row">
<button type="button" class="btn btn-sm btn-primary btn-view_pedido" data-id="${data.pedido_id}">Ver pedido</button>
</div>
</div>
`;
}
else
{
return ``;
}
<?php else: ?>
if (data.pedido_id === null) {
return `
<td class="text-right py-0 align-middle">
<div class="row mb-2">
<div class="btn-group btn-group-sm">
<a href="javascript:void(0);"><i class="ti ti-trash ti-sm btn-delete mx-2" data-id="${data.id}"></i></a>
<span class="edit"><a href="javascript:void(0);"><i class="ti ti-pencil ti-sm btn-edit mx-2" data-id="${data.id}"></i></a></span>
<span class="cancel"></span>
</div>
</div>
</td>`;
}
else{
return `
<div class="text-right py-0 align-middle">
<div class="row mb-2 align-middle">
<div class="btn-group btn-group-sm">
<a href="javascript:void(0);"><i class="ti ti-trash ti-sm btn-delete mx-2" data-id="${data.id}"></i></a>
<span class="edit"><a href="javascript:void(0);"><i class="ti ti-pencil ti-sm btn-edit mx-2" data-id="${data.id}"></i></a></span>
<span class="cancel"></span>
</div>
</div>
<div class="row">
<button type="button" class="btn btn-sm btn-primary btn-view_pedido" data-id="${data.pedido_id}">Ver pedido</button>
</div>
</div>
`;
}
<?php endif; ?>
};
var editor_lineas = new $.fn.dataTable.Editor( {
ajax: {
url: "<?= route_to('editorOfLineasFacturas') ?>",
headers: {
<?= csrf_token() ?? "token" ?> : <?= csrf_token() ?>v,
},
},
table : "#tableOfLineasFactura",
idSrc: 'id',
fields: [
{
name: "cantidad",
}, {
name: "descripcion",
type: "textarea",
attr: {
rows: 5,
style: "height: 120px;"
}
}, {
name: "precio_unidad",
attr: {
style: "min-width: 65px;"
}
}, {
name: "iva",
}, {
name: "pedido_linea_impresion_id",
type: "hidden"
}, {
name: "pedido_maquetacion_id",
type: "hidden"
}, {
name: "id",
type: "hidden"
}, {
name: "base",
type: "hidden"
},
]
} );
var old_cantidad = 0;
editor_lineas.on( 'preEdit', function ( e, json, data, id ) {
old_cantidad = data.cantidad;
});
editor_lineas.on( 'preSubmit', function ( e, d, type ) {
if ( type === 'create'){
d.data[0]['factura_id'] = <?= $facturaEntity->id ?>;
d.data[0]['old_cantidad'] = null;
}
else if(type === 'edit' ) {
for (v in d.data){
d.data[v]['factura_id'] = <?= $facturaEntity->id ?>;
d.data[v]['old_cantidad'] = old_cantidad;
}
}
});
editor_lineas.on( 'postSubmit', function ( e, json, data, action ) {
yeniden(json.<?= csrf_token() ?>);
});
editor_lineas.on( 'submitSuccess', function ( e, json, data, action ) {
tableLineas.clearPipeline();
tableLineas.draw();
});
// Activate an inline edit on click of a table cell
$('#tableOfLineasFactura').on( 'click', 'tbody span.edit', function (e) {
editor_lineas.inline(tableLineas.cells(this.closest('tr'), '*').nodes(),
{
cancelHtml: '<a href="javascript:void(0);"><i class="ti ti-x"></i></a>',
cancelTrigger: 'span.cancel',
submitHtml: '<a href="javascript:void(0);"><i class="ti ti-device-floppy"></i></a>',
submitTrigger: 'span.edit',
submit: 'allIfChanged'
}
);
} );
var tableLineas = $('#tableOfLineasFactura').DataTable({
processing: true,
serverSide: true,
autoWidth: true,
responsive: true,
scrollX: true,
columns: [
{
data: actionBtns,
className: 'row-edit dt-center'
},
{data: "id"},
{data: "pedido_linea_impresion_id"},
{data: "pedido_maquetacion_id"},
{data: "pedido_id"},
{data: "cantidad"},
{
data: "descripcion",
render: function (data, type, row, meta) {
if(row.pedido_linea_impresion_id != null){
// se convierten a float data.total_aceptado y subtotal
var total_aceptado = parseFloat(row.total_aceptado);
var subtotal = parseFloat(row.base);
var error_text = '';
if(total_aceptado != subtotal){
error_text = 'El total del pedido ('+ total_aceptado + '€) no coincide con la línea ('+ subtotal + '€)';
}
return `
<div>
${data}
</div>
<div class="mt-5">
<span style="color: red;" id="error-${meta.row}">${error_text}</span>
</div>
<div class="mt-2">
<label for="input-${meta.row}">Total aceptado</label>
<input readonly type="text" id="input-${meta.row}" value="${row.total_aceptado}">
</div>
`;
}
else{
return `
<div>
${data}
</div>
`;
}
}
},
{data: "precio_unidad"},
{data: "iva"},
{data: "base"},
{data: "total_iva"},
{data: "total"},
],
order: [[1, "asc"]],
dom: 't',
language: {
url: "/themes/vuexy/vendor/libs/datatables-sk/plugins/i18n/es-ES.json"
},
ajax : $.fn.dataTable.pipeline( {
url: '<?= route_to('dataTableOfLineasFacturas', $facturaEntity->id) ?>',
method: 'POST',
headers: {'X-Requested-With': 'XMLHttpRequest'},
async: true,
}),
columnDefs: [
{
orderable: false,
searchable: false,
targets: [0]
},
{
visible: false,
targets: [1, 2, 3, 4, 10, 11]
}
],
footerCallback: function (row, data, start, end, display) {
updateFooterLineas(this.api());
}
});
function updateFooterLineas(table){
// Remove the formatting to get integer data for summation
var intVal = function (i) {
return typeof i === 'string' ?
i.replace(/[\$,]/g, '')*1 :
typeof i === 'number' ?
i : 0;
};
// Total over all pages
var totalSubtotal = table
.column(9)
.data()
.reduce(function (a, b) {
return intVal(a) + intVal(b);
}, 0);
var totalIVA = table
.column(10)
.data()
.reduce(function (a, b) {
return intVal(a) + intVal(b);
}, 0);
var totalTotal = table
.column(11)
.data()
.reduce(function (a, b) {
return intVal(a) + intVal(b);
}, 0);
// Update footer
$('#subtotal-sum').html(totalSubtotal.toFixed(2));
$('#total-iva-sum').html(totalIVA.toFixed(2));
$('#total-sum').html(totalTotal.toFixed(2));
// Assuming pendiente de pago is totalTotal - totalIVA for this example
<?php if($facturaEntity->estado == 'borrador') :?>
var pendientePago = totalTotal ;
var total_pagos = 0;
<?php else: ?>
var total_pagos = parseFloat($('#totalCobrado-sum').html()).toFixed(2);
var pendientePago = totalTotal - total_pagos;
<?php endif; ?>
if(isNaN(pendientePago)){
pendientePago = 0;
}
$('#pendiente-pago').html(pendientePago.toFixed(2));
$.ajax({
url: '<?= route_to('updateFacturaTotales', $facturaEntity->id) ?>',
method: 'POST',
data: {
base: totalSubtotal,
total: totalTotal,
total_pagos: total_pagos,
pendiente: pendientePago
}
}).done((data, textStatus, jqXHR) => {
if(data.estado_pago == 'pagada'){
$('#estado_pago_text').text('<?= lang('Facturas.pagada') ?>');
$('#estado_pago_text').css('color', 'green');
}
else{
$('#estado_pago_text').text('<?= lang('Facturas.pendiente') ?>');
$('#estado_pago_text').css('color', 'red');
}
}).fail((jqXHR, textStatus, errorThrown) => {
popErrorAlert(jqXHR.responseJSON.messages.error)
})
}
// Delete row
$(document).on('click', '.btn-delete', function(e) {
const dataId = $(this).attr('data-id');
const row = $(this).closest('tr');
if ($.isNumeric(dataId)) {
asyncConfirmDialogWithParams(
"Borrar Linea de Factura",
"¿Está seguro de borrar la línea? Esta acción no se puede deshacer.",
deleteConfirmed, function(){}, [dataId, row])
}
});
function deleteConfirmed(params){
var factura_linea_id = params[0];
var row = params[1];
const row_data = tableLineas.row($(row)).data();
if(row_data.pedido_linea_impresion_id != null){
var url = '<?= route_to('deleteLineaPedidoImpresion') ?>';
$.ajax({
url: url,
method: 'POST',
data: {
factura_id: <?= $facturaEntity->id ?>,
pedido_linea_impresion_id: row_data.pedido_linea_impresion_id,
cantidad: row_data.cantidad
}
}).done((data, textStatus, jqXHR) => {
}).fail((jqXHR, textStatus, errorThrown) => {
popErrorAlert(jqXHR.responseJSON.messages.error)
})
}
var url = '<?= route_to('deleteLineaFactura', ':id') ?>';
url = url.replace(':id', factura_linea_id );
$.ajax({
url: url,
method: 'GET',
}).done((data, textStatus, jqXHR) => {
$('#tableOfLineasFactura').DataTable().clearPipeline();
$('#tableOfLineasFactura').DataTable().row($(row)).invalidate().draw();
}).fail((jqXHR, textStatus, errorThrown) => {
popErrorAlert(jqXHR.responseJSON.messages.error)
})
}
$(document).on('click', '.btn-view_pedido', function(e) {
var pedido_id = $(this).data('id');
var url = '<?= route_to('editarPedido', ':id') ?>';
url = url.replace(':id', pedido_id );
window.open(url, '_blank');
});
$('#addLineaFactura').on('click', function() {
const formOptions= {
submitTrigger: 0,
submitHtml: '<a href="javascript:void(0);"><i class="ti ti-device-floppy"></i></a>'
};
editor_lineas.inlineCreate('end', formOptions);
});
<?=$this->endSection() ?>

View File

@ -0,0 +1,352 @@
<div class="accordion accordion-bordered mt-3" id="pagosFacturas">
<div class="card accordion-item active">
<h2 class="accordion-header" id="headingPagosFacturas">
<button type="button" class="accordion-button" data-bs-toggle="collapse" data-bs-target="#accordionPagosFacturaTip" aria-expanded="false" aria-controls="accordionPagosFacturaTip">
<h3><?= lang("Facturas.pagos") ?></h3>
</button>
</h2>
<div id="accordionPagosFacturaTip" class="accordion-collapse collapse show" data-bs-parent="#pagosFacturas">
<div class="accordion-body">
<table id="tableOfLineasPagos" class="table table-striped table-hover" style="width: 100%; grid-template-columns: 1fr 2fr 6fr 1fr 1fr 1fr;"">
<thead>
<tr>
<th style="max-width:30px;"></th>
<th></th>
<th><?= lang('Facturas.formaPago') ?></th>
<th><?= lang('Facturas.notas') ?></th>
<th><?= lang('Facturas.fechaVencimiento') ?></th>
<th><?= lang('Facturas.fechaCobro') ?></th>
<th><?= lang('Facturas.cantidad') ?></th>
</tr>
</thead>
<tbody></tbody>
<tfoot>
<tr>
<td colspan="6" style="text-align:right">Total:</td>
<td id="totalCobrado-sum"></td>
</tr>
</tfoot>
</table>
<div id="addPagoRow" class="row">
<div class="col-md-12 col-lg-2">
<button
type="button"
class="btn btn-label-primary float-start me-sm-3 me-1"
name="addPagoFactura"
id="addPagoFactura" >
<?= lang("Facturas.addPago") ?>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
<?=$this->section('additionalInlineJs') ?>
const formas_pago = <?= json_encode($facturaEntity->formas_pago) ?>;
var formaPagoLookup = {};
formas_pago.forEach(function(pago) {
formaPagoLookup[pago.value] = pago.label;
});
const actionBtns_pagos = function(data) {
return `
<div class="btn-group btn-group-sm">
<a href="javascript:void(0);"><i class="ti ti-trash ti-sm btn-delete-pago mx-2" data-id="${data.id}"></i></a>
<span class="edit-pago"><a href="javascript:void(0);"><i class="ti ti-pencil ti-sm btn-edit-pago mx-2" data-id="${data.id}"></i></a></span>
<span class="cancel-pago"></span>
</div>`;
}
var editor_pagos = new $.fn.dataTable.Editor( {
ajax: {
url: "<?= route_to('editorOfPagosFacturas') ?>",
headers: {
<?= csrf_token() ?? "token" ?> : <?= csrf_token() ?>v,
},
},
table : "#tableOfLineasPagos",
idSrc: 'id',
fields: [
{
name: "forma_pago_id",
type: "select",
options: formas_pago,
},
{
name: "notes",
type: "textarea",
attr: {
rows: 5,
style: "height: 120px;"
}
},
{
name: "total",
attr: {
style: "min-width: 65px;"
}
},
{
name: "fecha_pago_at",
type: "datetime",
def: function () {
return new Date().toISOString().split('T')[0]; // YYYY-MM-DD
},
wireFormat: 'YYYY-MM-DD HH:mm:ss',
displayFormat: 'DD/MM/YYYY',
},
{
name: "fecha_vencimiento_at",
type: "datetime",
def: () => new Date(),
def: function () {
return new Date().toISOString().split('T')[0]; // YYYY-MM-DD
},
wireFormat: 'YYYY-MM-DD HH:mm:ss',
displayFormat: 'DD/MM/YYYY',
},
{
name: "id",
type: "hidden"
},
{
name: "factura_id",
type: "hidden"
},
]
});
editor_pagos.on( 'preSubmit', function ( e, d, type ) {
if ( type === 'create'){
d.data[0]['factura_id'] = <?= $facturaEntity->id ?>;
}
else if(type === 'edit' ) {
for (v in d.data){
d.data[v]['factura_id'] = <?= $facturaEntity->id ?>;
}
}
});
editor_pagos.on( 'postSubmit', function ( e, json, data, action ) {
yeniden(json.<?= csrf_token() ?>);
tablePagos.clearPipeline();
tablePagos.draw();
});
var tablePagos = $('#tableOfLineasPagos').DataTable({
processing: true,
serverSide: true,
autoWidth: true,
responsive: true,
scrollX: true,
columns: [
{
data: null,
render: actionBtns_pagos,
className: 'row-edit dt-center'
},
{data: "id"},
{
data: "forma_pago_id",
render: function(data, type, row) {
return formaPagoLookup[data] || data;
}
},
{data: "notes"},
{
data: "fecha_vencimiento_at",
render: function(data, type, row) {
if(data == null){
return '';
}
return data!='0000-00-00 00:00:00' ? moment(data).format('DD/MM/YYYY') : '';
}
},
{
data: "fecha_pago_at",
render: function(data, type, row) {
if(data == null){
return '';
}
return data!='0000-00-00 00:00:00' ? moment(data).format('DD/MM/YYYY') : '';
}
},
{data: "total"},
],
order: [[1, "asc"]],
dom: 't',
language: {
url: "/themes/vuexy/vendor/libs/datatables-sk/plugins/i18n/es-ES.json"
},
ajax: {
url: '<?= route_to('dataTableOfPagosFacturas', $facturaEntity->id) ?>',
method: 'POST',
headers: {'X-Requested-With': 'XMLHttpRequest'},
async: true,
},
columnDefs: [
{
orderable: false,
searchable: false,
targets: [0]
},
{
visible: false,
targets: [1]
},
{
width: '40%', // Ajusta el ancho para la columna de notas
targets: 3
},
{
width: '10%', // Ajusta el ancho para la columna de notas
targets: [4, 5, 6]
},
],
footerCallback: function (row, data, start, end, display) {
var api = this.api();
// Remove the formatting to get integer data for summation
var intVal = function (i) {
return typeof i === 'string' ? i.replace(/[\$,]/g, '')*1 : typeof i === 'number' ? i : 0;
};
// Total over all pages
var totalPagos = api
.column(6)
.data()
.reduce(function (a, b) {
return intVal(a) + intVal(b);
}, 0);
// Update footer
$('#totalCobrado-sum').html(totalPagos.toFixed(2));
// call footerCallback of the other table
if (typeof tableLineas !== 'undefined') {
updateFooterLineas(tableLineas);
}
}
});
function updateFooterLineas(table){
// Remove the formatting to get integer data for summation
var intVal = function (i) {
return typeof i === 'string' ?
i.replace(/[\$,]/g, '')*1 :
typeof i === 'number' ?
i : 0;
};
// Total over all pages
var totalSubtotal = table
.column(9)
.data()
.reduce(function (a, b) {
return intVal(a) + intVal(b);
}, 0);
var totalIVA = table
.column(10)
.data()
.reduce(function (a, b) {
return intVal(a) + intVal(b);
}, 0);
var totalTotal = table
.column(11)
.data()
.reduce(function (a, b) {
return intVal(a) + intVal(b);
}, 0);
// Update footer
$('#subtotal-sum').html(totalSubtotal.toFixed(2));
$('#total-iva-sum').html(totalIVA.toFixed(2));
$('#total-sum').html(totalTotal.toFixed(2));
// Assuming pendiente de pago is totalTotal - totalIVA for this example
<?php if($facturaEntity->estado == 'borrador') :?>
var pendientePago = totalTotal ;
var total_pagos = 0;
<?php else: ?>
var total_pagos = parseFloat($('#totalCobrado-sum').html()).toFixed(2);
var pendientePago = totalTotal - total_pagos;
<?php endif; ?>
// Se comprueba si pendientePago es un numero o NAN
if(isNaN(pendientePago)){
pendientePago = 0;
}
$('#pendiente-pago').html(pendientePago.toFixed(2));
$.ajax({
url: '<?= route_to('updateFacturaTotales', $facturaEntity->id) ?>',
method: 'POST',
data: {
base: totalSubtotal,
total: totalTotal,
total_pagos: total_pagos,
pendiente: pendientePago
}
}).done((data, textStatus, jqXHR) => {
if($('#pendiente-pago').html() == '0.00'){
$('#addPagoRow').hide();
} else {
$('#validarFactura').show();
}
if(data.estado_pago == 'pagada'){
$('#estado_pago_text').text('<?= lang('Facturas.pagada') ?>');
$('#estado_pago_text').css('color', 'green');
}
else{
$('#estado_pago_text').text('<?= lang('Facturas.pendiente') ?>');
$('#estado_pago_text').css('color', 'red');
}
}).fail((jqXHR, textStatus, errorThrown) => {
popErrorAlert(jqXHR.responseJSON.messages.error)
})
}
$('#addPagoFactura').on('click', function () {
const formOptions= {
submitTrigger: 0,
submitHtml: '<a href="javascript:void(0);"><i class="ti ti-device-floppy"></i></a>'
};
editor_pagos.inlineCreate('end', formOptions);
});
// Activate an inline edit on click of a table cell
$('#tableOfLineasPagos').on( 'click', 'tbody span.edit-pago', function (e) {
editor_pagos.inline(tablePagos.cells(this.closest('tr'), '*').nodes(),
{
cancelHtml: '<a href="javascript:void(0);"><i class="ti ti-x"></i></a>',
cancelTrigger: 'span.cancel-pago',
submitHtml: '<a href="javascript:void(0);"><i class="ti ti-device-floppy"></i></a>',
submitTrigger: 'span.edit-pago',
submit: 'allIfChanged'
}
);
} );
<?=$this->endSection() ?>

View File

@ -0,0 +1,22 @@
<div class="accordion accordion-bordered mt-3" id="rectificadaFactura">
<div class="card accordion-item active">
<h2 class="accordion-header" id="headingrectificadaFactura">
<button type="button" class="accordion-button" data-bs-toggle="collapse" data-bs-target="#accordionRectificadaFacturaTip" aria-expanded="false" aria-controls="accordionRectificadaFacturaTip">
<h3><?= lang("Facturas.facturaRectificada") ?></h3>
</button>
</h2>
<div id="accordionRectificadaFacturaTip" class="accordion-collapse collapse show" data-bs-parent="#rectificadaFactura">
<div class="accordion-body">
<p><?= lang("Facturas.facturaPagada") ?></p>
</div>
</div>
</div>
</div>
<?=$this->section('additionalInlineJs') ?>
<?=$this->endSection() ?>

View File

@ -0,0 +1,118 @@
<?= $this->include('themes/_commonPartialsBs/datatables') ?>
<?= $this->include("themes/_commonPartialsBs/select2bs5") ?>
<?= $this->include("themes/_commonPartialsBs/sweetalert") ?>
<?= $this->include('themes/_commonPartialsBs/_confirm2delete') ?>
<?=$this->extend('themes/vuexy/main/defaultlayout') ?>
<?= $this->section("content") ?>
<div class="row">
<div class="col-12">
<div class="card card-info">
<div class="card-header">
<h3 class="card-title"><?= $boxTitle ?? $pageTitle ?></h3>
</div><!--//.card-header -->
<form id="addFacturaForm" class="card-body" method="post" action="<?= $formAction ?>">
<?= csrf_field() ?>
<?= view("themes/_commonPartialsBs/_alertBoxes") ?>
<?= !empty($validation->getErrors()) ? $validation->listErrors("bootstrap_style") : "" ?>
<div class="row">
<div class="col-md-12 col-lg-6 px-4">
<div class="mb-3">
<label for="cliente_id" class="form-label">
<?= lang('Presupuestos.clienteId') ?>*
</label>
<select id="cliente_id" name="cliente_id" class="form-control select2bs2" style="width: 100%;"></select>
</div><!--//.mb-3 -->
</div><!--//.col -->
</div><!--//.row -->
<div class="row">
<div class="col-md-12 col-lg-6 px-4">
<div class="mb-3">
<label for="serie_id" class="form-label">
<?= lang('Facturas.serieFacturacion') ?>*
</label>
<select id="serie_id" name="serie_id" class="form-control select2bs2" style="width: 100%;"></select>
</div><!--//.mb-3 -->
</div><!--//.col -->
</div><!--//.row -->
<div class="pt-4">
<input type="submit"
class="btn btn-primary float-start me-sm-3 me-1"
name="save"
value="<?= lang("Basic.global.Save") ?>"
/>
<?= anchor(route_to("tarifaAcabadoList"), lang("Basic.global.Cancel"), ["class" => "btn btn-secondary float-start"]) ?>
</div><!-- /.card-footer -->
</form>
</div><!-- //.card -->
</div><!--//.col -->
</div><!--//.row -->
<?= $this->endSection() ?>
<?= $this->section("additionalInlineJs") ?>
$('#cliente_id').select2({
allowClear: false,
ajax: {
url: '<?= route_to("menuItemsOfClientes") ?>',
type: 'post',
dataType: 'json',
data: function(params) {
return {
id: 'id',
text: 'nombre',
searchTerm: params.term,
<?= csrf_token() ?? "token" ?> : <?= csrf_token() ?>v
};
},
delay: 60,
processResults: function(response) {
yeniden(response.<?= csrf_token() ?>);
return {
results: response.menu
};
},
cache: true
}
});
$('#serie_id').select2({
allowClear: false,
minimumResultsForSearch: -1,
ajax: {
url: '<?= route_to("menuItemsOfSeriesFacturas") ?>',
type: 'post',
dataType: 'json',
data: function(params) {
return {
id: 'id',
text: 'nombre',
searchTerm: params.term,
<?= csrf_token() ?? "token" ?> : <?= csrf_token() ?>v
};
},
delay: 60,
processResults: function(response) {
yeniden(response.<?= csrf_token() ?>);
return {
results: response.menu
};
},
cache: true
}
});
<?= $this->endSection() ?>

View File

@ -0,0 +1,132 @@
<?= $this->include('themes/_commonPartialsBs/datatables') ?>
<?= $this->include("themes/_commonPartialsBs/select2bs5") ?>
<?= $this->include("themes/_commonPartialsBs/sweetalert") ?>
<?= $this->include('themes/_commonPartialsBs/_confirm2delete') ?>
<?=$this->extend('themes/vuexy/main/defaultlayout') ?>
<?= $this->section("content") ?>
<div class="row">
<div class="col-12">
<div class="card card-info">
<div class="card-header">
<h3 class="card-title"><?= $boxTitle ?? $pageTitle ?></h3>
</div><!--//.card-header -->
<form id="addFacturaForm" class="card-body" method="post" action="<?= $formAction ?>">
<?= csrf_field() ?>
<?= view("themes/_commonPartialsBs/_alertBoxes") ?>
<?= !empty($validation->getErrors()) ? $validation->listErrors("bootstrap_style") : "" ?>
<?= view("themes/vuexy/form/facturas/_facturaCabeceraItems") ?>
<?php if($facturaEntity->estado =='borrador') : ?>
<?= view("themes/vuexy/form/facturas/_addPedidosItems") ?>
<?php endif; ?>
<?= view("themes/vuexy/form/facturas/_facturaLineasItems") ?>
<?php if($facturaEntity->estado !='borrador' && (strpos($facturaEntity->numero, "REC ") !== 0) ) : ?>
<?= view("themes/vuexy/form/facturas/_pagosFacturasItems") ?>
<?php endif; ?>
<?php if($facturaEntity->estado !='borrador' && (strpos($facturaEntity->numero, "REC ") === 0) ) : ?>
<?= view("themes/vuexy/form/facturas/_rectificadaFacturasItems") ?>
<?php endif; ?>
<div class="pt-4">
<?php if($facturaEntity->estado =='borrador') : ?>
<input type="button"
class="btn btn-success float-start me-sm-3 me-1"
id="validarFactura"
name="validarFactura"
value="<?= lang("Facturas.validarFactura") ?>"
/>
<input type="button"
class="btn btn-danger float-start me-sm-3 me-1"
id="borrarFactura"
name="borrarFactura"
value="<?= lang("Facturas.borrarFactura") ?>"
/>
<?php endif; ?>
<input type="button"
class="btn btn-info float-start me-sm-3 me-1"
id="imprimirFactura"
name="imprimirFactura"
value="<?= lang("Facturas.imprimirFactura") ?>"
/>
<?= anchor(route_to("facturasList"), lang("Basic.global.back"), ["class" => "btn btn-secondary float-start"]) ?>
</div><!-- /.card-footer -->
</form>
</div><!-- //.card -->
</div><!--//.col -->
<?= view("themes/_commonPartialsBs/_modalConfirmDialog") ?>
</div><!--//.row -->
<?= $this->endSection() ?>
<?= $this->section("additionalInlineJs") ?>
$("#borrarFactura").on("click", function(){
asyncConfirmDialog(
"Borrar Factura",
"¿Está seguro de borrar la factura? Esta acción no se puede deshacer.",
deleteConfirmed, null)
});
function deleteConfirmed(){
$.ajax({
url: "<?= route_to("borrarFactura", $facturaEntity->id) ?>",
type: 'GET',
success: function(response){
window.location.href = "<?= route_to("facturasList") ?>";
}
});
}
$("#validarFactura").on("click", function(){
asyncConfirmDialog(
"Validar Factura",
"¿Está seguro de pasar la factura a validada? Esta acción no se puede deshacer.",
validatedConfirmed, null)
});
function validatedConfirmed(){
$.ajax({
url: "<?= route_to("validarFactura", $facturaEntity->id) ?>",
type: 'GET',
success: function(response){
window.location.href = "<?= route_to("editarFactura", $facturaEntity->id) ?>";
}
});
}
<?= $this->endSection() ?>
<?=$this->section('css') ?>
<link rel="stylesheet" href="<?= site_url("/themes/vuexy/vendor/libs/flatpickr/flatpickr.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/css/sk-datatables.css') ?>">
<link rel="stylesheet" href="<?= site_url('themes/vuexy/css/datatables-editor/editor.dataTables.min.css') ?>">
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/datetime/1.5.2/css/dataTables.dateTime.min.css">
<?=$this->endSection() ?>
<?= $this->section('additionalExternalJs') ?>
<script src="<?= site_url("/themes/vuexy/vendor/libs/flatpickr/flatpickr.js") ?>"></script>
<script src="<?= site_url("/themes/vuexy/vendor/libs/datatables-sk/plugins/buttons/dataTables.buttons.min.js") ?>"></script>
<script src="<?= site_url("/themes/vuexy/vendor/libs/datatables-sk/plugins/buttons/buttons.bootstrap5.min.js") ?>"></script>
<script src="<?= site_url("themes/vuexy/vendor/libs/datatables-sk/plugins/select/dataTables.select.min.js") ?>"></script>
<script src="<?= site_url("/themes/vuexy/vendor/libs/datatables-sk/plugins/buttons/buttons.html5.min.js") ?>"></script>
<script src="<?= site_url("/themes/vuexy/vendor/libs/datatables-sk/plugins/buttons/buttons.print.min.js") ?>"></script>
<script src="<?= site_url("/themes/vuexy/vendor/libs/datatables-sk/plugins/jszip/jszip.min.js") ?>"></script>
<script src="<?= site_url("/themes/vuexy/vendor/libs/datatables-sk/plugins/pdfmake/pdfmake.min.js") ?>" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="<?= site_url("/themes/vuexy/vendor/libs/datatables-sk/plugins/pdfmake/vfs_fonts.js") ?>"></script>
<script src="<?= site_url('themes/vuexy/js/datatables-editor/dataTables.editor.min.js') ?>"></script>
<script type="text/javascript" src="https://cdn.datatables.net/datetime/1.5.2/js/dataTables.dateTime.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>
<?=$this->endSection() ?>

View File

@ -27,6 +27,7 @@
<th><?= lang('Facturas.estadoPago') ?></th> <th><?= lang('Facturas.estadoPago') ?></th>
<th><?= lang('Facturas.formaPago') ?></th> <th><?= lang('Facturas.formaPago') ?></th>
<th><?= lang('Facturas.vencimiento') ?></th> <th><?= lang('Facturas.vencimiento') ?></th>
<th><?= lang('Facturas.dias') ?></th>
<th class="text-nowrap"><?= lang('Basic.global.Action') ?></th> <th class="text-nowrap"><?= lang('Basic.global.Action') ?></th>
</tr> </tr>
</thead> </thead>
@ -49,12 +50,22 @@
const lastColNr = $('#tableOfFacturas').find("tr:first th").length - 1; const lastColNr = $('#tableOfFacturas').find("tr:first th").length - 1;
const actionBtns = function(data) { const actionBtns = function(data) {
return ` if(data.estado == 'borrador'){
return `
<td class="text-right py-0 align-middle">
<div class="btn-group btn-group-sm">
<a href="javascript:void(0);"><i class="ti ti-pencil ti-sm btn-edit mx-2" data-id="${data.id}"></i></a>
</div>
</td>`;
}
else{
return `
<td class="text-right py-0 align-middle"> <td class="text-right py-0 align-middle">
<div class="btn-group btn-group-sm"> <div class="btn-group btn-group-sm">
<a href="javascript:void(0);"><i class="ti ti-eye ti-sm btn-edit mx-2" data-id="${data.id}"></i></a> <a href="javascript:void(0);"><i class="ti ti-eye ti-sm btn-edit mx-2" data-id="${data.id}"></i></a>
</div> </div>
</td>`; </td>`;
}
}; };
theTable = $('#tableOfFacturas').DataTable({ theTable = $('#tableOfFacturas').DataTable({
@ -100,7 +111,24 @@
{ 'data': 'base' }, { 'data': 'base' },
{ 'data': 'total' }, { 'data': 'total' },
{ 'data': 'pendiente' }, { 'data': 'pendiente' },
{ 'data': 'creditoAsegurado' }, { 'data': 'creditoAsegurado' ,
render: function(data, type, row, meta) {
switch(data){
case "0":
return '<?= lang('Basic.global.no') ?>';
break;
case "1":
return '<?= lang('Basic.global.yes') ?>';
break;
default:
return '--'; // Debug
break;
}
},
},
{ 'data': 'estado', { 'data': 'estado',
render: function(data, type, row, meta) { render: function(data, type, row, meta) {
switch(data){ switch(data){
@ -141,8 +169,7 @@
} }
} }
}, },
{ 'data': 'total_presupuesto' }, { 'data': 'forma_pago',
{ 'data': forma_pago,
render: function(data, type, row, meta) { render: function(data, type, row, meta) {
switch(data){ switch(data){
case "cheque": case "cheque":
@ -170,20 +197,21 @@
break; break;
default: default:
return '--'; // Debug return data; // Debug
break; break;
} }
} }
}, },
{ 'data': vencimiento }, { 'data': 'vencimiento' },
{ 'data': 'dias_vencimiento' },
{ 'data': actionBtns } { 'data': actionBtns }
] ]
}); });
$(document).on('click', '.btn-edit', function(e) { $(document).on('click', '.btn-edit', function(e) {
var url = '<?= route_to('editarPedido', ':id') ?>'; var url = '<?= route_to('editarFactura', ':id') ?>';
url = url.replace(':id', `${$(this).attr('data-id')}` ); url = url.replace(':id', `${$(this).attr('data-id')}` );
window.location.href = url; window.location.href = url;
}); });

View File

@ -10,6 +10,21 @@
<div id="accordionFacturasTip" class="accordion-collapse collapse show" data-bs-parent="#accordioFacturas"> <div id="accordionFacturasTip" class="accordion-collapse collapse show" data-bs-parent="#accordioFacturas">
<div class="accordion-body"> <div class="accordion-body">
<table id="tableOfFacturas" class="table table-striped table-hover" style="width: 100%;grid-template-columns: 1fr 1fr 6fr 1fr 1fr 1fr;">
<thead>
<tr>
<th style="max-width:60px;"></th>
<th>ID</th>
<th><?= lang('Facturas.numeroFactura') ?></th>
<th><?= lang('Facturas.serieFacturacion') ?></th>
<th><?= lang('Facturas.estado') ?></th>
<th><?= lang('Facturas.fechaFactura') ?></th>
<th><?= lang('Facturas.total') ?></th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div> <!-- /.accordion-body --> </div> <!-- /.accordion-body -->
</div> </div>
@ -19,6 +34,77 @@
<?=$this->section('additionalInlineJs') ?> <?=$this->section('additionalInlineJs') ?>
const actionBtns_facturas = function(data) {
return `
<td class="text-right py-0 align-middle">
<div class="btn-group btn-group-sm">
<a href="javascript:void(0);"><i class="ti ti-eye ti-sm btn-view-factura mx-2" data-id="${data.id}"></i></a>
</div>
</td>`;
};
tablaFacturasPedido = $('#tableOfFacturas').DataTable({
processing: true,
serverSide: true,
autoWidth: true,
responsive: true,
scrollX: true,
"dom": 't',
stateSave: true,
order: [[1, 'asc']],
language: {
url: "/themes/vuexy/vendor/libs/datatables-sk/plugins/i18n/es-ES.json"
},
ajax : $.fn.dataTable.pipeline( {
url: '<?= route_to('dataTableOfFacturasPedido') ?>',
method: 'POST',
data: function ( d ) {
d.pedido_id = <?= $pedidoEntity->id ?>;
},
headers: {'X-Requested-With': 'XMLHttpRequest'},
async: true,
}),
columnDefs: [
{
orderable: false,
searchable: false,
targets: [0]
}
],
columns : [
{ 'data': actionBtns_facturas },
{ 'data': 'id' },
{ 'data': 'numero' },
{ 'data': 'serie' },
{ 'data': 'estado',
render: function(data, type, row, meta) {
switch(data){
case "borrador":
return '<?= lang('Facturas.borrador') ?>';
break;
case "validada":
return '<?= lang('Facturas.validada') ?>';
break;
default:
return '--'; // Debug
break;
}
}
},
{ 'data': 'fecha_factura_at' },
{ 'data': 'total' },
]
});
$(document).on('click', '.btn-view-factura', function(e) {
var pedido_id = $(this).data('id');
var url = '<?= route_to('editarFactura', ':id') ?>';
url = url.replace(':id', pedido_id );
window.open(url, '_blank');
});
<?=$this->endSection() ?> <?=$this->endSection() ?>

View File

@ -130,7 +130,6 @@ $(document).on('click', '.btn-view', function(e) {
var url = '<?= route_to('editarPresupuestoCliente2', ':id') ?>'; var url = '<?= route_to('editarPresupuestoCliente2', ':id') ?>';
<?php endif; ?> <?php endif; ?>
url = url.replace(':id', `${$(this).attr('data-id')}` ); url = url.replace(':id', `${$(this).attr('data-id')}` );
console.log(url);
window.open( window.open(
url, url,
'_blank' // <- This is what makes it open in a new window. '_blank' // <- This is what makes it open in a new window.

View File

@ -16,7 +16,7 @@
</div> </div>
<div class="row"> <div class="row">
<div class="col-sm-6 mb-3" <?= $clienteId != 0 ?' style="display:none;"':''?>> <div class="col-sm-6 mb-3" <?= $clienteId != 0 && !(auth()->user()->inGroup('admin') || auth()->user()->inGroup('beta')) ?' style="display:none;"':''?>>
<label for="clienteId" class="form-label"> <label for="clienteId" class="form-label">
<?= lang('Presupuestos.clienteId') ?>* <?= lang('Presupuestos.clienteId') ?>*
</label> </label>

View File

@ -97,7 +97,7 @@
$total = $presupuestoEntity->total_aceptado; $total = $presupuestoEntity->total_aceptado;
$iva = $presupuestoEntity->iva_reducido?1.04:1.21; $iva = $presupuestoEntity->iva_reducido?1.04:1.21;
$total *= $iva; $total *= $iva;
$total_unidad = $total / $presupuestoEntity->tirada; $total_unidad = $presupuestoEntity->total_precio_unidad * $iva;;
echo '<h4 id="resumenTotalIVA" class="mb-1">Total: ' . round($total, 2) . '€</h4>'; echo '<h4 id="resumenTotalIVA" class="mb-1">Total: ' . round($total, 2) . '€</h4>';
echo '<h6 id="resumenPrecioU" class="mb-0">' . round($total_unidad, 4) . '€/ud</h6>' echo '<h6 id="resumenPrecioU" class="mb-0">' . round($total_unidad, 4) . '€/ud</h6>'
?> ?>

View File

@ -606,7 +606,7 @@ async function calcularPresupuesto() {
if($('#colorColorDiv').hasClass('checked') || $('#colorColorHqDiv').hasClass('checked')) if($('#colorColorDiv').hasClass('checked') || $('#colorColorHqDiv').hasClass('checked'))
isColor = true; isColor = true;
let isHq = false; let isHq = false;
if($('#colorNegroDiv').hasClass('checked') || $('#colorColorHqDiv').hasClass('checked')) if($('#colorNegroHqDiv').hasClass('checked') || $('#colorColorHqDiv').hasClass('checked'))
isHq = true; isHq = true;
if(!comprobarTiradasPOD()){ if(!comprobarTiradasPOD()){

View File

@ -76,6 +76,16 @@
</div> </div>
</div> </div>
<?php if ($presupuestoEntity->estado_id == 2): ?>
<div class="row mt-5">
<div class="mb-1">
<label for="paginas" class="form-label">
<?= lang('Presupuestos.totalAceptado') ?>
</label>
<input disabled type="text" id="totalAceptado" name="totalAceptado" class="form-control" value="<?= old('paginas', $presupuestoEntity->total_aceptado) ?>" <?php echo ($tipo_impresion_id == 21)?' max=80':'' ?>>
</div><!--//.mb-3 -->
</div>
<?php endif; ?>
</div> <!-- //.accordion-body --> </div> <!-- //.accordion-body -->
</div> <!-- //.accordion-collapse --> </div> <!-- //.accordion-collapse -->

View File

@ -177,8 +177,8 @@ function updateTotales(updateLP=true, updateServicios=true, updateEnvio=true){
margenEnvios = parseFloat($('#margenEnvios').attr('val')) margenEnvios = parseFloat($('#margenEnvios').attr('val'))
} }
var totalCostes = totalPapel + totalImpresion + totalServicios + totalEnvios var totalCostes = parseFloat(totalPapel.toFixed(2)) + parseFloat(totalImpresion.toFixed(2)) + parseFloat(totalServicios.toFixed(2)) + parseFloat(totalEnvios.toFixed(2))
var totalMargenes = margenPapel + margenImpresion + margenServicios + margenEnvios var totalMargenes = parseFloat(margenPapel.toFixed(2)) + parseFloat(margenImpresion.toFixed(2)) + parseFloat(margenServicios.toFixed(2)) + parseFloat(margenEnvios.toFixed(2))
$('#totalCostes').text((addSeparatorsNF(totalCostes.toFixed(2), ".", ",", ".")) + "€") $('#totalCostes').text((addSeparatorsNF(totalCostes.toFixed(2), ".", ",", ".")) + "€")
$('#totalMargenes').text((addSeparatorsNF(totalMargenes.toFixed(2), ".", ",", ".")) + "€") $('#totalMargenes').text((addSeparatorsNF(totalMargenes.toFixed(2), ".", ",", ".")) + "€")
$('#totalCostes').attr('val',(totalCostes).toFixed(2) + '€') $('#totalCostes').attr('val',(totalCostes).toFixed(2) + '€')
@ -251,11 +251,13 @@ function getValuesResumenForm(){
formResumen += '&total_presupuesto=' + $('#totalDespuesDecuento').attr('val'); formResumen += '&total_presupuesto=' + $('#totalDespuesDecuento').attr('val');
formResumen += '&total_precio_unidad=' + $('#precioUnidadPresupuesto').attr('val'); formResumen += '&total_precio_unidad=' + $('#precioUnidadPresupuesto').attr('val');
formResumen += '&total_factor=' + $('#total_factor').text(); // replace , for . in the values
formResumen += '&total_factor_ponderado=' + $('#total_factor_ponderado').text(); formResumen += '&total_factor=' + $('#factor').text().replace(/,/g, '.');
formResumen += '&total_factor_ponderado=' + $('#factor_ponderado').text().replace(/,/g, '.');
if($('#confirmar_presupuesto').prop('checked')){ if($('#confirmar_presupuesto').prop('checked')){
formResumen += '&confirmar=1'; formResumen += '&confirmar=1';
formResumen += '&total_aceptado=' + $('#totalDespuesDecuento').attr('val');
} }
return formResumen return formResumen

View File

@ -1,444 +0,0 @@
<!--Style-->
<link href="<?= site_url("themes/focus2/vendor/bootstrap-material-datetimepicker/css/bootstrap-material-datetimepicker.css") ?>"
rel="stylesheet">
<style>
.input_hidden {
border: 0;
clip: rect(0 0 0 0);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
width: 1px;
}
</style>
<!--Content Body-->
<div class="content-body">
<div class="container-fluid">
<div class="row page-titles mx-0">
<div class="col-sm-6 p-md-0">
<div class="welcome-text">
<h4><i class="<?= $title['icon'] ?? '' ?>"></i> <?= $title['module'] ?? '' ?></h4>
<span class="ml-1"><?= $title['page'] ?? '' ?></span>
</div>
</div>
<div class="col-sm-6 p-md-0 justify-content-sm-end mt-2 mt-sm-0 d-flex">
<ol class="breadcrumb">
<?php foreach ($breadcrumb ?? [] as $item) : ?>
<?php if (!$item['active']) : ?>
<li class="breadcrumb-item"><a
href="<?= site_url($item['route']) ?>"><?= $item['title'] ?></a></li>
<?php else : ?>
<li class="breadcrumb-item active"><?= $item['title'] ?></li>
<?php endif; ?>
<?php endforeach; ?>
</ol>
</div>
</div>
<div class="row">
<div class="col-lg-8">
<div class="card">
<div class="card-header">
<h4 class="card-title"><?= $title['page'] ?? '' ?></h4>
</div>
<div class="card-body">
<?= formAlert() ?>
<form class="form" action="<?= site_url("profile/store") ?>" method="post">
<?= csrf_field() ?>
<div class="form-body">
<div class="row">
<div class="col-lg-12">
<label class="text-primary"><?= lang("App.profile_msg_desc_1") ?></label>
</div>
<div class="col-lg-6">
<div class="form-group">
<label class="text-dark"><?= lang("App.profile_first_name") ?></label>
<input type="text" id="first_name" name="first_name" class="form-control"
placeholder="<?= lang("App.profile_first_name_ph") ?>"
value="<?= (isset($obj)) ? $obj->first_name : set_value('first_name'); ?>">
</div>
</div>
<div class="col-lg-6">
<div class="form-group">
<label class="text-dark"><?= lang("App.profile_last_name") ?></label>
<input type="text" id="last_name" name="last_name" class="form-control"
placeholder="<?= lang("App.profile_last_name_ph") ?>"
value="<?= (isset($obj)) ? $obj->last_name : set_value('last_name'); ?>">
</div>
</div>
<div class="col-lg-4">
<div class="form-group">
<label class="text-dark"><?= lang("App.profile_date_birth") ?></label>
<input type="text" class="form-control"
placeholder="<?= lang("App.profile_date_birth_ph") ?>"
id="date_birth" name="date_birth"
value="<?= (isset($obj)) ? $obj->date_birth : set_value('date_birth'); ?>">
</div>
</div>
<div class="col-lg-8">
<div class="form-group">
<label class="text-dark"><?= lang("App.profile_email") ?></label>
<input type="text" id="email" name="email" class="form-control"
placeholder="<?= lang("App.profile_email_ph") ?>"
value="<?= (isset($obj)) ? $obj->email : set_value('email'); ?>"
disabled>
</div>
</div>
<div class="col-lg-4">
<div class="form-group">
<label for="mobile"
class="text-dark"><?= lang("App.profile_mobile") ?></label>
<input type="text" id="mobile" name="mobile" class="form-control"
placeholder="<?= lang("App.profile_mobile_ph") ?>"
value="<?= (isset($obj)) ? $obj->mobile : set_value('mobile'); ?>">
</div>
</div>
<div class="col-lg-4">
<div class="form-group">
<label for="password"
class="text-dark"><?= lang("App.profile_password") ?></label>
<input type="password" id="password" name="password" class="form-control"
placeholder="<?= lang("App.profile_password_ph") ?>">
</div>
</div>
<div class="col-lg-4">
<div class="form-group">
<label for="confirm_password"
class="text-dark"><?= lang("App.profile_confirm_password") ?></label>
<input type="password" id="confirm_password" name="confirm_password"
class="form-control"
placeholder="<?= lang("App.profile_confirm_password_ph") ?>">
</div>
</div>
</div>
<div class="row">
<div class="col-lg-12">
<label class="text-primary"><?= lang("App.profile_msg_desc_2") ?></label>
</div>
<div class="col-lg-8">
<div class="form-group">
<label class="text-dark"><?= lang("App.profile_address") ?></label>
<input type="text" id="address" name="address" class="form-control"
placeholder="<?= lang("App.profile_address_ph") ?>"
value="<?= (isset($obj)) ? $obj->address : set_value('address'); ?>">
</div>
</div>
<div class="col-lg-4">
<div class="form-group">
<label for="city" class="text-dark"><?= lang("App.profile_city") ?></label>
<input type="text" id="city" name="city" class="form-control"
placeholder="<?= lang("App.profile_city_ph") ?>"
value="<?= (isset($obj)) ? $obj->city : set_value('city'); ?>">
</div>
</div>
<div class="col-lg-4">
<div class="form-group">
<label for="state"
class="text-dark"><?= lang("App.profile_state") ?></label>
<input type="text" id="state" name="state" class="form-control"
placeholder="<?= lang("App.profile_state_ph") ?>"
value="<?= (isset($obj)) ? $obj->state : set_value('state'); ?>">
</div>
</div>
<div class="col-lg-4">
<div class="form-group">
<label for="country"
class="text-dark"><?= lang("App.profile_country") ?></label>
<?php $id_select = (isset($obj)) ? $obj->country ?? [] : set_value('country'); ?>
<select name="country" id="country" class="form-control">
<option value=""><?= lang("App.global_select") ?></option>
<?php foreach ($country ?? [] as $item) : ?>
<option value="<?= $item['code'] ?? '' ?>" <?= $id_select == $item['code'] ? 'selected' : '' ?>><?= $item['name'] ?? '' ?></option>
<?php endforeach; ?>
</select>
</div>
</div>
<div class="col-lg-4">
<div class="form-group">
<label for="language"
class="text-dark"><?= lang("App.profile_language") ?></label>
<?php $id_select = (isset($obj)) ? $obj->language ?? [] : set_value('language'); ?>
<select name="language" id="language" class="form-control">
<option value=""><?= lang("App.global_select") ?></option>
<option value="en" <?= $id_select == "en" ? 'selected' : '' ?>><?= lang("App.lang_en") ?></option>
<option value="es" <?= $id_select == "es" ? 'selected' : '' ?>><?= lang("App.lang_es") ?></option>
<option value="pt" <?= $id_select == "pt" ? 'selected' : '' ?>><?= lang("App.lang_pt") ?></option>
</select>
</div>
</div>
</div>
</div>
<div class="form-actions">
<a href="<?= site_url($btn_return['route'] ?? '#') ?>"
class="<?= $btn_return['class'] ?? '' ?>">
<i class="<?= $btn_return['icon'] ?? '' ?>"></i> <?= $btn_return['title'] ?? '' ?>
</a>
<button type="submit" class="<?= $btn_submit['class'] ?? '' ?>">
<i class="<?= $btn_submit['icon'] ?? '' ?>"></i> <?= $btn_submit['title'] ?? '' ?>
</button>
</div>
</form>
</div>
</div>
</div>
<div class="col-lg-4">
<div class="card">
<div class="card-header">
<h4 class="card-title"><?= lang("App.profile_subtitle_image") ?></h4>
</div>
<div class="card-body">
<div class="row">
<div class="col-lg-12 justify-content-center d-flex">
<img src="<?= $obj->picture ?? '' ?>" class="btn-circle btn-circle-md">
</div>
<div class="col-lg-12 text-center mt-3">
<span><b><?= $obj->first_name ?? '' ?></b></span><br>
<span><?= $obj->email ?? '' ?></span>
</div>
<div class="col-lg-12 mt-3">
<button type="button" class="btn btn-primary btn-block" data-toggle="modal"
data-target="#photoModalCenter"><i
class="fas fa-camera"></i> <?= lang("App.profile_change_photo") ?></button>
</div>
<!-- Modal -->
<div class="modal fade" id="photoModalCenter">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-body">
<div class="row">
<div class="col-lg-12 mb-2">
<h5><?= lang("App.profile_change_image") ?></h5>
</div>
<div class="col-lg-3 mt-2">
<div class="row">
<div class="col-lg-12 justify-content-center d-flex">
<form name="form_upload" class="form"
action="<?= site_url("profile") ?>"
enctype="multipart/form-data" method="post">
<?= csrf_field() ?>
<input type="file" name="file" id="file"
class="input_hidden"
onchange="form_upload.submit()" accept="image/*">
<div class="btn btn-light btn-circle btn-circle-md"><a
href="#" class="file-upload"><i
class="fas fa-cloud-upload-alt fa-2xl"></i></a>
</div>
</form>
</div>
<div class="col-lg-12 text-center mt-1">
<b><i class="fas fa-upload"></i> <?= strtoupper(lang("App.profile_upload_msg")) ?>
</b>
</div>
</div>
</div>
<div class="col-lg-3 mt-2">
<div class="row">
<div class="col-lg-12 justify-content-center d-flex">
<form name="form_not" action="<?= site_url("profile") ?>"
method="post">
<?= csrf_field() ?>
<input type="hidden" id="image_not" name="image_not"
value="<?= site_url("assets/img/default-user.png") ?>">
<a href="javascript:form_not.submit()"><img
src="<?= site_url("assets/img/default-user.png") ?>"
class="btn-circle btn-circle-md"></a>
</form>
</div>
<div class="col-lg-12 text-center mt-1">
<b><i class="fas fa-user-slash"></i> <?= strtoupper(lang("App.profile_no_image_msg")) ?>
</b>
</div>
</div>
</div>
<div class="col-lg-3 mt-2">
<div class="row">
<div class="col-lg-12 justify-content-center d-flex">
<form name="form_gravatar"
action="<?= site_url("profile") ?>" method="post">
<?= csrf_field() ?>
<input type="hidden" id="image_gravatar"
name="image_gravatar"
value="https://s.gravatar.com/avatar/<?= MD5($obj->email ?? '') ?>?s=150">
<a href="javascript:form_gravatar.submit()"><img
src="https://s.gravatar.com/avatar/<?= MD5($obj->email ?? '') ?>?s=150"
class="btn-circle btn-circle-md"></a>
</form>
</div>
<div class="col-lg-12 text-center mt-1">
<b><i class="fas fa-user-circle"></i> <?= strtoupper(lang("App.profile_gravatar_msg")) ?>
</b>
</div>
</div>
</div>
<?php foreach ($oauth ?? [] as $item) : ?>
<?php
$icon = '';
switch ($item['provider']) {
case "vkontakte":
$icon = '<i class="fab fa-vk"></i> ';
break;
case "wechat":
$icon = '<i class="fab fa-weixin"></i> ';
break;
default:
$icon = '<i class="fab fa-' . $item['provider'] . '"></i> ';
break;
}
?>
<div class="col-lg-3 mt-2">
<div class="row">
<div class="col-lg-12 justify-content-center d-flex">
<form name="form_<?= $item['provider'] ?? '' ?>"
action="<?= site_url("profile") ?>" method="post">
<?= csrf_field() ?>
<input type="hidden"
id="image_<?= $item['provider'] ?? '' ?>"
name="image_<?= $item['provider'] ?? '' ?>"
value="<?= $item['picture'] ?? '' ?>">
<a href="javascript:form_<?= $item['provider'] ?? '' ?>.submit()"><img
src="<?= $item['picture'] ?? '' ?>"
class="btn-circle btn-circle-md"></a>
</form>
</div>
<div class="col-lg-12 text-center mt-1">
<b><?= $icon ?><?= strtoupper($item['provider'] ?? '') ?></b>
</div>
</div>
</div>
<?php endforeach; ?>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<?php $settings = session()->get('settings'); ?>
<?php if ($settings['two_factor_auth']) : ?>
<form name="form_otp" class="form" action="<?= site_url("profile/store") ?>" method="post" id="sendFormTFA">
<?= csrf_field() ?>
<div class="row">
<div class="col-lg-8">
<div class="card">
<div class="card-header">
<div class="row mx-0" style="width: 100%;">
<div class="col-sm-6 p-md-0">
<h4 class="card-title"><?= lang("App.profile_subtitle_tfa") ?></h4>
</div>
<div class="col-sm-6 p-md-0 justify-content-sm-end mt-2 mt-sm-0 d-flex">
<div class="custom-control custom-switch ml-2">
<input type="checkbox" id="tfa" name="tfa" class="custom-control-input"
onchange="tfaView()" <?= $obj['tfa'] ?? false ? 'checked' : '' ?>>
<label for="tfa"
class="custom-control-label"><?= lang("App.profile_tfa_msg") ?></label>
</div>
</div>
</div>
</div>
<div class="card-body">
<div id="otp" style="display: <?= $obj['tfa'] ?? false ? 'block' : 'none' ?>">
<?php
$tfa = new \App\Libraries\Authenticator();
$name = $obj['first_name'] ?? '';
if ($obj['tfa'] && !empty($obj['tfa_secret'])) {
$tfa_secret = $obj['tfa_secret'] ?? '';
$qrcode = $tfa->GetQR("{$settings['title']} ({$name})", $tfa_secret);
} else {
$tfa_secret = $tfa->createSecret();
$qrcode = $tfa->GetQR("{$settings['title']} ({$name})", $tfa_secret);
}
?>
<div class="row">
<div class="col-lg-6">
<p><b><?= lang("App.profile_qrcode") ?></b></p>
<img src="<?php echo $qrcode; ?>" class="img-responsive">
</div>
<div class="col-lg-6">
<p><b><?= lang("App.profile_backup_code") ?></b></p>
<?php
$codes = "";
if (!empty($obj['tfa_code'] ?? '')) {
$codes = explode(',', $obj['tfa_code'] ?? '');
foreach ($codes as $item) {
echo '<span class="badge badge-primary mr-2 mb-1">' . $item . '</span>';
}
} else {
$codes = array();
for ($i = 1; $i <= 8; $i++) {
$code = random_string('numeric', 6);
$codes[] = $code;
echo '<span class="badge badge-primary mr-2 mb-1">' . $code . '</span>';
}
}
?>
<p class="mt-2"><b><?= lang("App.profile_tfa_secret") ?></b><br><b
class="text-primary"><?= $tfa_secret ?></b></p>
<input type="hidden" id="tfa_secret" name="tfa_secret"
value="<?= $tfa_secret ?>">
<input type="hidden" id="tfa_code" name="tfa_code"
value="<?= implode(',', $codes) ?>">
<button type="button" class="btn btn-primary btn-block mt-2"
onclick="download('<?= lang("App.profile_qrcode") ?>\n<?= implode(",", $codes) ?>\n<?= lang("App.profile_tfa_secret") ?>\n<?= $tfa_secret ?>','backup_codes.txt')">
<i class="fas fa-download mr-1"></i> <?= lang("App.profile_tfa_download") ?>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</form>
<?php endif; ?>
</div>
</div>
<!-- Required vendors -->
<script src="<?= site_url("themes/focus2/vendor/global/global.min.js") ?>">></script>
<script src="<?= site_url("themes/focus2/js/quixnav-init.js") ?>">></script>
<script src="<?= site_url("themes/focus2/js/custom.min.js") ?>">></script>
<script src="<?= site_url("themes/focus2/vendor/select2/js/select2.full.min.js") ?>">></script>
<!-- Alert -->
<script src="<?= site_url("themes/focus2/vendor/sweetalert2/dist/sweetalert2.min.js") ?>">></script>
<script src="<?= site_url("themes/focus2/vendor/toastr/js/toastr.min.js") ?>">></script>
<!-- Date Range Picker -->
<!-- momment js is must -->
<script src="<?= site_url("themes/focus2/vendor/moment/moment.min.js") ?>">></script>
<script src="<?= site_url("themes/focus2/vendor/bootstrap-daterangepicker/daterangepicker.js") ?>">></script>
<!-- Material color picker -->
<script src="<?= site_url("themes/focus2/vendor/bootstrap-material-datetimepicker/js/bootstrap-material-datetimepicker.js") ?>">></script>
<!-- Form -->
<script>
"use strict";
$(document).ready(function () {
$('#first_name').focus();
$("#country").select2();
$("#language").select2();
$('#date_birth').bootstrapMaterialDatePicker({
format: '<?=momentDateJS()?>',
time: false
});
});
$('.file-upload').on('click', function (e) {
e.preventDefault();
$('#file').trigger('click');
});
function download(text, filename) {
let blob = new Blob([text], {type: "text/plain;charset=utf-8"});
let url = window.URL.createObjectURL(blob);
let a = document.createElement("a");
a.href = url;
a.download = filename;
a.click();
}
function tfaView() {
document.getElementById("sendFormTFA").submit();
}
</script>
<?= sweetAlert() ?>

View File

@ -1,5 +1,4 @@
<?= $this->include("themes/_commonPartialsBs/select2bs5") ?> <?= $this->extend('themes/vuexy/main/defaultlayout') ?>
<?= $this->extend('themes/vuexy/main/general_settings_layout') ?>
<?= $this->section('content'); ?> <?= $this->section('content'); ?>
<!--Content Body--> <!--Content Body-->
@ -12,10 +11,11 @@
<form id="formAccountSettings" method="POST" action="<?= site_url("profile/store") ?>"> <form id="formAccountSettings" method="POST" action="<?= site_url("profile/store") ?>">
<?= csrf_field() ?> <?= csrf_field() ?>
<div class="row"> <div class="row">
<div class="mb-3 col-md-6"> <div class="mb-3 col-md-4">
<label for="first_name" class="form-label"><?= lang("App.profile_first_name") ?></label> <label for="first_name" class="form-label"><?= lang("App.profile_first_name") ?> *</label>
<input <input
class="form-control" class="form-control"
tabindex="1"
type="text" type="text"
id="first_name" id="first_name"
name="first_name" name="first_name"
@ -24,9 +24,10 @@
autofocus autofocus
/> />
</div> </div>
<div class="mb-3 col-md-6"> <div class="mb-3 col-md-4">
<label for="last_name" class="form-label"><?= lang("App.profile_last_name") ?></label> <label for="last_name" class="form-label"><?= lang("App.profile_last_name") ?> *</label>
<input class="form-control" <input class="form-control"
tabindex="2"
type="text" type="text"
name="last_name" name="last_name"
id="last_name" id="last_name"
@ -34,54 +35,52 @@
value="<?= (isset($obj)) ? $obj->last_name : set_value('last_name'); ?>" value="<?= (isset($obj)) ? $obj->last_name : set_value('last_name'); ?>"
/> />
</div> </div>
<div class="mb-3 col-md-6"> <div class="mb-3 col-md-4">
<label for="email" class="form-label"><?= lang("App.profile_email") ?></label> <label for="email" class="form-label"><?= lang("App.profile_email") ?></label>
<input <input
class="form-control" class="form-control"
tabindex="3"
type="text" type="text"
id="email" id="email"
name="email" name="email"
disabled
placeholder="<?= lang("App.profile_email_ph") ?>" placeholder="<?= lang("App.profile_email_ph") ?>"
value="<?= (isset($obj)) ? $obj->email : set_value('email'); ?>" value="<?= (isset($obj)) ? $obj->email : set_value('email'); ?>"
/> />
</div> </div>
<div class="mb-3 col-md-6">
<label for="new_pwd" class="form-label"><?= lang("App.profile_password") ?></label>
<input
class="form-control"
tabindex="4"
type="text"
id="new_pwd"
name="new_pwd"
placeholder="<?= lang("App.profile_password_ph") ?>"
value=""
/>
</div>
<div class="mb-3 col-md-6">
<label for="new_pwd_confirm" class="form-label"><?= lang("App.profile_confirm_password") ?></label>
<input
class="form-control"
tabindex="5"
type="text"
id="new_pwd_confirm"
name="new_pwd_confirm"
placeholder="<?= lang("App.profile_confirm_password_ph") ?>"
value=""
/>
</div>
</div> </div>
<div class="mt-2"> <div class="mt-2">
<button type="submit" class="btn btn-primary me-2"><?= $btn_submit['title'] ?? '' ?></button> <button type="submit" class="btn btn-primary me-2"><?= lang("Basic.global.Save") ?? '' ?></button>
<button type="reset" class="btn btn-label-secondary"><?= $btn_return['title'] ?? '' ?></button> <?= anchor(route_to("home"), lang("Basic.global.Cancel"), ["class" => "btn btn-dark"]) ?>
</div> </div>
</form> </form>
</div> </div>
<!-- /Account --> <!-- /Account -->
</div> </div>
<!-- <div class="card">
<h5 class="card-header">Delete Account</h5>
<div class="card-body">
<div class="mb-3 col-12 mb-0">
<div class="alert alert-warning">
<h5 class="alert-heading mb-1">Are you sure you want to delete your account?</h5>
<p class="mb-0">Once you delete your account, there is no going back. Please be certain.</p>
</div>
</div>
<form id="formAccountDeactivation" onsubmit="return false">
<div class="form-check mb-4">
<input
class="form-check-input"
type="checkbox"
name="accountActivation"
id="accountActivation"
/>
<label class="form-check-label" for="accountActivation"
>I confirm my account deactivation</label
>
</div>
<button type="submit" class="btn btn-danger deactivate-account">Deactivate Account</button>
</form>
</div>
</div> -->
</div> </div>
<?php $settings = session()->get('settings'); ?> <?php $settings = session()->get('settings'); ?>
@ -96,12 +95,7 @@
<?= $this->section('additionalInlineJs') ?> <?= $this->section('additionalInlineJs') ?>
"use strict"; "use strict";
$(document).ready(function () { $(document).ready(function () {
$('#first_name').focus(); $('#first_name').focus();
}); });
$('.file-upload').on('click', function (e) {
e.preventDefault();
$('#file').trigger('click');
});
<?= $this->endSection() ?> <?= $this->endSection() ?>

View File

@ -1,26 +1,41 @@
<div class="row"> <div class="col-md-12 col-lg-12 px-4">
<div class="col-md-12 col-lg-6 px-4"> <div class="row">
<div class="col-md-6 col-lg-4">
<div class="mb-3">
<label for="firstName" class="form-label">
<?= lang('Users.firstName') ?> *
</label>
<input tabindex="1" type="text" id="firstName" name="first_name" maxLength="150" class="form-control"
value="<?= old('first_name', $user->first_name) ?>">
</div>
</div>
<div class="mb-3"> <div class="col-md-6 col-lg-4">
<label for="firstName" class="form-label"> <div class="mb-3">
<?= lang('Users.firstName') ?> <label for="lastName" class="form-label">
</label> <?= lang('Users.lastName') ?> *
<input tabindex="1" type="text" id="firstName" name="first_name" maxLength="150" class="form-control" </label>
value="<?= old('first_name', $user->first_name) ?>"> <input tabindex="2" type="text" id="lastName" name="last_name" maxLength="150" class="form-control"
</div><!--//.mb-3 --> value="<?= old('last_name', $user->last_name) ?>">
</div>
</div>
<div class="mb-3"> <div class="col-md-6 col-lg-4">
<label for="email" class="form-label"> <div class="mb-3">
<?= lang('Users.email') ?>* <label for="email" class="form-label">
</label> <?= lang('Users.email') ?>*
<input tabindex="13" type="email" id="email" name="email" maxLength="150" class="form-control" </label>
value="<?= old('email', $user->email) ?>"> <input tabindex="3" type="email" id="email" name="email" maxLength="150" class="form-control"
</div><!--//.mb-3 --> value="<?= old('email', $user->email) ?>">
</div>
</div>
</div>
<div class="row">
<div class="mb-3"> <div class="mb-3">
<div class="form-group"> <div class="form-group">
<label for="group" class="form-label"> <?= lang('Users.group') ?></label> <label for="group" class="form-label"> <?= lang('Users.group') ?></label>
<select tabindex="17" name="group[]" id="group" multiple="multiple" <select tabindex="5" name="group[]" id="group" multiple="multiple"
class="form-control select2 form-select"> class="form-control select2 form-select">
<option value=""><?= lang('Basic.global.pleaseSelectA', [lang('Users.group')]) ?></option> <option value=""><?= lang('Basic.global.pleaseSelectA', [lang('Users.group')]) ?></option>
<?php <?php
@ -36,59 +51,106 @@
<?php endforeach; ?> <?php endforeach; ?>
</select> </select>
</div> </div>
</div><!--//.mb-3 -->
</div><!--//.col -->
<div class="col-md-12 col-lg-6 px-4">
<div class="mb-3">
<label for="lastName" class="form-label">
<?= lang('Users.lastName') ?>
</label>
<input tabindex="2" type="text" id="lastName" name="last_name" maxLength="150" class="form-control"
value="<?= old('last_name', $user->last_name) ?>">
</div><!--//.mb-3 -->
<div class="mb-3">
<label for="status" class="form-label">
<?= lang('Users.blocked') ?>
</label>
<?php $isBanned = old('blocked', $user->status); ?>
<select tabindex="12" name="status" id="status" class="select2 form-control">
<option value="0" <?= is_null($isBanned) ? 'selected' : '' ?>><?= lang("Users.non_blocked") ?></option>
<option value="1" <?= $isBanned === "banned" ? 'selected' : '' ?>><?= lang("Users.blocked") ?></option>
</select>
</div> </div>
<div class="mb-3">
<label for="active" class="form-label">
<?= lang('Users.status') ?>
</label>
<?php $isActive = old('status', $user->active); ?>
<select tabindex="16" name="active" id="active" class="select2 form-control">
<option value="1" <?= $isActive ? 'selected' : '' ?>><?= lang("Users.global_active") ?></option>
<option value="0" <?= $isActive ? '' : 'selected' ?>><?= lang("Users.global_inactive") ?></option>
</select>
</div><!--//.mb-3 -->
</div><!--//.col -->
<div class="col-md-12 col-lg-6 px-4">
<div class="mb-3"> <div class="mb-3">
<label for="cliente_id" class="form-label"> <label for="cliente_id" class="form-label">
<?= lang('Presupuestos.clienteId') ?> <?= lang('Presupuestos.clienteId') ?>
</label> </label>
<select id="cliente_id" name="cliente_id" class="form-control select2bs2" style="width: 100%;"> <select tabindex="7" id="cliente_id" name="cliente_id" class="form-control select2bs2" style="width: 100%;">
<?php if (isset($clienteList) && is_array($clienteList) && !empty($clienteList)) : <?php if (isset($clienteList) && is_array($clienteList) && !empty($clienteList)) :
foreach ($clienteList as $k => $v) : ?> foreach ($clienteList as $k => $v) : ?>
<option value="<?= $k ?>" <?= $k == $user->cliente_id ? ' selected' : '' ?>> <option value="<?= $k ?>" <?= $k == $user->cliente_id ? ' selected' : '' ?>>
<?= $v ?> <?= $v ?>
</option> </option>
<?php endforeach; <?php endforeach;
endif; ?> endif; ?>
</select> </select>
</div> </div>
</div><!--//.col --> </div>
<div class="row">
<div class="col-md-6 col-lg-6">
<div class="mb-3">
<label for="status" class="form-label">
<?= lang('Users.blocked') ?>
</label>
<?php $isBanned = old('blocked', $user->status); ?>
<select tabindex="4" name="status" id="status" class="select2 form-control">
<option value="0" <?= is_null($isBanned) ? 'selected' : '' ?>><?= lang("Users.non_blocked") ?></option>
<option value="1" <?= $isBanned === "banned" ? 'selected' : '' ?>><?= lang("Users.blocked") ?></option>
</select>
</div>
</div>
<div class="col-md-6 col-lg-6">
<div class="mb-3">
<label for="active" class="form-label">
<?= lang('Users.status') ?>
</label>
<?php $isActive = old('status', $user->active); ?>
<select tabindex="6" name="active" id="active" class="select2 form-control">
<option value="1" <?= $isActive ? 'selected' : '' ?>><?= lang("Users.global_active") ?></option>
<option value="0" <?= $isActive ? '' : 'selected' ?>><?= lang("Users.global_inactive") ?></option>
</select>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6 col-lg-6">
<div class="mb-3">
<label for="new_pwd" class="form-label">
<?= lang('Users.password') ?>
</label>
<input
tabindex="8"
type="text"
id="new_pwd"
name="new_pwd"
maxLength="50"
class="form-control"
placeholder="Introduzca contraseña para cambiarla"
value=""
>
</div>
</div>
<div class="col-md-6 col-lg-6">
<div class="mb-3">
<label for="new_pwd_confirm" class="form-label">
Repita <?= lang('Users.password') ?>
</label>
<input
tabindex="9"
type="text"
id="new_pwd_confirm"
name="new_pwd_confirm"
maxLength="50"
class="form-control"
placeholder="Repita la contraseña para cambiarla"
value=""
>
</div>
</div>
</div>
<div class="row">
<div class="mb-3">
<label for="comments" class="form-label">
Comentarios
</label>
<textarea
rows="3"
id="comments"
name="comments"
style="height: 10em;"
class="form-control"
><?=old('comments', $user->comments) ?></textarea>
</div>
</div>
</div><!--//.col -->
</div><!-- //.row -->

View File

@ -17,8 +17,8 @@
<tr> <tr>
<th><?= lang('Users.firstName') ?></th> <th><?= lang('Users.firstName') ?></th>
<th><?= lang('Users.lastName') ?></th> <th><?= lang('Users.lastName') ?></th>
<th><?= lang('Users.group') ?></th> <th><?= lang('Users.email') ?></th>
<th><?= lang('Users.lastAccess') ?></th> <th><?= lang('Users.lastAccess') ?></th>
<?php /* <?php /*
<th><?= lang('Users.mobile') ?></th> <th><?= lang('Users.mobile') ?></th>
<th><?= lang('Users.email') ?></th> <th><?= lang('Users.email') ?></th>
@ -46,11 +46,10 @@
<td class="align-middle"> <td class="align-middle">
<?= empty($item->last_name) || strlen($item->last_name) < 51 ? esc($item->last_name) : character_limiter(esc($item->last_name), 50) ?> <?= empty($item->last_name) || strlen($item->last_name) < 51 ? esc($item->last_name) : character_limiter(esc($item->last_name), 50) ?>
</td> </td>
<td class="align-middle"> <td class="align-middle">
<?= empty($item->group) ? "" : character_limiter(esc(lang('Users.' . $item->group)), 50) ?> <?= empty($item->email) ? "" : character_limiter(esc(lang($item->email)), 50) ?>
</td> </td>
<td class="align-middle text-nowrap">
<td class="align-middle text-nowrap">
<?= empty($item->last_active) ? '' : date('d/m/Y H:m:s', strtotime($item->last_active)) ?> <?= empty($item->last_active) ? '' : date('d/m/Y H:m:s', strtotime($item->last_active)) ?>
</td> </td>

View File

@ -1,357 +0,0 @@
<?php
$session = session();
$token = $session->get('token') ?? '';
$tfa = $session->get('tfa') ?? false;
$settings = $session->get('settings');
$picture = "/assets/img/default-user.png";
$pulse = session()->get('pulse');
$notification = session()->get('notification');
if (!empty($token) && $tfa == false) {
//echo "<script>window.location.href = '/'; </script>";
}
?>
<!DOCTYPE html>
<html
lang="<?= $session->get('lang') ?>"
class="h-100 light-style layout-navbar-fixed layout-menu-fixed"
dir="ltr"
data-theme="theme-default"
data-assets-path="<?= site_url('themes/vuexy/') ?>"
data-template="vertical-menu-template-no-customizer"
>
<head>
<meta charset="utf-8">
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"
/>
<title><?= config('Safekat')->appName ?></title>
<meta name="description" content=""/>
<!-- Favicon -->
<link rel="icon" type="image/x-icon" href="<?= site_url('themes/vuexy/img/favicon/favicon.ico') ?>"/>
<link rel="apple-touch-icon" sizes="57x57" href="<?= site_url('themes/vuexy/img/favicon/apple-icon-57x57.png') ?>">
<link rel="apple-touch-icon" sizes="60x60" href="<?= site_url('themes/vuexy/img/favicon/apple-icon-60x60.png') ?>">
<link rel="apple-touch-icon" sizes="72x72" href="<?= site_url('themes/vuexy/img/favicon/apple-icon-72x72.png') ?>">
<link rel="apple-touch-icon" sizes="76x76" href="<?= site_url('themes/vuexy/img/favicon/apple-icon-76x76.png') ?>">
<link rel="apple-touch-icon" sizes="114x114"
href="<?= site_url('themes/vuexy/img/favicon/apple-icon-114x114.png') ?>">
<link rel="apple-touch-icon" sizes="120x120"
href="<?= site_url('themes/vuexy/img/favicon/apple-icon-120x120.png') ?>">
<link rel="apple-touch-icon" sizes="144x144"
href="<?= site_url('themes/vuexy/img/favicon/apple-icon-144x144.png') ?>">
<link rel="apple-touch-icon" sizes="152x152"
href="<?= site_url('themes/vuexy/img/favicon/apple-icon-152x152.png') ?>">
<link rel="apple-touch-icon" sizes="180x180"
href="<?= site_url('themes/vuexy/img/favicon/apple-icon-180x180.png') ?>">
<link rel="icon" type="image/png" sizes="192x192"
href="<?= site_url('themes/vuexy/img/favicon/android-icon-192x192.png') ?>">
<link rel="icon" type="image/png" sizes="32x32"
href="<?= site_url('themes/vuexy/img/favicon/favicon-32x32.png') ?>">
<link rel="icon" type="image/png" sizes="96x96"
href="<?= site_url('themes/vuexy/img/favicon/favicon-96x96.png') ?>">
<link rel="icon" type="image/png" sizes="16x16"
href="<?= site_url('themes/vuexy/img/favicon/favicon-16x16.png') ?>">
<link rel="manifest" href="<?= site_url('themes/vuexy/img/favicon/manifest.json') ?>">
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com"/>
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin/>
<link
href="https://fonts.googleapis.com/css2?family=Public+Sans:ital,wght@0,300;0,400;0,500;0,600;0,700;1,300;1,400;1,500;1,600;1,700&display=swap"
rel="stylesheet"
/>
<!-- Icons -->
<link rel="stylesheet" href="<?= site_url('themes/vuexy/vendor/fonts/fontawesome.css') ?>"/>
<link rel="stylesheet" href="<?= site_url('themes/vuexy/vendor/fonts/tabler-icons.css') ?>"/>
<link rel="stylesheet" href="<?= site_url('themes/vuexy/vendor/fonts/flag-icons.css') ?>"/>
<!-- Core CSS -->
<link rel="stylesheet" href="<?= site_url('themes/vuexy/vendor/css/rtl/core.css') ?>"/>
<link rel="stylesheet" href="<?= site_url('themes/vuexy/vendor/css/rtl/theme-semi-dark.css') ?>"/>
<link rel="stylesheet" href="<?= site_url('themes/vuexy/css/safekat.css') ?>"/>
<!-- Vendors CSS -->
<link rel="stylesheet" href="<?= site_url('themes/vuexy/vendor/libs/perfect-scrollbar/perfect-scrollbar.css') ?>"/>
<!-- Page CSS -->
<?= $this->renderSection('css') ?>
<!-- Helpers -->
<script src="<?= site_url('themes/vuexy/vendor/js/helpers.js') ?>"></script>
<script src="<?= site_url('themes/vuexy/js/config.js') ?>"></script>
</head>
<body>
<!-- Layout wrapper -->
<div class="layout-wrapper layout-content-navbar">
<div class="layout-container">
<?php include "selector_menu.php" ?>
<!-- Layout container -->
<div class="layout-page">
<!-- Navbar -->
<nav
class="layout-navbar container-xxl navbar navbar-expand-xl navbar-detached align-items-center bg-navbar-theme"
id="layout-navbar"
>
<div class="layout-menu-toggle navbar-nav align-items-xl-center me-3 me-xl-0 d-xl-none">
<a class="nav-item nav-link px-0 me-xl-4" href="javascript:void(0)">
<i class="ti ti-menu-2 ti-sm"></i>
</a>
</div>
<div class="navbar-nav-right d-flex align-items-center" id="navbar-collapse">
<div class="navbar-nav align-items-center">
<a class="nav-link style-switcher-toggle hide-arrow" href="javascript:void(0);">
<i class="ti ti-sm"></i>
</a>
</div>
<ul class="navbar-nav flex-row align-items-center ms-auto">
<!-- Notification -->
<li class="nav-item dropdown-notifications navbar-dropdown dropdown me-3 me-xl-1">
<a
class="nav-link dropdown-toggle hide-arrow"
href="javascript:void(0);"
data-bs-toggle="dropdown"
data-bs-auto-close="outside"
aria-expanded="false"
>
<i class="ti ti-bell ti-md"></i>
<span class="badge bg-danger rounded-pill badge-notifications">5</span>
</a>
</li>
<!--/ Notification -->
<!-- Search Budgets -->
<li class="nav-item navbar-dropdown dropdown me-3 me-xl-1">
<a
class="nav-link hide-arrow"
href="<?= site_url('presupuestos/buscador'); ?>"
title="Acceso directo a buscador de presupuestos"
>
<i class="ti ti-report-search ti-md"></i>
</a>
</li>
<!--/ Search Budgets -->
<!-- View Mode links -->
<li class="nav-item dropdown-shortcuts navbar-dropdown dropdown me-2 me-xl-0">
<a
class="nav-link dropdown-toggle hide-arrow"
href="javascript:void(0);"
data-bs-toggle="dropdown"
data-bs-auto-close="outside"
aria-expanded="false"
>
<i class="ti ti-eye ti-md"></i>
</a>
<div class="dropdown-menu dropdown-menu-end py-0">
<div class="dropdown-menu-header border-bottom">
<div class="dropdown-header d-flex align-items-center py-3">
<h5 class="text-body mb-0 me-auto">Vistas</h5>
</div>
</div>
<div class="dropdown-shortcuts-list scrollable-container">
<div class="row row-bordered overflow-visible g-0">
<div class="dropdown-shortcuts-item col">
<span class="dropdown-shortcuts-icon rounded-circle mb-2">
<i class="ti ti-printer fs-4"></i>
</span>
<small class="text-muted mb-0">Vista</small>
<a href="<?= site_url('viewmode/' . config("Basics")->vista_impresion); ?>" class="stretched-link">Impresión</a>
</div>
<div class="dropdown-shortcuts-item col">
<span class="dropdown-shortcuts-icon rounded-circle mb-2">
<i class="ti ti-ruler-2 fs-4"></i>
</span>
<small class="text-muted mb-0">Vista</small>
<a href="<?= site_url('viewmode/' . config("Basics")->vista_maquetacion); ?>" class="stretched-link">Maquetación</a>
</div>
</div>
<div class="row row-bordered overflow-visible g-0">
<div class="dropdown-shortcuts-item col">
<span class="dropdown-shortcuts-icon rounded-circle mb-2">
<i class="ti ti-file-code-2 fs-4"></i>
</span>
<small class="text-muted mb-0">Vista</small>
<a href="<?= site_url('viewmode/' . config("Basics")->vista_digitalizacion); ?>" class="stretched-link">Digitalización</a>
</div>
</div>
</div>
</div>
</li>
<!-- View Mode links -->
<!-- Language -->
<li class="nav-item dropdown-language dropdown me-2 me-xl-0">
<a class="nav-link dropdown-toggle hide-arrow" href="javascript:void(0);"
data-bs-toggle="dropdown">
<i class="fi <?= getCurrentLanguageFlag(); ?> fis rounded-circle me-1 fs-3"></i>
</a>
<ul class="dropdown-menu dropdown-menu-end">
<li>
<a class="dropdown-item" href="<?= site_url('lang/es'); ?>" data-language="es">
<i class="fi fi-es fis rounded-circle me-1 fs-3"></i>
<span class="align-middle"><?= lang("App.lang_es") ?></span>
</a>
</li>
<li>
<a class="dropdown-item" href="<?= site_url('lang/en'); ?>" data-language="en">
<i class="fi fi-gb fis rounded-circle me-1 fs-3"></i>
<span class="align-middle"><?= lang("App.lang_en") ?></span>
</a>
</li>
</ul>
</li>
<!--/ Language -->
<!-- User -->
<li class="nav-item navbar-dropdown dropdown-user dropdown">
<a class="nav-link dropdown-toggle hide-arrow" href="javascript:void(0);"
data-bs-toggle="dropdown">
<div class="avatar">
<img src="<?= $picture ?? '' ?>" alt class="h-auto rounded-circle"/>
</div>
</a>
<ul class="dropdown-menu dropdown-menu-end">
<li>
<a class="dropdown-item" href="#">
<div class="d-flex">
<div class="flex-shrink-0 me-3">
<div class="avatar avatar">
<img src="<?= $picture ?? '' ?>" alt class="h-auto rounded-circle"/>
</div>
</div>
<div class="flex-grow-1">
<span class="fw-semibold d-block"><?= $session->get('first_name') . ' ' . $session->get('last_name') ?></span>
<small class="text-muted">Admin</small>
</div>
</div>
</a>
</li>
<li>
<div class="dropdown-divider"></div>
</li>
<li>
<a class="dropdown-item" href="<?= site_url('profile'); ?>">
<i class="ti ti-user-check me-2 ti-sm"></i>
<span class="align-middle"><?= lang("App.menu_profile") ?></span>
</a>
</li>
<!-- <li>-->
<!-- <a class="dropdown-item" href="#">-->
<!-- <i class="ti ti-settings me-2 ti-sm"></i>-->
<!-- <span class="align-middle">Settings</span>-->
<!-- </a>-->
<!-- </li>-->
<li>
<div class="dropdown-divider"></div>
</li>
<li>
<a class="dropdown-item" href="<?= site_url("logout") ?>">
<i class="ti ti-logout me-2 ti-sm"></i>
<span class="align-middle"><?= lang("App.menu_logout") ?></span>
</a>
</li>
</ul>
</li>
<!--/ User -->
</ul>
</div>
</nav>
<!-- / Navbar -->
<!-- Content wrapper -->
<div class="content-wrapper">
<!-- Content -->
<div class="container-xxl flex-grow-1 container-p-y">
<h5 class="py-3 mb-4">
<?php include "breadcrumbs.php" ?>
</h5>
<?= $this->renderSection('content') ?>
</div>
<!-- / Content -->
<!-- Footer -->
<footer class="content-footer footer bg-footer-theme">
<div class="container-xxl">
<div class="footer-container d-flex align-items-center justify-content-between py-2 flex-md-row flex-column">
<div>
<a href="#" target="_blank" class="fw-semibold">Safekat</a> © <?= date('Y'); ?>
</div>
</div>
</div>
</footer>
<!-- / Footer -->
<div class="content-backdrop fade"></div>
</div>
<!-- Content wrapper -->
</div>
<!-- / Layout page -->
</div>
<!-- Overlay -->
<div class="layout-overlay layout-menu-toggle"></div>
<!-- Drag Target Area To SlideIn Menu On Small Screens -->
<div class="drag-target"></div>
</div>
<!-- / Layout wrapper -->
<?= $this->renderSection('footerAdditions') ?>
<!-- Core JS -->
<!-- build:js assets/vendor/js/core.js -->
<script src="<?= site_url('themes/vuexy/vendor/libs/jquery/jquery.js') ?>"></script>
<script src="<?= site_url('themes/vuexy/vendor/libs/popper/popper.js') ?>"></script>
<script src="<?= site_url('themes/vuexy/vendor/js/bootstrap.js') ?>"></script>
<script src="<?= site_url('themes/vuexy/vendor/libs/perfect-scrollbar/perfect-scrollbar.js') ?>"></script>
<script src="<?= site_url('themes/vuexy/vendor/libs/hammer/hammer.js') ?>"></script>
<script src="<?= site_url('themes/vuexy/vendor/js/menu.js') ?>"></script>
<!-- endbuild -->
<!-- Vendors JS -->
<?= $this->renderSection('additionalExternalJs') ?>
<!-- Main JS -->
<script src="<?= site_url('themes/vuexy/js/main.js') ?>"></script>
<!-- Page JS -->
<script src="<?= site_url('assets/js/main.js') ?>"></script>
<?= sweetAlert() ?>
<script type="text/javascript">
<?= $this->renderSection('additionalInlineJs') ?>
</script>
</body>
</html>

View File

@ -1,570 +0,0 @@
<?php
$session = session();
$settings = $session->get('settings');
$picture = "/assets/img/default-user.png";
?>
<!DOCTYPE html>
<html
lang="<?= $session->get('lang') ?>"
class="h-100"
class="semi-dark-style customizer-hide"
dir="ltr"
data-theme="theme-default"
data-assets-path="<?= site_url('themes/vuexy/') ?>"
data-template="vertical-menu-template-no-customizer"
>
<head>
<meta charset="utf-8">
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"
/>
<title><?= config('Safekat')->appName ?></title>
<meta name="description" content=""/>
<!-- Favicon -->
<link rel="icon" type="image/x-icon" href="<?= site_url('themes/vuexy/img/favicon/favicon.ico') ?>"/>
<link rel="apple-touch-icon" sizes="57x57" href="<?= site_url('themes/vuexy/img/favicon/apple-icon-57x57.png') ?>">
<link rel="apple-touch-icon" sizes="60x60" href="<?= site_url('themes/vuexy/img/favicon/apple-icon-60x60.png') ?>">
<link rel="apple-touch-icon" sizes="72x72" href="<?= site_url('themes/vuexy/img/favicon/apple-icon-72x72.png') ?>">
<link rel="apple-touch-icon" sizes="76x76" href="<?= site_url('themes/vuexy/img/favicon/apple-icon-76x76.png') ?>">
<link rel="apple-touch-icon" sizes="114x114"
href="<?= site_url('themes/vuexy/img/favicon/apple-icon-114x114.png') ?>">
<link rel="apple-touch-icon" sizes="120x120"
href="<?= site_url('themes/vuexy/img/favicon/apple-icon-120x120.png') ?>">
<link rel="apple-touch-icon" sizes="144x144"
href="<?= site_url('themes/vuexy/img/favicon/apple-icon-144x144.png') ?>">
<link rel="apple-touch-icon" sizes="152x152"
href="<?= site_url('themes/vuexy/img/favicon/apple-icon-152x152.png') ?>">
<link rel="apple-touch-icon" sizes="180x180"
href="<?= site_url('themes/vuexy/img/favicon/apple-icon-180x180.png') ?>">
<link rel="icon" type="image/png" sizes="192x192"
href="<?= site_url('themes/vuexy/img/favicon/android-icon-192x192.png') ?>">
<link rel="icon" type="image/png" sizes="32x32"
href="<?= site_url('themes/vuexy/img/favicon/favicon-32x32.png') ?>">
<link rel="icon" type="image/png" sizes="96x96"
href="<?= site_url('themes/vuexy/img/favicon/favicon-96x96.png') ?>">
<link rel="icon" type="image/png" sizes="16x16"
href="<?= site_url('themes/vuexy/img/favicon/favicon-16x16.png') ?>">
<link rel="manifest" href="<?= site_url('themes/vuexy/img/favicon/manifest.json') ?>">
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com"/>
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin/>
<link
href="https://fonts.googleapis.com/css2?family=Public+Sans:ital,wght@0,300;0,400;0,500;0,600;0,700;1,300;1,400;1,500;1,600;1,700&display=swap"
rel="stylesheet"
/>
<!-- Icons -->
<link rel="stylesheet" href="<?= site_url('themes/vuexy/vendor/fonts/fontawesome.css') ?>"/>
<link rel="stylesheet" href="<?= site_url('themes/vuexy/vendor/fonts/tabler-icons.css') ?>"/>
<link rel="stylesheet" href="<?= site_url('themes/vuexy/vendor/fonts/flag-icons.css') ?>"/>
<!-- Core CSS -->
<link rel="stylesheet" href="<?= site_url('themes/vuexy/vendor/css/rtl/core.css') ?>"/>
<link rel="stylesheet" href="<?= site_url('themes/vuexy/vendor/css/rtl/theme-semi-dark.css') ?>"/>
<link rel="stylesheet" href="<?= site_url('themes/vuexy/css/safekat.css') ?>"/>
<!-- Vendors CSS -->
<link rel="stylesheet" href="<?= site_url('themes/vuexy/vendor/libs/perfect-scrollbar/perfect-scrollbar.css') ?>"/>
<!-- Page CSS -->
<!-- Helpers -->
<script src="<?= site_url('themes/vuexy/vendor/js/helpers.js') ?>"></script>
<script src="<?= site_url('themes/vuexy/js/config.js') ?>"></script>
</head>
<body>
<!-- Layout wrapper -->
<div class="layout-wrapper layout-content-navbar">
<div class="layout-container">
<?php include "selector_menu.php" ?>
<!-- Layout container -->
<div class="layout-page">
<!-- Navbar -->
<nav
class="layout-navbar container-xxl navbar navbar-expand-xl navbar-detached align-items-center bg-navbar-theme"
id="layout-navbar"
>
<div class="layout-menu-toggle navbar-nav align-items-xl-center me-3 me-xl-0 d-xl-none">
<a class="nav-item nav-link px-0 me-xl-4" href="javascript:void(0)">
<i class="ti ti-menu-2 ti-sm"></i>
</a>
</div>
<div class="navbar-nav-right d-flex align-items-center" id="navbar-collapse">
<div class="navbar-nav align-items-center">
<a class="nav-link style-switcher-toggle hide-arrow" href="javascript:void(0);">
<i class="ti ti-sm"></i>
</a>
</div>
<ul class="navbar-nav flex-row align-items-center ms-auto">
<!-- Notification -->
<li class="nav-item dropdown-notifications navbar-dropdown dropdown me-3 me-xl-1">
<a
class="nav-link dropdown-toggle hide-arrow"
href="javascript:void(0);"
data-bs-toggle="dropdown"
data-bs-auto-close="outside"
aria-expanded="false"
>
<i class="ti ti-bell ti-md"></i>
<span class="badge bg-danger rounded-pill badge-notifications">5</span>
</a>
<ul class="dropdown-menu dropdown-menu-end py-0">
<li class="dropdown-menu-header border-bottom">
<div class="dropdown-header d-flex align-items-center py-3">
<h5 class="text-body mb-0 me-auto">Notification</h5>
<a
href="javascript:void(0)"
class="dropdown-notifications-all text-body"
data-bs-toggle="tooltip"
data-bs-placement="top"
title="Mark all as read"
><i class="ti ti-mail-opened fs-4"></i
></a>
</div>
</li>
<li class="dropdown-notifications-list scrollable-container">
<ul class="list-group list-group-flush">
<li class="list-group-item list-group-item-action dropdown-notifications-item">
<div class="d-flex">
<div class="flex-shrink-0 me-3">
<div class="avatar">
<img src="../../assets/img/avatars/1.png" alt
class="h-auto rounded-circle"/>
</div>
</div>
<div class="flex-grow-1">
<h6 class="mb-1">Congratulation Lettie 🎉</h6>
<p class="mb-0">Won the monthly best seller gold badge</p>
<small class="text-muted">1h ago</small>
</div>
<div class="flex-shrink-0 dropdown-notifications-actions">
<a href="javascript:void(0)" class="dropdown-notifications-read"
><span class="badge badge-dot"></span
></a>
<a href="javascript:void(0)" class="dropdown-notifications-archive"
><span class="ti ti-x"></span
></a>
</div>
</div>
</li>
<li class="list-group-item list-group-item-action dropdown-notifications-item">
<div class="d-flex">
<div class="flex-shrink-0 me-3">
<div class="avatar">
<span class="avatar-initial rounded-circle bg-label-danger">CF</span>
</div>
</div>
<div class="flex-grow-1">
<h6 class="mb-1">Charles Franklin</h6>
<p class="mb-0">Accepted your connection</p>
<small class="text-muted">12hr ago</small>
</div>
<div class="flex-shrink-0 dropdown-notifications-actions">
<a href="javascript:void(0)" class="dropdown-notifications-read"
><span class="badge badge-dot"></span
></a>
<a href="javascript:void(0)" class="dropdown-notifications-archive"
><span class="ti ti-x"></span
></a>
</div>
</div>
</li>
<li class="list-group-item list-group-item-action dropdown-notifications-item marked-as-read">
<div class="d-flex">
<div class="flex-shrink-0 me-3">
<div class="avatar">
<img src="../../assets/img/avatars/2.png" alt
class="h-auto rounded-circle"/>
</div>
</div>
<div class="flex-grow-1">
<h6 class="mb-1">New Message ✉️</h6>
<p class="mb-0">You have new message from Natalie</p>
<small class="text-muted">1h ago</small>
</div>
<div class="flex-shrink-0 dropdown-notifications-actions">
<a href="javascript:void(0)" class="dropdown-notifications-read"
><span class="badge badge-dot"></span
></a>
<a href="javascript:void(0)" class="dropdown-notifications-archive"
><span class="ti ti-x"></span
></a>
</div>
</div>
</li>
<li class="list-group-item list-group-item-action dropdown-notifications-item">
<div class="d-flex">
<div class="flex-shrink-0 me-3">
<div class="avatar">
<span class="avatar-initial rounded-circle bg-label-success"
><i class="ti ti-shopping-cart"></i
></span>
</div>
</div>
<div class="flex-grow-1">
<h6 class="mb-1">Whoo! You have new order 🛒</h6>
<p class="mb-0">ACME Inc. made new order $1,154</p>
<small class="text-muted">1 day ago</small>
</div>
<div class="flex-shrink-0 dropdown-notifications-actions">
<a href="javascript:void(0)" class="dropdown-notifications-read"
><span class="badge badge-dot"></span
></a>
<a href="javascript:void(0)" class="dropdown-notifications-archive"
><span class="ti ti-x"></span
></a>
</div>
</div>
</li>
<li class="list-group-item list-group-item-action dropdown-notifications-item marked-as-read">
<div class="d-flex">
<div class="flex-shrink-0 me-3">
<div class="avatar">
<img src="../../assets/img/avatars/9.png" alt
class="h-auto rounded-circle"/>
</div>
</div>
<div class="flex-grow-1">
<h6 class="mb-1">Application has been approved 🚀</h6>
<p class="mb-0">Your ABC project application has been approved.</p>
<small class="text-muted">2 days ago</small>
</div>
<div class="flex-shrink-0 dropdown-notifications-actions">
<a href="javascript:void(0)" class="dropdown-notifications-read"
><span class="badge badge-dot"></span
></a>
<a href="javascript:void(0)" class="dropdown-notifications-archive"
><span class="ti ti-x"></span
></a>
</div>
</div>
</li>
<li class="list-group-item list-group-item-action dropdown-notifications-item marked-as-read">
<div class="d-flex">
<div class="flex-shrink-0 me-3">
<div class="avatar">
<span class="avatar-initial rounded-circle bg-label-success"
><i class="ti ti-chart-pie"></i
></span>
</div>
</div>
<div class="flex-grow-1">
<h6 class="mb-1">Monthly report is generated</h6>
<p class="mb-0">July monthly financial report is generated</p>
<small class="text-muted">3 days ago</small>
</div>
<div class="flex-shrink-0 dropdown-notifications-actions">
<a href="javascript:void(0)" class="dropdown-notifications-read"
><span class="badge badge-dot"></span
></a>
<a href="javascript:void(0)" class="dropdown-notifications-archive"
><span class="ti ti-x"></span
></a>
</div>
</div>
</li>
<li class="list-group-item list-group-item-action dropdown-notifications-item marked-as-read">
<div class="d-flex">
<div class="flex-shrink-0 me-3">
<div class="avatar">
<img src="../../assets/img/avatars/5.png" alt
class="h-auto rounded-circle"/>
</div>
</div>
<div class="flex-grow-1">
<h6 class="mb-1">Send connection request</h6>
<p class="mb-0">Peter sent you connection request</p>
<small class="text-muted">4 days ago</small>
</div>
<div class="flex-shrink-0 dropdown-notifications-actions">
<a href="javascript:void(0)" class="dropdown-notifications-read"
><span class="badge badge-dot"></span
></a>
<a href="javascript:void(0)" class="dropdown-notifications-archive"
><span class="ti ti-x"></span
></a>
</div>
</div>
</li>
<li class="list-group-item list-group-item-action dropdown-notifications-item">
<div class="d-flex">
<div class="flex-shrink-0 me-3">
<div class="avatar">
<img src="../../assets/img/avatars/6.png" alt
class="h-auto rounded-circle"/>
</div>
</div>
<div class="flex-grow-1">
<h6 class="mb-1">New message from Jane</h6>
<p class="mb-0">Your have new message from Jane</p>
<small class="text-muted">5 days ago</small>
</div>
<div class="flex-shrink-0 dropdown-notifications-actions">
<a href="javascript:void(0)" class="dropdown-notifications-read"
><span class="badge badge-dot"></span
></a>
<a href="javascript:void(0)" class="dropdown-notifications-archive"
><span class="ti ti-x"></span
></a>
</div>
</div>
</li>
<li class="list-group-item list-group-item-action dropdown-notifications-item marked-as-read">
<div class="d-flex">
<div class="flex-shrink-0 me-3">
<div class="avatar">
<span class="avatar-initial rounded-circle bg-label-warning"
><i class="ti ti-alert-triangle"></i
></span>
</div>
</div>
<div class="flex-grow-1">
<h6 class="mb-1">CPU is running high</h6>
<p class="mb-0">CPU Utilization Percent is currently at 88.63%,</p>
<small class="text-muted">5 days ago</small>
</div>
<div class="flex-shrink-0 dropdown-notifications-actions">
<a href="javascript:void(0)" class="dropdown-notifications-read"
><span class="badge badge-dot"></span
></a>
<a href="javascript:void(0)" class="dropdown-notifications-archive"
><span class="ti ti-x"></span
></a>
</div>
</div>
</li>
</ul>
</li>
<li class="dropdown-menu-footer border-top">
<a
href="javascript:void(0);"
class="dropdown-item d-flex justify-content-center text-primary p-2 h-px-40 mb-1 align-items-center"
>
View all notifications
</a>
</li>
</ul>
</li>
<!--/ Notification -->
<!-- Search Budgets -->
<li class="nav-item navbar-dropdown dropdown me-3 me-xl-1">
<a
class="nav-link hide-arrow"
href="<?= site_url('presupuestos/buscador'); ?>"
title="Acceso directo a buscador de presupuestos"
>
<i class="ti ti-report-search ti-md"></i>
</a>
</li>
<!--/ Search Budgets -->
<!-- View Mode links -->
<li class="nav-item dropdown-shortcuts navbar-dropdown dropdown me-2 me-xl-0">
<a
class="nav-link dropdown-toggle hide-arrow"
href="javascript:void(0);"
data-bs-toggle="dropdown"
data-bs-auto-close="outside"
aria-expanded="false"
>
<i class="ti ti-building ti-md"></i>
</a>
<div class="dropdown-menu dropdown-menu-end py-0">
<div class="dropdown-menu-header border-bottom">
<div class="dropdown-header d-flex align-items-center py-3">
<h5 class="text-body mb-0 me-auto">Vistas</h5>
</div>
</div>
<div class="dropdown-shortcuts-list scrollable-container">
<div class="row row-bordered overflow-visible g-0">
<div class="dropdown-shortcuts-item col">
<span class="dropdown-shortcuts-icon rounded-circle mb-2">
<i class="ti ti-printer fs-4"></i>
</span>
<small class="text-muted mb-0">Vista</small>
<a href="<?= site_url('viewmode/' . config("Basics")->vista_impresion); ?>" class="stretched-link">Impresión</a>
</div>
<div class="dropdown-shortcuts-item col">
<span class="dropdown-shortcuts-icon rounded-circle mb-2">
<i class="ti ti-ruler-2 fs-4"></i>
</span>
<small class="text-muted mb-0">Vista</small>
<a href="<?= site_url('viewmode/' . config("Basics")->vista_maquetacion); ?>" class="stretched-link">Maquetación</a>
</div>
</div>
<div class="row row-bordered overflow-visible g-0">
<div class="dropdown-shortcuts-item col">
<span class="dropdown-shortcuts-icon rounded-circle mb-2">
<i class="ti ti-file-code-2 fs-4"></i>
</span>
<small class="text-muted mb-0">Vista</small>
<a href="<?= site_url('viewmode/' . config("Basics")->vista_digitalizacion); ?>" class="stretched-link">Digitalización</a>
</div>
</div>
</div>
</div>
</li>
<!-- View Mode links -->
<!-- Language -->
<li class="nav-item dropdown-language dropdown me-2 me-xl-0">
<a class="nav-link dropdown-toggle hide-arrow" href="javascript:void(0);"
data-bs-toggle="dropdown">
<i class="fi <?= getCurrentLanguageFlag(); ?> fis rounded-circle me-1 fs-3"></i>
</a>
<ul class="dropdown-menu dropdown-menu-end">
<li>
<a class="dropdown-item" href="<?= site_url('lang/es'); ?>" data-language="es">
<i class="fi fi-es fis rounded-circle me-1 fs-3"></i>
<span class="align-middle"><?= lang("App.lang_es") ?></span>
</a>
</li>
<li>
<a class="dropdown-item" href="<?= site_url('lang/en'); ?>" data-language="en">
<i class="fi fi-gb fis rounded-circle me-1 fs-3"></i>
<span class="align-middle"><?= lang("App.lang_en") ?></span>
</a>
</li>
</ul>
</li>
<!--/ Language -->
<!-- User -->
<li class="nav-item navbar-dropdown dropdown-user dropdown">
<a class="nav-link dropdown-toggle hide-arrow" href="javascript:void(0);"
data-bs-toggle="dropdown">
<div class="avatar">
<img src="<?= $picture ?? '' ?>" alt class="h-auto rounded-circle"/>
</div>
</a>
<ul class="dropdown-menu dropdown-menu-end">
<li>
<a class="dropdown-item" href="#">
<div class="d-flex">
<div class="flex-shrink-0 me-3">
<div class="avatar avatar-online">
<img src="<?= $picture ?? '' ?>" alt class="h-auto rounded-circle"/>
</div>
</div>
<div class="flex-grow-1">
<span class="fw-semibold d-block"><?= $session->get('first_name') . ' ' . $session->get('last_name') ?></span>
<small class="text-muted">Admin</small>
</div>
</div>
</a>
</li>
<li>
<div class="dropdown-divider"></div>
</li>
<li>
<a class="dropdown-item" href="<?= site_url('profile'); ?>">
<i class="ti ti-user-check me-2 ti-sm"></i>
<span class="align-middle"><?= lang("App.menu_profile") ?></span>
</a>
</li>
<!-- <li>-->
<!-- <a class="dropdown-item" href="#">-->
<!-- <i class="ti ti-settings me-2 ti-sm"></i>-->
<!-- <span class="align-middle">Settings</span>-->
<!-- </a>-->
<!-- </li>-->
<li>
<div class="dropdown-divider"></div>
</li>
<li>
<a class="dropdown-item" href="<?= site_url("logout") ?>">
<i class="ti ti-logout me-2 ti-sm"></i>
<span class="align-middle"><?= lang("App.menu_logout") ?></span>
</a>
</li>
</ul>
</li>
<!--/ User -->
</ul>
</div>
</nav>
<!-- / Navbar -->
<!-- Content wrapper -->
<div class="content-wrapper">
<!-- Content -->
<div class="container-xxl flex-grow-1 container-p-y">
<h5 class="py-3 mb-4">
<?php include "breadcrumbs.php" ?>
</h5>
<p>
Sample page.
</p>
</div>
<!-- / Content -->
<!-- Footer -->
<footer class="content-footer footer bg-footer-theme">
<div class="container-xxl">
<div class="footer-container d-flex align-items-center justify-content-between py-2 flex-md-row flex-column">
<div>
<a href="#" target="_blank" class="fw-semibold">Safekat</a> © <?= date('Y'); ?>
</div>
</div>
</div>
</footer>
<!-- / Footer -->
<div class="content-backdrop fade"></div>
</div>
<!-- Content wrapper -->
</div>
<!-- / Layout page -->
</div>
<!-- Overlay -->
<div class="layout-overlay layout-menu-toggle"></div>
<!-- Drag Target Area To SlideIn Menu On Small Screens -->
<div class="drag-target"></div>
</div>
<!-- / Layout wrapper -->
<!-- Core JS -->
<!-- build:js assets/vendor/js/core.js -->
<script src="<?= site_url('themes/vuexy/vendor/libs/jquery/jquery.js') ?>"></script>
<script src="<?= site_url('themes/vuexy/vendor/libs/popper/popper.js') ?>"></script>
<script src="<?= site_url('themes/vuexy/vendor/js/bootstrap.js') ?>"></script>
<script src="<?= site_url('themes/vuexy/vendor/libs/perfect-scrollbar/perfect-scrollbar.js') ?>"></script>
<script src="<?= site_url('themes/vuexy/vendor/libs/hammer/hammer.js') ?>"></script>
<script src="<?= site_url('themes/vuexy/vendor/js/menu.js') ?>"></script>
<!-- endbuild -->
<!-- Vendors JS -->
<!-- Main JS -->
<script src="<?= site_url('themes/vuexy/js/main.js') ?>"></script>
<!-- Page JS -->
</body>
</html>

View File

@ -133,7 +133,6 @@ $picture = "/assets/img/default-user.png";
title="Acceso directo a buscador de presupuestos" title="Acceso directo a buscador de presupuestos"
> >
<i class="ti ti-report-search ti-md"></i> <i class="ti ti-report-search ti-md"></i>
</a> </a>
</li> </li>
<!--/ Search Budgets --> <!--/ Search Budgets -->
@ -232,8 +231,8 @@ $picture = "/assets/img/default-user.png";
</div> </div>
</div> </div>
<div class="flex-grow-1"> <div class="flex-grow-1">
<span class="fw-semibold d-block"><?= $session->get('first_name') . ' ' . $session->get('last_name') ?></span> <span class="fw-semibold d-block"><?= auth()->user()->getFullName(); ?></span>
<small class="text-muted">Admin</small> <small class="text-muted"><?= auth()->user()->getEmail(); ?></small>
</div> </div>
</div> </div>
</a> </a>
@ -247,13 +246,6 @@ $picture = "/assets/img/default-user.png";
<span class="align-middle"><?= lang("App.menu_profile") ?></span> <span class="align-middle"><?= lang("App.menu_profile") ?></span>
</a> </a>
</li> </li>
<!-- <li>-->
<!-- <a class="dropdown-item" href="#">-->
<!-- <i class="ti ti-settings me-2 ti-sm"></i>-->
<!-- <span class="align-middle">Settings</span>-->
<!-- </a>-->
<!-- </li>-->
<li> <li>
<div class="dropdown-divider"></div> <div class="dropdown-divider"></div>
</li> </li>

View File

@ -1,297 +0,0 @@
<?php
$session = session();
$token = $session->get('token') ?? '';
$tfa = $session->get('tfa') ?? false;
$settings = $session->get('settings');
$picture = "/assets/img/default-user.png";
$pulse = session()->get('pulse');
$notification = session()->get('notification');
if (!empty($token) && $tfa == false) {
//echo "<script>window.location.href = '/'; </script>";
}
?>
<!DOCTYPE html>
<html
lang="<?= $session->get('lang') ?>"
class="h-100 light-style layout-navbar-fixed layout-menu-fixed"
dir="ltr"
data-theme="theme-default"
data-assets-path="<?= site_url('themes/vuexy/') ?>"
data-template="vertical-menu-template-no-customizer"
>
<head>
<meta charset="utf-8">
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"
/>
<title><?= config('Safekat')->appName ?></title>
<meta name="description" content=""/>
<!-- Favicon -->
<link rel="icon" type="image/x-icon" href="<?= site_url('themes/vuexy/img/favicon/favicon.ico') ?>"/>
<link rel="apple-touch-icon" sizes="57x57" href="<?= site_url('themes/vuexy/img/favicon/apple-icon-57x57.png') ?>">
<link rel="apple-touch-icon" sizes="60x60" href="<?= site_url('themes/vuexy/img/favicon/apple-icon-60x60.png') ?>">
<link rel="apple-touch-icon" sizes="72x72" href="<?= site_url('themes/vuexy/img/favicon/apple-icon-72x72.png') ?>">
<link rel="apple-touch-icon" sizes="76x76" href="<?= site_url('themes/vuexy/img/favicon/apple-icon-76x76.png') ?>">
<link rel="apple-touch-icon" sizes="114x114"
href="<?= site_url('themes/vuexy/img/favicon/apple-icon-114x114.png') ?>">
<link rel="apple-touch-icon" sizes="120x120"
href="<?= site_url('themes/vuexy/img/favicon/apple-icon-120x120.png') ?>">
<link rel="apple-touch-icon" sizes="144x144"
href="<?= site_url('themes/vuexy/img/favicon/apple-icon-144x144.png') ?>">
<link rel="apple-touch-icon" sizes="152x152"
href="<?= site_url('themes/vuexy/img/favicon/apple-icon-152x152.png') ?>">
<link rel="apple-touch-icon" sizes="180x180"
href="<?= site_url('themes/vuexy/img/favicon/apple-icon-180x180.png') ?>">
<link rel="icon" type="image/png" sizes="192x192"
href="<?= site_url('themes/vuexy/img/favicon/android-icon-192x192.png') ?>">
<link rel="icon" type="image/png" sizes="32x32"
href="<?= site_url('themes/vuexy/img/favicon/favicon-32x32.png') ?>">
<link rel="icon" type="image/png" sizes="96x96"
href="<?= site_url('themes/vuexy/img/favicon/favicon-96x96.png') ?>">
<link rel="icon" type="image/png" sizes="16x16"
href="<?= site_url('themes/vuexy/img/favicon/favicon-16x16.png') ?>">
<link rel="manifest" href="<?= site_url('themes/vuexy/img/favicon/manifest.json') ?>">
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com"/>
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin/>
<link
href="https://fonts.googleapis.com/css2?family=Public+Sans:ital,wght@0,300;0,400;0,500;0,600;0,700;1,300;1,400;1,500;1,600;1,700&display=swap"
rel="stylesheet"
/>
<!-- Icons -->
<link rel="stylesheet" href="<?= site_url('themes/vuexy/vendor/fonts/fontawesome.css') ?>"/>
<link rel="stylesheet" href="<?= site_url('themes/vuexy/vendor/fonts/tabler-icons.css') ?>"/>
<link rel="stylesheet" href="<?= site_url('themes/vuexy/vendor/fonts/flag-icons.css') ?>"/>
<!-- Core CSS -->
<link rel="stylesheet" href="<?= site_url('themes/vuexy/vendor/css/rtl/core.css') ?>"/>
<link rel="stylesheet" href="<?= site_url('themes/vuexy/vendor/css/rtl/theme-semi-dark.css') ?>"/>
<link rel="stylesheet" href="<?= site_url('themes/vuexy/css/safekat.css') ?>"/>
<!-- Vendors CSS -->
<link rel="stylesheet" href="<?= site_url('themes/vuexy/vendor/libs/perfect-scrollbar/perfect-scrollbar.css') ?>"/>
<link rel="stylesheet" href="<?= site_url('themes/vuexy/vendor/libs/node-waves/node-waves.css') ?>"/>
<link rel="stylesheet" href="<?= site_url('themes/vuexy/vendor/libs/select2/select2.css') ?>"/>
<!-- Page CSS -->
<!-- Helpers -->
<script src="<?= site_url('themes/vuexy/vendor/js/helpers.js') ?>"></script>
<script src="<?= site_url('themes/vuexy/js/config.js') ?>"></script>
</head>
<body>
<!-- Layout wrapper -->
<div class="layout-wrapper layout-content-navbar">
<div class="layout-container">
<?php include "menu.php" ?>
<!-- Layout container -->
<div class="layout-page">
<!-- Navbar -->
<nav
class="layout-navbar container-xxl navbar navbar-expand-xl navbar-detached align-items-center bg-navbar-theme"
id="layout-navbar"
>
<div class="layout-menu-toggle navbar-nav align-items-xl-center me-3 me-xl-0 d-xl-none">
<a class="nav-item nav-link px-0 me-xl-4" href="javascript:void(0)">
<i class="ti ti-menu-2 ti-sm"></i>
</a>
</div>
<div class="navbar-nav-right d-flex align-items-center" id="navbar-collapse">
<div class="navbar-nav align-items-center">
<a class="nav-link style-switcher-toggle hide-arrow" href="javascript:void(0);">
<i class="ti ti-sm"></i>
</a>
</div>
<ul class="navbar-nav flex-row align-items-center ms-auto">
<!-- Notification -->
<li class="nav-item dropdown-notifications navbar-dropdown dropdown me-3 me-xl-1">
<a
class="nav-link dropdown-toggle hide-arrow"
href="javascript:void(0);"
data-bs-toggle="dropdown"
data-bs-auto-close="outside"
aria-expanded="false"
>
<i class="ti ti-bell ti-md"></i>
<span class="badge bg-danger rounded-pill badge-notifications">5</span>
</a>
</li>
<!--/ Notification -->
<!-- Language -->
<li class="nav-item dropdown-language dropdown me-2 me-xl-0">
<a class="nav-link dropdown-toggle hide-arrow" href="javascript:void(0);" data-bs-toggle="dropdown">
<i class="fi fi-es fis rounded-circle me-1 fs-3"></i>
</a>
<ul class="dropdown-menu dropdown-menu-end">
<li>
<a class="dropdown-item" href="<?= site_url('lang/es'); ?>" data-language="es">
<i class="fi fi-es fis rounded-circle me-1 fs-3"></i>
<span class="align-middle"><?= lang("App.lang_es") ?></span>
</a>
</li>
<li>
<a class="dropdown-item" href="<?= site_url('lang/en'); ?>" data-language="en">
<i class="fi fi-gb fis rounded-circle me-1 fs-3"></i>
<span class="align-middle"><?= lang("App.lang_en") ?></span>
</a>
</li>
</ul>
</li>
<!--/ Language -->
<!-- User -->
<li class="nav-item navbar-dropdown dropdown-user dropdown">
<a class="nav-link dropdown-toggle hide-arrow" href="javascript:void(0);"
data-bs-toggle="dropdown">
<div class="avatar">
<img src="<?= $picture ?? '' ?>" alt class="h-auto rounded-circle"/>
</div>
</a>
<ul class="dropdown-menu dropdown-menu-end">
<li>
<a class="dropdown-item" href="#">
<div class="d-flex">
<div class="flex-shrink-0 me-3">
<div class="avatar avatar-online">
<img src="<?= $picture ?? '' ?>" alt class="h-auto rounded-circle"/>
</div>
</div>
<div class="flex-grow-1">
<span class="fw-semibold d-block"><?= $session->get('first_name') . ' ' . $session->get('last_name') ?></span>
<small class="text-muted">Admin</small>
</div>
</div>
</a>
</li>
<li>
<div class="dropdown-divider"></div>
</li>
<li>
<a class="dropdown-item" href="<?= site_url('profile'); ?>">
<i class="ti ti-user-check me-2 ti-sm"></i>
<span class="align-middle"><?= lang("App.menu_profile") ?></span>
</a>
</li>
<li>
<a class="dropdown-item" href="#">
<i class="ti ti-settings me-2 ti-sm"></i>
<span class="align-middle">Settings</span>
</a>
</li>
<li>
<div class="dropdown-divider"></div>
</li>
<li>
<a class="dropdown-item" href="<?= site_url("logout") ?>">
<i class="ti ti-logout me-2 ti-sm"></i>
<span class="align-middle"><?= lang("App.menu_logout") ?></span>
</a>
</li>
</ul>
</li>
<!--/ User -->
</ul>
</div>
</nav>
<!-- / Navbar -->
<!-- Content wrapper -->
<div class="content-wrapper">
<!-- Content -->
<div class="container-xxl flex-grow-1 container-p-y">
<h4 class="fw-bold py-3 mb-4">
<span class="text-muted fw-light">Safekat /</span>
<?= $page_name ?? "" ?>
</h4>
<div class="row">
<div class="col-12">
<div class="card mb-4">
<h5 class="card-header">Prueba privilegios</h5>
<div class="card-body">
<div class="d-grid gap-2 col-lg-6 mx-auto">
<button onclick="location.href='<?= $url ?>/add'" type="button" class="btn btn-dark">Añadir</button>
<button onclick="location.href='<?= $url ?>/edit'" type="button" class="btn btn-info">Editar</button>
<button onclick="location.href='<?= $url ?>/delete'" type="button" class="btn btn-danger">Borrar</button>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- / Content -->
<!-- Footer -->
<footer class="content-footer footer bg-footer-theme">
<div class="container-xxl">
<div class="footer-container d-flex align-items-center justify-content-between py-2 flex-md-row flex-column">
<div>
<a href="#" target="_blank" class="fw-semibold">Safekat</a> © <?= date('Y'); ?>
</div>
</div>
</div>
</footer>
<!-- / Footer -->
<div class="content-backdrop fade"></div>
</div>
<!-- Content wrapper -->
</div>
<!-- / Layout page -->
</div>
<!-- Overlay -->
<div class="layout-overlay layout-menu-toggle"></div>
<!-- Drag Target Area To SlideIn Menu On Small Screens -->
<div class="drag-target"></div>
</div>
<!-- / Layout wrapper -->
<!-- Core JS -->
<!-- build:js assets/vendor/js/core.js -->
<script src="<?= site_url('themes/vuexy/vendor/libs/jquery/jquery.js') ?>"></script>
<script src="<?= site_url('themes/vuexy/vendor/libs/popper/popper.js') ?>"></script>
<script src="<?= site_url('themes/vuexy/vendor/js/bootstrap.js') ?>"></script>
<script src="<?= site_url('themes/vuexy/vendor/libs/perfect-scrollbar/perfect-scrollbar.js') ?>"></script>
<script src="<?= site_url('themes/vuexy/vendor/libs/node-waves/node-waves.js') ?>"></script>
<script src="<?= site_url('themes/vuexy/vendor/libs/hammer/hammer.js') ?>"></script>
<script src="<?= site_url('themes/vuexy/vendor/js/menu.js') ?>"></script>
<!-- endbuild -->
<!-- Vendors JS -->
<script src="<?= site_url('themes/vuexy/vendor/libs/select2/select2.js') ?>"></script>
<!-- Main JS -->
<script src="<?= site_url('themes/vuexy/js/main.js') ?>"></script>
<!-- Page JS -->
</body>
</html>

View File

@ -1,359 +0,0 @@
<?php
$session = session();
$token = $session->get('token') ?? '';
$tfa = $session->get('tfa') ?? false;
$settings = $session->get('settings');
$picture = "/assets/img/default-user.png";
$pulse = session()->get('pulse');
$notification = session()->get('notification');
if (!empty($token) && $tfa == false) {
//echo "<script>window.location.href = '/'; </script>";
}
?>
<!DOCTYPE html>
<html
lang="<?= $session->get('lang') ?>"
class="h-100 light-style layout-navbar-fixed layout-menu-fixed"
dir="ltr"
data-theme="theme-default"
data-assets-path="<?= site_url('themes/vuexy/') ?>"
data-template="vertical-menu-template-no-customizer"
>
<head>
<meta charset="utf-8">
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"
/>
<title><?= config('Safekat')->appName ?></title>
<meta name="description" content=""/>
<!-- Favicon -->
<link rel="icon" type="image/x-icon" href="<?= site_url('themes/vuexy/img/favicon/favicon.ico') ?>"/>
<link rel="apple-touch-icon" sizes="57x57" href="<?= site_url('themes/vuexy/img/favicon/apple-icon-57x57.png') ?>">
<link rel="apple-touch-icon" sizes="60x60" href="<?= site_url('themes/vuexy/img/favicon/apple-icon-60x60.png') ?>">
<link rel="apple-touch-icon" sizes="72x72" href="<?= site_url('themes/vuexy/img/favicon/apple-icon-72x72.png') ?>">
<link rel="apple-touch-icon" sizes="76x76" href="<?= site_url('themes/vuexy/img/favicon/apple-icon-76x76.png') ?>">
<link rel="apple-touch-icon" sizes="114x114"
href="<?= site_url('themes/vuexy/img/favicon/apple-icon-114x114.png') ?>">
<link rel="apple-touch-icon" sizes="120x120"
href="<?= site_url('themes/vuexy/img/favicon/apple-icon-120x120.png') ?>">
<link rel="apple-touch-icon" sizes="144x144"
href="<?= site_url('themes/vuexy/img/favicon/apple-icon-144x144.png') ?>">
<link rel="apple-touch-icon" sizes="152x152"
href="<?= site_url('themes/vuexy/img/favicon/apple-icon-152x152.png') ?>">
<link rel="apple-touch-icon" sizes="180x180"
href="<?= site_url('themes/vuexy/img/favicon/apple-icon-180x180.png') ?>">
<link rel="icon" type="image/png" sizes="192x192"
href="<?= site_url('themes/vuexy/img/favicon/android-icon-192x192.png') ?>">
<link rel="icon" type="image/png" sizes="32x32"
href="<?= site_url('themes/vuexy/img/favicon/favicon-32x32.png') ?>">
<link rel="icon" type="image/png" sizes="96x96"
href="<?= site_url('themes/vuexy/img/favicon/favicon-96x96.png') ?>">
<link rel="icon" type="image/png" sizes="16x16"
href="<?= site_url('themes/vuexy/img/favicon/favicon-16x16.png') ?>">
<link rel="manifest" href="<?= site_url('themes/vuexy/img/favicon/manifest.json') ?>">
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com"/>
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin/>
<link
href="https://fonts.googleapis.com/css2?family=Public+Sans:ital,wght@0,300;0,400;0,500;0,600;0,700;1,300;1,400;1,500;1,600;1,700&display=swap"
rel="stylesheet"
/>
<!-- Icons -->
<link rel="stylesheet" href="<?= site_url('themes/vuexy/vendor/fonts/fontawesome.css') ?>"/>
<link rel="stylesheet" href="<?= site_url('themes/vuexy/vendor/fonts/tabler-icons.css') ?>"/>
<link rel="stylesheet" href="<?= site_url('themes/vuexy/vendor/fonts/flag-icons.css') ?>"/>
<!-- Core CSS -->
<link rel="stylesheet" href="<?= site_url('themes/vuexy/vendor/css/rtl/core.css') ?>"/>
<link rel="stylesheet" href="<?= site_url('themes/vuexy/vendor/css/rtl/theme-semi-dark.css') ?>"/>
<link rel="stylesheet" href="<?= site_url('themes/vuexy/css/safekat.css') ?>"/>
<!-- Vendors CSS -->
<link rel="stylesheet" href="<?= site_url('themes/vuexy/vendor/libs/perfect-scrollbar/perfect-scrollbar.css') ?>"/>
<!-- Page CSS -->
<?= $this->renderSection('css') ?>
<!-- Helpers -->
<script src="<?= site_url('themes/vuexy/vendor/js/helpers.js') ?>"></script>
<script src="<?= site_url('themes/vuexy/js/config.js') ?>"></script>
</head>
<body>
<!-- Layout wrapper -->
<div class="layout-wrapper layout-content-navbar">
<div class="layout-container">
<?php include "selector_menu.php" ?>
<!-- Layout container -->
<div class="layout-page">
<!-- Navbar -->
<nav
class="layout-navbar container-xxl navbar navbar-expand-xl navbar-detached align-items-center bg-navbar-theme"
id="layout-navbar"
>
<div class="layout-menu-toggle navbar-nav align-items-xl-center me-3 me-xl-0 d-xl-none">
<a class="nav-item nav-link px-0 me-xl-4" href="javascript:void(0)">
<i class="ti ti-menu-2 ti-sm"></i>
</a>
</div>
<div class="navbar-nav-right d-flex align-items-center" id="navbar-collapse">
<div class="navbar-nav align-items-center">
<a class="nav-link style-switcher-toggle hide-arrow" href="javascript:void(0);">
<i class="ti ti-sm"></i>
</a>
</div>
<ul class="navbar-nav flex-row align-items-center ms-auto">
<!-- Notification -->
<li class="nav-item dropdown-notifications navbar-dropdown dropdown me-3 me-xl-1">
<a
class="nav-link dropdown-toggle hide-arrow"
href="javascript:void(0);"
data-bs-toggle="dropdown"
data-bs-auto-close="outside"
aria-expanded="false"
>
<i class="ti ti-bell ti-md"></i>
<span class="badge bg-danger rounded-pill badge-notifications">5</span>
</a>
</li>
<!--/ Notification -->
<!-- Search Budgets -->
<li class="nav-item navbar-dropdown dropdown me-3 me-xl-1">
<a
class="nav-link hide-arrow"
href="<?= site_url('presupuestos/buscador'); ?>"
title="Acceso directo a buscador de presupuestos"
>
<i class="ti ti-report-search ti-md"></i>
</a>
</li>
<!--/ Search Budgets -->
<!-- View Mode links -->
<li class="nav-item dropdown-shortcuts navbar-dropdown dropdown me-2 me-xl-0">
<a
class="nav-link dropdown-toggle hide-arrow"
href="javascript:void(0);"
data-bs-toggle="dropdown"
data-bs-auto-close="outside"
aria-expanded="false"
>
<i class="ti ti-building ti-md"></i>
</a>
<div class="dropdown-menu dropdown-menu-end py-0">
<div class="dropdown-menu-header border-bottom">
<div class="dropdown-header d-flex align-items-center py-3">
<h5 class="text-body mb-0 me-auto">Vistas</h5>
</div>
</div>
<div class="dropdown-shortcuts-list scrollable-container">
<div class="row row-bordered overflow-visible g-0">
<div class="dropdown-shortcuts-item col">
<span class="dropdown-shortcuts-icon rounded-circle mb-2">
<i class="ti ti-printer fs-4"></i>
</span>
<small class="text-muted mb-0">Vista</small>
<a href="<?= site_url('viewmode/' . config("Basics")->vista_impresion); ?>"
class="stretched-link">Impresión</a>
</div>
<div class="dropdown-shortcuts-item col">
<span class="dropdown-shortcuts-icon rounded-circle mb-2">
<i class="ti ti-ruler-2 fs-4"></i>
</span>
<small class="text-muted mb-0">Vista</small>
<a href="<?= site_url('viewmode/' . config("Basics")->vista_maquetacion); ?>"
class="stretched-link">Maquetación</a>
</div>
</div>
<div class="row row-bordered overflow-visible g-0">
<div class="dropdown-shortcuts-item col">
<span class="dropdown-shortcuts-icon rounded-circle mb-2">
<i class="ti ti-file-code-2 fs-4"></i>
</span>
<small class="text-muted mb-0">Vista</small>
<a href="<?= site_url('viewmode/' . config("Basics")->vista_digitalizacion); ?>"
class="stretched-link">Digitalización</a>
</div>
</div>
</div>
</div>
</li>
<!-- View Mode links -->
<!-- Language -->
<li class="nav-item dropdown-language dropdown me-2 me-xl-0">
<a class="nav-link dropdown-toggle hide-arrow" href="javascript:void(0);"
data-bs-toggle="dropdown">
<i class="fi <?= getCurrentLanguageFlag(); ?> fis rounded-circle me-1 fs-3"></i>
</a>
<ul class="dropdown-menu dropdown-menu-end">
<li>
<a class="dropdown-item" href="<?= site_url('lang/es'); ?>" data-language="es">
<i class="fi fi-es fis rounded-circle me-1 fs-3"></i>
<span class="align-middle"><?= lang("App.lang_es") ?></span>
</a>
</li>
<li>
<a class="dropdown-item" href="<?= site_url('lang/en'); ?>" data-language="en">
<i class="fi fi-gb fis rounded-circle me-1 fs-3"></i>
<span class="align-middle"><?= lang("App.lang_en") ?></span>
</a>
</li>
</ul>
</li>
<!--/ Language -->
<!-- User -->
<li class="nav-item navbar-dropdown dropdown-user dropdown">
<a class="nav-link dropdown-toggle hide-arrow" href="javascript:void(0);"
data-bs-toggle="dropdown">
<div class="avatar">
<img src="<?= $picture ?? '' ?>" alt class="h-auto rounded-circle"/>
</div>
</a>
<ul class="dropdown-menu dropdown-menu-end">
<li>
<a class="dropdown-item" href="#">
<div class="d-flex">
<div class="flex-shrink-0 me-3">
<div class="avatar avatar">
<img src="<?= $picture ?? '' ?>" alt class="h-auto rounded-circle"/>
</div>
</div>
<div class="flex-grow-1">
<span class="fw-semibold d-block"><?= $session->get('first_name') . ' ' . $session->get('last_name') ?></span>
<small class="text-muted">Admin</small>
</div>
</div>
</a>
</li>
<li>
<div class="dropdown-divider"></div>
</li>
<li>
<a class="dropdown-item" href="<?= site_url('profile'); ?>">
<i class="ti ti-user-check me-2 ti-sm"></i>
<span class="align-middle"><?= lang("App.menu_profile") ?></span>
</a>
</li>
<!-- <li>-->
<!-- <a class="dropdown-item" href="#">-->
<!-- <i class="ti ti-settings me-2 ti-sm"></i>-->
<!-- <span class="align-middle">Settings</span>-->
<!-- </a>-->
<!-- </li>-->
<li>
<div class="dropdown-divider"></div>
</li>
<li>
<a class="dropdown-item" href="<?= site_url("logout") ?>">
<i class="ti ti-logout me-2 ti-sm"></i>
<span class="align-middle"><?= lang("App.menu_logout") ?></span>
</a>
</li>
</ul>
</li>
<!--/ User -->
</ul>
</div>
</nav>
<!-- / Navbar -->
<!-- Content wrapper -->
<div class="content-wrapper">
<!-- Content -->
<div class="container-xxl flex-grow-1 container-p-y">
<h5 class="py-3 mb-4">
<?php include "breadcrumbs.php" ?>
</h5>
<?= $this->renderSection('content') ?>
</div>
<!-- / Content -->
<!-- Footer -->
<footer class="content-footer footer bg-footer-theme">
<div class="container-xxl">
<div class="footer-container d-flex align-items-center justify-content-between py-2 flex-md-row flex-column">
<div>
<a href="#" target="_blank" class="fw-semibold">Safekat</a> © <?= date('Y'); ?>
</div>
</div>
</div>
</footer>
<!-- / Footer -->
<div class="content-backdrop fade"></div>
</div>
<!-- Content wrapper -->
</div>
<!-- / Layout page -->
</div>
<!-- Overlay -->
<div class="layout-overlay layout-menu-toggle"></div>
<!-- Drag Target Area To SlideIn Menu On Small Screens -->
<div class="drag-target"></div>
</div>
<!-- / Layout wrapper -->
<?= $this->renderSection('footerAdditions') ?>
<!-- Core JS -->
<!-- build:js assets/vendor/js/core.js -->
<script src="<?= site_url('themes/vuexy/vendor/libs/jquery/jquery.js') ?>"></script>
<script src="<?= site_url('themes/vuexy/vendor/libs/popper/popper.js') ?>"></script>
<script src="<?= site_url('themes/vuexy/vendor/js/bootstrap.js') ?>"></script>
<script src="<?= site_url('themes/vuexy/vendor/libs/perfect-scrollbar/perfect-scrollbar.js') ?>"></script>
<script src="<?= site_url('themes/vuexy/vendor/libs/hammer/hammer.js') ?>"></script>
<script src="<?= site_url('themes/vuexy/vendor/js/menu.js') ?>"></script>
<!-- endbuild -->
<!-- Vendors JS -->
<?= $this->renderSection('additionalExternalJs') ?>
<!-- Main JS -->
<script src="<?= site_url('themes/vuexy/js/main.js') ?>"></script>
<!-- Page JS -->
<?= sweetAlert() ?>
<script type="text/javascript">
<?= $this->renderSection('additionalInlineJs') ?>
</script>
</body>
</html>

View File

@ -4,8 +4,8 @@
*/ */
if ( if (
auth()->user()->can('paises.menu') || auth()->user()->can('paises.menu') ||
auth()->user()->can('papeles-genericos.menu') || auth()->user()->can('papel-genericosk .menu') ||
auth()->user()->can('papeles-impresion.menu') || auth()->user()->can('papel-impresion.menu') ||
auth()->user()->can('maquinas.menu') || auth()->user()->can('maquinas.menu') ||
auth()->user()->can('maquinas-defecto.menu') || auth()->user()->can('maquinas-defecto.menu') ||
auth()->user()->can('usuarios.menu') || auth()->user()->can('usuarios.menu') ||
@ -25,14 +25,14 @@ if (
</a> </a>
</li> </li>
<?php } ?> <?php } ?>
<?php if (auth()->user()->can('papeles-genericos.menu')) { ?> <?php if (auth()->user()->can('papel-generico.menu')) { ?>
<li class="menu-item"> <li class="menu-item">
<a href="<?= site_url("configuracion/papelesgenericos") ?>" class="menu-link"> <a href="<?= site_url("configuracion/papelesgenericos") ?>" class="menu-link">
<?= lang("App.menu_papelgenerico") ?> <?= lang("App.menu_papelgenerico") ?>
</a> </a>
</li> </li>
<?php } ?> <?php } ?>
<?php if (auth()->user()->can('papeles-impresion.menu')) { ?> <?php if (auth()->user()->can('papel-impresion.menu')) { ?>
<li class="menu-item"> <li class="menu-item">
<a href="<?= site_url("configuracion/papelesimpresion") ?>" class="menu-link"> <a href="<?= site_url("configuracion/papelesimpresion") ?>" class="menu-link">
<?= lang("App.menu_papelimpresion") ?> <?= lang("App.menu_papelimpresion") ?>

View File

@ -12,7 +12,7 @@ if (auth()->user()->inGroup('beta')) {
</a> </a>
<ul class="menu-sub"> <ul class="menu-sub">
<li class="menu-item"> <li class="menu-item">
<a href="<?= route_to('facturasList') ?>" class="menu-link"> <a href="<?= route_to('newFactura') ?>" class="menu-link">
<?= lang("App.menu_facturas_nueva") ?> <?= lang("App.menu_facturas_nueva") ?>
</a> </a>
</li> </li>

View File

@ -247,8 +247,8 @@ if (!empty($token) && $tfa == false) {
</div> </div>
</div> </div>
<div class="flex-grow-1"> <div class="flex-grow-1">
<span class="fw-semibold d-block"><?= $session->get('first_name') . ' ' . $session->get('last_name') ?></span> <span class="fw-semibold d-block"><?= auth()->user()->getFullName(); ?></span>
<small class="text-muted">Admin</small> <small class="text-muted"><?= auth()->user()->getEmail(); ?></small>
</div> </div>
</div> </div>
</a> </a>

30
ci4/packages.txt Normal file
View File

@ -0,0 +1,30 @@
ii php-cli 2:8.1+92ubuntu1 all command-line interpreter for the PHP scripting language (default)
ii php-common 2:92ubuntu1 all Common files for PHP packages
ii php-composer-ca-bundle 1.3.1-1 all utility library to find a path to the system CA bundle
ii php-composer-metadata-minifier 1.0.0-2 all Small utility library that handles metadata minification and expansion
ii php-composer-pcre 1.0.1-1 all PCRE wrapping library that offers type-safe preg_* replacements
ii php-composer-semver 3.2.9-1 all utilities, version constraint parsing and validation
ii php-composer-spdx-licenses 1.5.6-1 all SPDX licenses list and validation library
ii php-composer-xdebug-handler 2.0.4-1build1 all Restarts a process without Xdebug
ii php-curl 2:8.1+92ubuntu1 all CURL module for PHP [default]
ii php-intl 2:8.1+92ubuntu1 all Internationalisation module for PHP [default]
ii php-json-schema 5.2.11-1 all implementation of JSON schema
ii php-mbstring 2:8.1+92ubuntu1 all MBSTRING module for PHP [default]
ii php-psr-container 2.0.2-1 all Common Container Interface (PHP FIG PSR-11)
ii php-psr-log 3.0.0-1 all common interface for logging libraries
ii php-react-promise 2.7.0-2 all lightweight implementation of CommonJS Promises/A for PHP
ii php-symfony-console 5.4.4+dfsg-1ubuntu8 all run tasks from the command line
ii php-symfony-deprecation-contracts 2.4.0-1ubuntu2 all A generic function and convention to trigger deprecation notices
ii php-symfony-filesystem 5.4.4+dfsg-1ubuntu8 all basic filesystem utilities
ii php-symfony-finder 5.4.4+dfsg-1ubuntu8 all find files and directories
ii php-symfony-polyfill-php80 1.24.0-1ubuntu2 all Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions
ii php-symfony-process 5.4.4+dfsg-1ubuntu8 all execute commands in sub-processes
ii php-symfony-service-contracts 2.4.0-1ubuntu2 all Generic abstractions related to writing services
ii php-symfony-string 5.4.4+dfsg-1ubuntu8 all object-oriented API to work with strings
ii php8.1-cli 8.1.2-1ubuntu2.18 amd64 command-line interpreter for the PHP scripting language
ii php8.1-common 8.1.2-1ubuntu2.18 amd64 documentation, examples and common module for PHP
ii php8.1-curl 8.1.2-1ubuntu2.18 amd64 CURL module for PHP
ii php8.1-intl 8.1.2-1ubuntu2.18 amd64 Internationalisation module for PHP
ii php8.1-mbstring 8.1.2-1ubuntu2.18 amd64 MBSTRING module for PHP
ii php8.1-opcache 8.1.2-1ubuntu2.18 amd64 Zend OpCache module for PHP
ii php8.1-readline 8.1.2-1ubuntu2.18 amd64 readline module for PHP

View File

@ -1,20 +0,0 @@
@echo off
REM Solicitar al usuario el nombre de la nueva rama
set /p nombre_rama=Nuevo nombre de la rama:
echo %nombre_rama%
REM Verificar si se proporciona un nombre de rama
if not "%nombre_rama%"=="" (
REM Cambiar y actualizar la rama main
git checkout main
git pull
REM Crear nueva rama
git checkout -b %nombre_rama%
REM Hacer push de la nueva rama al repositorio remoto
git push -u origin %nombre_rama%
echo Se ha creado (a partir de la rama main) y cambiado a la nueva rama: %nombre_rama%
) else (
echo No se proporcionó un nombre de rama. La creación de la rama ha sido omitida.
)